get controller name & action in view file in zend framework 2 - php

I want to get controller and action name in respective view file
as when I GOTO login page
Controller=> authenticate
And action=> Login
come in action
I want to get those name directly in view with out passing it from each and every controller, because on every view file I want controller and action name.

To do this the proper ZF2 way you should write a custom view helper.
You can call this view helper for example RouteMatchHelper.
Then in the view you can simply do $this->routeMatchHelper();
<?php
namespace Application\View\Helper;
use Zend\Mvc\Router\RouteMatch;
use Zend\View\Helper\AbstractHelper;
class RouteMatchHelper extends AbstractHelper
{
/**
* #var RouteMatch
*/
protected $routeMatch;
/**
* Constructor with dependency
*
* #param RouteMatch $routeMatch
*/
public function __construct(RouteMatch $routeMatch)
{
$this->routeMatch = $routeMatch;
}
public function __invoke()
{
$controller = $this->routeMatch->getParam('controller');
$action = $this->routeMatch->getParam('action');
return sprintf(
"the action is %s and the controller name is %s",
$action,
$controller
);
}
}
You need RouteMatch in your view helper so you have to setup a factory. You will have to register the factory under the view_helpers key in your module.config.php file:
'view_helpers' => array(
'factories' => array(
'routeMatchHelper' => `Application\View\Helper\RouteMatchHelperFactory`
)
)
And then the factory itself:
<?php
namespace Application\View\Helper;
use Zend\Mvc\Router\RouteMatch;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class RouteMatchHelperFactory implements FactoryInterface
{
/**
* #param ServiceLocatorInterface $serviceLocator
* #return RouteMatchHelper
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$serviceManager = $serviceLocator->getServiceLocator();
/** #var RouteMatch $routeMatch */
$routeMatch = $serviceManager->get('Application')->getMvcEvent()->getRouteMatch();
return new RouteMatchHelper($routeMatch);
}
}
This code is not tested, but you get the point.
You can read more on writeing custom helperss in the official ZF2 documentation.

Related

Some Route Resource Not Working in Codeigniter 4

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.

Migration from ZF2 to ZF 3 without getServicelocator();

