I am currently looking a this piece of code from a module called ZfcUser for Zend 2:
namespace ZfcUser\Controller;
use Zend\Form\Form;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Stdlib\ResponseInterface as Response;
use Zend\Stdlib\Parameters;
use Zend\View\Model\ViewModel;
use ZfcUser\Service\User as UserService;
use ZfcUser\Options\UserControllerOptionsInterface;
class UserController extends AbstractActionController
{
/**
* #var UserService
*/
protected $userService;
.
.
public function indexAction()
{
if (!$this->zfcUserAuthentication()->hasIdentity()) {
return $this->redirect()->toRoute('zfcuser/login');
}
return new ViewModel();
}
.
.
}
In the namespace ZfcUser\Controller\Plugin:
namespace ZfcUser\Controller\Plugin;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
use Zend\Authentication\AuthenticationService;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\ServiceManager\ServiceManager;
use ZfcUser\Authentication\Adapter\AdapterChain as AuthAdapter;
class ZfcUserAuthentication extends AbstractPlugin implements ServiceManagerAwareInterface
{
/**
* #var AuthAdapter
*/
protected $authAdapter;
.
.
/**
* Proxy convenience method
*
* #return mixed
*/
public function hasIdentity()
{
return $this->getAuthService()->hasIdentity();
}
/**
* Get authService.
*
* #return AuthenticationService
*/
public function getAuthService()
{
if (null === $this->authService) {
$this->authService = $this->getServiceManager()->get('zfcuser_auth_service');
}
return $this->authService;
}
My Questions:
From indexAction(), the controller plugin is called without being instantiated ($this->zfcUserAuthentication()->hasIdentity()), do controller plugins always work like this?.
What really happens in the hasIdentity()? I see getAuthService() returning something but not hasIdentity().I am not familiar with this type of advanced class implementation of function calling so I would truly appreciate any explanation here or topic I should look into.
I can't answer your first question, but regarding your second question:
The getAuthService() method in your code returns an AuthenticationService object, which has a hasIdentity() method.
So there are two different hasIdentity() methods:
In the AuthenticationService class (source code here).
In the ZfcUserAuthentication class which you're looking at.
This line of code in the ZfcUserAuthentication class:
return $this->getAuthService()->hasIdentity();
does three things:
$this->getAuthService() returns an AuthenticationService object.
The hasIdentity() method of that AuthenticationService object is then called, and it returns a boolean.
That boolean is then returned.
Imagine splitting the code into two parts:
// Get AuthenticationService object Call a method of that object
$this->getAuthService() ->hasIdentity();
Hope that helps!
All sorts of plugins in Zend Framework are managed by plugin managers, which are subclasses of AbstractPluginManager which is subclasss of ServiceManager.
$this->zfcUserAuthentication() proxies by AbstractController to pluginmanager internally.
AuthenticationService::hasIdentity() checks if something was added to storage during successful authentication attempt in this or previous request:
See here
Related
I cannot find the problem using
$routes->resource
Please help me figure out what is the problem.
This is how I put my routes resource in config routes :
$routes->resource('ApiManageBanner', ['controller' =>'App\Controllers\ApiData\ApiManageBanner']); // get, put, create, delete
Recently I just move all my project to the newest codeigniter 4 version 4.2.6 from the previous version 4.1.2
This is my controllers :
<?php
namespace App\Controllers\ApiData;
use App\Controllers\BaseController;
use CodeIgniter\RESTful\ResourceController;
use Codeigniter\API\ResponseTrait;
class ApiManageBanner extends ResourceController
{
use ResponseTrait;
function __construct()
{
}
// equal to get
public function index() {
echo "Test";
}
// equal to post
public function create() {
}
// equal to get
public function show($id = null) {
}
// equal to put
public function update($id = null) {
}
// equal to delete
public function delete($id = null) {
}
}
I just try a simple to echo "Test".
But I got this error :
I search everywhere but cannot find the problem related to the error.
If I change the routes name to 'ApiManageBanners' using 's' :
$routes->resource('ApiManageBanners', ['controller' =>'App\Controllers\ApiData\ApiManageBanner']); // get, put, create, delete
It is working.
But I cannot change my routes name because my application is reading
'ApiManageBanner' not 'ApiManageBanners'
I am very curious what cause the problem. It is not working for almost all my resources api controller routes.
I found the problem. According to the error it is related to session. When I check all my file. I found that I always init the :
$this->Session = \Config\Services::session();
In all my controller and model __construct();
function __construct()
{
$this->Session = \Config\Services::session();
}
So I remove it and init globaly in BaseController.php
<?php
namespace App\Controllers;
use CodeIgniter\Controller;
use CodeIgniter\HTTP\CLIRequest;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Psr\Log\LoggerInterface;
/**
* Class BaseController
*
* BaseController provides a convenient place for loading components
* and performing functions that are needed by all your controllers.
* Extend this class in any new controllers:
* class Home extends BaseController
*
* For security be sure to declare any new methods as protected or private.
*/
abstract class BaseController extends Controller
{
/**
* Instance of the main Request object.
*
* #var CLIRequest|IncomingRequest
*/
protected $request;
/**
* An array of helpers to be loaded automatically upon
* class instantiation. These helpers will be available
* to all other controllers that extend BaseController.
*
* #var array
*/
protected $helpers = [''];
/**
* Constructor.
*/
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
{
// Do Not Edit This Line
parent::initController($request, $response, $logger);
// Preload any models, libraries, etc, here.
// E.g.: $this->session = \Config\Services::session();
$this->session = \Config\Services::session();
$this->language = \Config\Services::language();
$this->language->setLocale($this->session->lang);
}
}
Then the error is gone.
I'm a new in a php and dusk, but I try to work with page object in dusk, and I'm stuck because when I try to add page object to test, phpstorm said me that "Method logInUserName not found in $this". Can someone explain to me where i'm wrong?
I have page class:
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
class LogInPage extends Page
{
/**
* Get the URL for the page.
*
* #return string
*/
public function url()
{
return '/login';
}
/**
*
* #return void
*/
public function logInUserName(Browser $browser)
{
$browser->type("#username", "lol");
}
}
I have test class
use Tests\Browser\Pages\LogInPage;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use PHPUnit\Framework\Assert;
class ExampleTest extends DuskTestCase
{
/**
* A basic browser test example.
*
* #return void
*/
public function testLogInFail()
{
$this->browse(function (Browser $browser) {
$browser
->visit(new LogInPage)
->logInUserName()
->keys("#password","lol")
->click("button.btn-primary"));}
Agree this is annoying, there are 2 ways you could get around this
Restart the chaining on the browser object, you may still get a warning about logInUserName but you get your code assist back, which I agree can be useful when still learning.
$browser
->visit(new LogInPage)
->logInUserName();
$browser
->keys("#password","lol")
->click("button.btn-primary"));
Create a helper file defining your custom functions
Or use this gist and create a file in the root of your project that your IDE will read - https://gist.github.com/slava-vishnyakov/5eb90352fc97702f53a41888e5bae27a
Only issue is you may get a PHPSTORM warning about multiple definitions exist for class Browser...not sure how to get around that
Results in something like this
<?php
namespace Laravel\Dusk {
class Browser
{
/**
* #return Browser
*/
public function logInUserName()
{
}
}
}
I wrote a Command Controller that handles data import from an URL.
pseudo-syntax is like this:
class ImportCommandController extends \TYPO3\CMS\Extbase\Mvc\Controller\CommandController
{
public function importCommand($auth){
$data = file_get_content();
}
}
this works.
But when I try to call that command from the Action Controller of my backend Module I get errors.
Heres the code:
ActionController:
class ImportController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{
/**
* #var \Vendor\MyExt\Command\ImportCommandController importCommandCtrl
* #inject
*/
protected $importCommandCtrl;
public function importAction()//($url,$usr,$pass)
{
//$this->importCommandCtrl = GeneralUtility::makeInstance('Vendor\MyExt\Command\ImportCommandController');
$this->importCommandCtrl->testCommand();
}
}
When I call importAction() like this, I get:
"Call to a member function testCommand() on null"
When I uncomment the makeInstance, I get:
"Call to a member function get() on null"
Sadly, this topic is documente rather poorly in the TYPO3 Docs.
Can someone help me on this or point me to the right direction?
I'd like to slightly alter the answer already given by René and add some code examples. I also recommend to put your import logic into a dedicated class, e.g. ImportService:
namespace Vendor\MyExt\Service;
use TYPO3\CMS\Core\SingletonInterface;
class ImportService implements SingletonInterface
{
public function importData()
{
// import logic goes here
}
}
You can now inject this class as a dependency of your CommandController and your ActionController:
class ImportController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{
/**
* #var \Vendor\MyExt\Service\ImportService
* #inject
*/
protected $importService;
public function importAction()
{
$this->importService->importData();
}
}
class ImportCommandController extends \TYPO3\CMS\Extbase\Mvc\Controller\CommandControlle
{
/**
* #var \Vendor\MyExt\Service\ImportService
* #inject
*/
protected $importService;
public function importCommand()
{
$this->importService->importData();
}
}
The use of an CommandController in an ActionController is not recommended because they have different envoiroment variables.
If you want to use some code on more position it's recommanded to use Utility classes.
So create an Class in the my_ext/Classes/Utility/ directory call the class something like ImportUtility and try to code your import independed from some controller.
I'd like to retrieve my module configuration from a controller in Zend Framework 3.
I searched, and it seems that the standard way to do this in ZF2 is to use
$this->getServiceLocator()
to access the configuration in module.config.php.
However, this won't work in ZF3, as there is no getServiceLocator() method.
What is the standard way to achieve this?
Don't know if you found an answer, as there are different solutions as tasmaniski wrote. Just in case, let me share one that would have helped me a lot when I started to play with ZF3:
MyControllerFactory.php
<?php
namespace My\Namespace;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
use DependencyNamespace\...\ControllerDependencyClass; // this is not a real one of course!
class MyControllerFactory implements FactoryInterface
{
/**
* #param ContainerInterface $container
* #param string $requestedName
* #param null|array $options
* #return AuthAdapter
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
// Get config.
$config = $container->get('configuration');
// Get what I'm interested in config.
$myStuff = $config['the-array-i-am-interested-in']
// Do something with it.
$controllerDepency = dummyFunction($myStuff);
/*...the rest of your code here... */
// Inject dependency.
return $controllerDepency;
}
}
MyController.php
<?php
namespace My\Namespace;
use Zend\Mvc\Controller\AbstractActionController;
use DependencyNamespace\...\DependencyClass;
class MyController extends AbstractActionController
{
private $controllerDepency;
public function __construct(DependencyClass $controllerDepency)
{
$this->controllerDepency = $controllerDepency;
}
/*...the rest of your class here... */
}
You need to inject your dependencies through service manager.
Basicly you need to create 2 class Controller and ControllerFactory that will create Controller with all dependencies.
I have been doing a read up on ZF2 Service Locator component and could say I understand how its being used. I have, however, a question which I think its silly but it wouldn't hurt to ask.
I want to have a namespace inside my Module called Component where I can put generic code in like say FunctionsComponent.php, MailerComponent.php or ExcelComponent.php. This would allow me to do some stuff inside my controllers.
What I would like to tryout is to have an ability to have controllers define the components they are interested to use (see below):
class SalesController extends AbstractController
{
protected $components = ['Excel'];
//In some action
public function exportAction()
{
$data = ['data to be exported'];
/**
$data : data to be exported
boolean : Whether to force download or save the file in a dedicated location
*/
$this->Excel->export($data, true);
}
}
The idea is to create a ComponentCollection that perhaps implements the FactoryInterface or ServiceLocatorInterface and then let it check each controller when the MvcEvent has been triggered inside my Module class and have the ComponentCollection inject all the controller component and make them accessible without using the service locator as shown below:
$excel = $sm->get('Application\Component\Excel');
I am well aware that this may seem like a daunting ask but I feel like the best way to learn a framework among other things is to play around with it and try to do the unimaginable.
You should create a BaseController somewhere and then extend all your Controllers from BaseController. Then you can inject your dependencies in your BaseController and use anywhere in kids. For example, I am doing this in my Controller to set head title:
<?php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
class BaseController extends AbstractActionController
{
/**
* Sets the head title for every page
*
* #param string $title
*/
public function setHeadTitle($title)
{
$viewHelperManager = $this->getServiceLocator()->get('ViewHelperManager');
// Getting the headTitle helper from the view helper manager
$headTitleHelper = $viewHelperManager->get('headTitle');
// Setting a separator string for segments
$headTitleHelper->setSeparator(' - ');
// Setting the action, controller, module and site name as title segments
$siteName = 'Ribbon Cutters';
$translator = $this->getServiceLocator()->get('translator');
$title = $translator->translate($title);
$headTitleHelper->append(ucfirst($title));
$headTitleHelper->append($siteName);
}
}
Instead of defining methods, you can define properties.
public $headTitleHelper
and assign it in constructor of BaseController
$this->headTitleHelper = $this->getServiceLocator()->get('ViewHelperManager')->get('headTitle');
Now you can use $this->headTitleHelper in child controllers.
And then
<?php
namespace Application\Controller;
use Zend\View\Model\ViewModel;
use Application\Controller\BaseController;
class IndexController extends BaseController
{
/**
* Property for setting entity manager of doctrine
*/
protected $em;
/**
* landing page
*
* #return ViewModel
*/
public function indexAction()
{
$this->setHeadTitle('Welcome'); // Welcome - Ribbon Cutters
$viewModel = new ViewModel();
return $viewModel;
}
/**
* Sets and gives Doctrine Entity Manager
*
* #return Doctrine Entity Manager
*/
protected function getEntityManager()
{
if (null === $this->em) {
$this->em = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default');
}
return $this->em;
}
}
I think this can help you.