I am new at ZF3 and I need your help.
In ZF3 there is no service Locator any more. So I created a Factory class to replace the service Locator in my code.
Here is my code with service Locator in my AbstractController.php file:
protected function getService()
{
return $this->getServiceLocator()->get($service); //remove from ZF3
return $this->service = $service;
}
Now I replaced the service Locator in AbstractController.php:
protected function getService($service)
{
$service = $this->service;
return $this->service = $service;
}
And in Module.Config.php I added the following lines:
return [
'controllers' => [
'factories' => [
Controller\AbstactController::class => Controller\AbstactControllerFactory::class,
],
],
And I created a AbstractControllerFactory file with the following lines:
<?php
namespace Application\Controller;
use Application\Controller\AbstractController;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
class AbstractControllerFactory implements FactoryInterface
{
protected function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
return new AbstractController($container->get(service::class));
}
}
I need to know if this is a correct migration from ZF2 to ZF3?
In ZF3 the first thing you do is create your Service and a Factory for it. Let's take in this example UserManager.php in Services folder.
So we have in folder Service -> UserManager.php and in Service -> Factory -> UserManagerFactory.php
UserManagerFactory.php:
<?php
namespace User\Service\Factory;
use Interop\Container\ContainerInterface;
use User\Service\UserManager;
/**
* This is the factory class for UserManager service. The purpose of the factory
* is to instantiate the service and pass it dependencies (inject dependencies).
*/
class UserManagerFactory
{
/**
* This method creates the UserManager service and returns its instance.
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$entityManager = $container->get('doctrine.entitymanager.orm_default');
return new UserManager($entityManager);
}
}
UserManager.php:
<?php
namespace User\Service;
use User\Entity\User;
/**
* This service is responsible for adding/editing users
* and changing user password.
*/
class UserManager
{
/**
* Doctrine entity manager.
* #var Doctrine\ORM\EntityManager
*/
private $entityManager;
/**
* Constructs the service.
*/
public function __construct($entityManager)
{
$this->entityManager = $entityManager;
}
// REST OF YOUR CODE
}
Now that we have our service, we go into User\config\modules.config.php:
'service_manager' => [
'factories' => [
Service\UserManager::class => Service\Factory\UserManagerFactory::class,
],
],
Well that's basically it, we can inject the service in our controller and job done:
<?php
namespace User\Controller;
use Zend\Mvc\Controller\AbstractActionController;
/**
* This controller is responsible for user management (adding, editing,
* viewing users and changing user's password).
*/
class UserController extends AbstractActionController
{
/**
* User manager.
* #var User\Service\UserManager
*/
private $userManager;
/**
* Constructor.
*/
public function __construct($userManager)
{
$this->userManager = $userManager;
}
// REST OF YOUR CODE
}
I really hope this helps you understand how to use Service in ZF3.
Good Luck!

While attempting to create controlleralbumcontroller(alias: Controller\AlbumController) an invalid factory was registered for this instance type

I have created AlbumControllerFactory.php in folder \module\Album\src\Album\Factory as follows: But it is showing error a mentioned above
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Album\Controller\AlbumController;
class AlbumControllerFactory implements FactoryInterface
{
/**
*
* #param ContainerInterface $container
* #param string $requestedName
* #param null|array $options
* #return AlbumController
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$class = $requestedName ? $requestedName : AlbumController::class;
$albumTable = $container->get('Album\Model\AlbumTable'); // get service from service manager
$controller = new $class($albumTable);
return $controller;
}
/**
* Provided for backwards compatibility; proxies to __invoke().
*
* #param ContainerInterface|ServiceLocatorInterface $container
* #return AlbumController
*/
public function createService(ServiceLocatorInterface $container)
{
return $this($container, AlbumController::class);
}
}
And in my controller i have following code to get my factory:
namespace Album\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Album\Model\Album;
use Album\Form\AlbumForm;
class AlbumController extends AbstractActionController
{
protected $_albumTable;
public function __construct(AlbumTable $albumTable)
{
$this->_albumTable = $albumTable;
}
public function indexAction()
{
return new ViewModel(array(
'albums' => $this->getAlbumTable()->fetchAll(),
));
}
}
And in my module.config.php i have set the controller as like follows:
return array(
'controllers' => array(
'factories' => array(
Controller\AlbumController::class => Factory\Controller\AlbumControllerFactory::class,
),
),
So How i can fix this issue in-order to make my module work fine as it was working fine before creating the factory but it was showing a deprecated message. Please have a look at let me know what wrong i have done and how to fix this.
Here is a full example of how to use factories in Zend 2/3. I guess you are missing namespace in module.config.php file, but please compare your namespaces and directories with these.
You should have following directory structure:
module
- Album
- config
module.config.php
- src
- Controller
AlbumController.php
- Factory
- Controller
AlbumControllerFactory.php
- Module.php
Factory
namespace Album\Factory\Controller
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Album\Controller\AlbumController;
class AlbumControllerFactory implements FactoryInterface
{
/**
*
* #param ContainerInterface $container
* #param string $requestedName
* #param null|array $options
* #return AlbumController
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$class = $requestedName ? $requestedName : AlbumController::class;
$albumTable = $container->get('Album\Model\AlbumTable'); // get service from service manager
$controller = new $class($albumTable);
return $controller;
}
/**
* Provided for backwards compatibility; proxies to __invoke().
*
* #param ContainerInterface|ServiceLocatorInterface $container
* #return AlbumController
*/
public function createService(ServiceLocatorInterface $container)
{
return $this($container, AlbumController::class);
}
}
Controller
namespace Album\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Album\Model\Album;
use Album\Form\AlbumForm;
class AlbumController extends AbstractActionController
{
protected $_albumTable;
public function __construct(AlbumTable $albumTable)
{
$this->_albumTable = $albumTable;
}
public function indexAction()
{
return new ViewModel(array(
'albums' => $this->getAlbumTable()->fetchAll(),
));
}
}
module.config.php
namespace Album;
use Album\Controller;
use Album\Factory;
return array(
'controllers' => array(
'factories' => array(
Controller\AlbumController::class => Factory\Controller\AlbumControllerFactory::class,
),
),
I like to have segregated factories, but you can keep all your factories in main Factory directory, but be sure to set correct namespaces for them and in module.config.php file
Your problem is about Namespace :
You said :
I have created AlbumControllerFactory.php in folder
\module\Album\src\Album\Factory
BUT you call
Controller\AlbumController::class => Factory\Controller\AlbumControllerFactory::class,
Factory\Controller\AlbumControllerFactory is not a correct Full Qualified Class Name (FQCN)
You should have this in your config file
Suppose your namespace declared in the config file is Album :
Controller\AlbumController::class => Factory\AlbumControllerFactory::class

display username in layout.phtml in zend framework 2.5.1

I am new in zend and using zend framework 2.5.1.
Using "authservice" i have done login authentication in my project. I am able to fetch login detail by using $this->getAuthService()->getIdentity(); in my controller. But i want to use it in each and every view page (layout).
So that i could manage session but i am unable to do this.
Moreover i want to display logged in username in layout.phtml(or header.phtml).
I want to show logged in user name like "Welcome ABC".
So please help me to solve this problem.
See the Identity view helper for in your view files like: layout.phtml or page specific ones.
Just like the document states:
if ($user = $this->identity()) {
echo $this->translate('Welcome') . ' ' . $this->escapeHtml($user->getUsername());
} else {
echo $this->translate('Welcome guest');
}
I use a custom view helper to achieve this, passing the Auth service via factory.
My view helper
namespace Application\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Zend\Authentication\AuthenticationService;
class WelcomeUser extends AbstractHelper
{
private $welcomeUser;
/**
*
* #param AuthenticationService $auth
*/
public function __construct(AuthenticationService $auth)
{
$this->welcomeUser = 'Guest';
if ($auth->hasIdentity()) {
$user = $auth->getIdentity();
$this->welcomeUser = $user->getFirstLastName();
}
}
/**
*
* #return string
*/
public function __invoke()
{
return $this->welcomeUser;
}
}
And it's factory
namespace Application\View\Helper\Service;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Application\View\Helper\WelcomeUser;
use Zend\Authentication\AuthenticationService;
class WelcomeUserFactory implements FactoryInterface
{
/**
*
* #param ServiceLocatorInterface $serviceLocator
* #return WelcomeUser
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
return new WelcomeUser($serviceLocator->getServiceLocator()->get(AuthenticationService::class));
}
}
Don't forget to register you view helper in module.config.php
'view_helpers' => array(
'factories' => array(
'welcomeUser' => 'Application\View\Helper\Service\WelcomeUserFactory',
),
),
Finally in your layout.phtml use <?php echo $this->welcomeUser(); ?>
I hope this point you in the right direction.

Must I move data dependency out of my Controllers (and into Factories)?

This question can be viewed through a prism of ZF2 + Doctrine + MVC programming practices, or it can be viewed through just an OOP perspective.
My concern is about Separation of Concerns, and on removing dependencies.
I am using code in my controllers that goes something like this:
class MyController
{
private $em; //entityManager
function __construct()
{
$this->em = DoctrineConnector::getEntityManager();
}
function indexAction()
{
//Input
$inputParameter = filter_input(...);
//request for Data
$queryBuilder = $this->em->createQuery(...)
->setParameter('param', $inputParameter);
$query = $queryBuilder->getQuery();
//$services is the user-defined data type requested
$services = $query->getResult();
//use data to produce a view model
$view = new ViewModel();
$view->setVariables(array('services' => $services));
return $view;
}
}
I am not entirely comfortable with the above and wanted a second opinion. For one, my EntityManager is part of the class, so my class is cognizant of the entity manager construct, when I think it should not be a part of the controller. Do I perhaps use a Factory or Builder design pattern to help me create MyController class?
If I do, I can move my em (entityManager) construct into the Factory pattern and create and populate my MyController inside the Factory. Then, the MyController can have a private variable $services instead.
i.e.
class MyController
{
private $services;
function setServices($services)
{
$this->services = $services;
}
function indexAction()
{
//use data to produce a view model
$view = new ViewModel();
$view->setVariables(array('services' => $this->services));
return $view;
}
}
class MyFactoryMethod
{
function createMyController()
{
//Input
$inputParameter = filter_input(INPUT_GET...);
//request for Data
$queryBuilder = $this->em->createQuery(...)
->setParameter('param', $inputParameter);
$query = $queryBuilder->getQuery();
//$services is the user-defined data type requested
$services = $query->getResult();
//create and return MyController instance
$controller = new MyController();
$controller->setServices($services);
return $controller;
}
}
I typically tried to do this PHP's mysql extension to remove dependency on data out of my various objects. I am using Doctrine2 now which is an ORM, and wondering if I should keep doing the same thing (namely preferring 2nd example rather than the first...
Question:
I can write code both ways. It works essentially the same. My question is -- is the code, as it is written in my 2nd example preferred more than the code as it is written in my first?
Notes / Clarifications:
In my case variable $services is a domain-specific variable (not ZF2's ServiceLocator). i.e. think of MyController as a controller for business-specific "services".
I am not harnessing full power of ZF2 with configs, routers, events, and everything. I am using ZF2 modules on an existing legacy codebase on as-needed basis.
When your controller has hard dependencies I would suggest to use the common ZF2 solution by creating the controller and injecting the dependency in a factory instance and registering the controller under the 'factories' key in your 'controllers' config array.
In your module.config.php
'controllers' => array(
'factories' => array(
'Application\Controller\MyController' => 'Application\Controller\MyControllerFactory'
)
)
In your controller I would set hard dependency in the __construct method. Like this you prevent the controller from ever being instantiated without your dependencies (it will throw an exception).
Never inject something like $services (if this is a ServiceLocator) from which you will pull the actual dependencies since it is not clear what the class actually needs. It will be harder to understand for other developers and it is also hard to test since you cannot set mocks for your individual dependencies so easily.
Your Controller class:
<?php
namespace Application\Controller;
use Doctrine\ORM\EntityManager;
class MyController
{
/**
* #var EntityManager
*/
private $entityManager;
/**
* #param EntityManager $entityManager
*/
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
/**
*
*/
function indexAction()
{
//Do stuff
$entityManager = $this->getEntityManager();
}
/**
* #return EntityManager
*/
public function getEntityManager()
{
return $this->entityManager;
}
}
Your Factory:
<?php
namespace Application\Controller;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Doctrine\ORM\EntityManager;
class MyControllerFactory implements FactoryInterface
{
/**
* #param ServiceLocatorInterface $serviceLocator
* #return MyController
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
/** #var EntityManager $entityManager */
$serviceManager = $serviceLocator->getServiceLocator()
$entityManager = $serviceManager->get('doctrine.entitymanager.orm_default');
$myController = new MyController($entityManager);
return $myController;
}
}
There are two different approaches to this problem that are provided by ZF2.
Use the ServiceLocator to retrieve the EntityManager via a Factory.
In Module.php, add an anonymous function or Factory.
public function getServiceConfig()
{
return [
'factories' => [
'Doctrine\ORM\EntityManager' => function (ServiceManager $sm) {
$entityManager = $sm->get('doctrine.entitymanager.orm_default');
return $entityManager;
}
],
],
}
In your Controller
$em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
Create an Initializer and AwareInterface to inject the EntityManger into your controllers.
The AwareInterface can be added to any class which is initialized by the ServiceManager.
interface EntityManagerAwareInterface
{
/**
* Set EntityManager locator
*
* #param EntityManager $entityManager
*/
public function setEntityManager(EntityManager $entityManager);
/**
* Get service locator
*
* #return EntityManager
*/
public function getServiceLocator();
}
The Initializer is run when services are initialized by the ServiceManager. A check is performed to so if $instance is a EntityManagerAwareInterface.
use Application\EntityManager\EntityManagerAwareInterface;
use Zend\ServiceManager\InitializerInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class EntityManagerInitializer implements InitializerInterface
{
/**
* Initialize
*
* #param $instance
* #param ServiceLocatorInterface $serviceLocator
* #return mixed
*/
public function initialize($instance, ServiceLocatorInterface $serviceLocator)
{
if ($instance instanceof EntityManagerAwareInterface) {
$entityManager = $serviceLocator->get('doctrine.entitymanager.orm_default');
$instance->setEntityManager($entityManager);
}
}
}
Next add the Initializer to Module.php
public function getServiceConfig()
{
return [
'initializers' => [
'entityManager' => new EntityManagerInitializer(),
],
],
}
The advantage of going the Initializer route is there is a one time setup. Any class that implements the EntityManagerAwareInterface will have the EntityManager injected when the class is initialized.

Categories