Zend Framework 2 : Automatic Controller Invokables via Abstract Factories
Before you continue reading, you should know that this is just to handle if you forgot to mention/register your controller in invokables/factories. Being explicit is more secure and reliable.
Ok then, let’s start. One of the Zend Framework Service Managers keys is abstract_factories. An abstract factory can be considered a “fallback” – if the service does not exist in the manager, it will then pass it to any abstract factories attached to it until one of them is able to return an object. For example, we want to automatic register class of our controllers of our application if we forgot to register in invokables.
1. Create an abstract factories
//module/SanCommons/src/SanCommons/Services/CommonControlAppAbstractFactory.php namespace SanCommons\Services; use Zend\ServiceManager\AbstractFactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; class CommonControlAppAbstractFactory implements AbstractFactoryInterface { public function canCreateServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName) { if (class_exists($requestedName.'Controller')){ return true; } return false; } public function createServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName) { $class = $requestedName.'Controller'; return new $class; } }
2. Register to getControllerConfig()
//module/SanCommons/Module.php namespace SanCommons; class Module { public function getControllerConfig() { return array( 'abstract_factories' => array( 'SanCommons\Services\CommonControlAppAbstractFactory' ), ); } public function getAutoloaderConfig(){ /*common code*/} public function getConfig(){ /*common code*/} }
Remember, ‘controllers’ and ‘ModuleManager’ are the services that composed automatically by mvc stack. So, if route found a match ‘/:controller’ segment, ServiceManager will find a Service that named the Name of The Controller that pass in url in ‘controllers’ => ‘invokables’ key.
//module/SanCommons/config/module.config.php return array( 'controllers' => array( 'invokables' => array( 'YourModule\Controller\A' => 'YourModule\Controller\AController', 'YourModule\Controller\B' => 'YourModule\Controller\BController', /*.. etc ...*/ ), ), ),
The controllers services named ‘YourModule\Controller\A’, etc. Whenever you forgot to mention/register that in ServiceManager, ServiceManager will find it in the ‘Limbo’ (abstract_factories). If the abstract factory returns true to the canCreateServiceWithName method the service manager will create a service via createServiceWithName method.
For example : If we just created a controller with end with ‘Controller’, for example, TestAutoController, and forgot to register it into invokables, The Controller will automatically getted because service automatically created.
What if we want other service that not in Mvc Stack, and need to be called by ServiceLocator with ‘hand’ 😀 ? create abstract factory and register into abstract_factories under getServiceConfig().
Done !
References :
1. http://akrabat.com/zend-framework-2/zendservicemanager-configuration-keys/
2. http://zf2.readthedocs.org/en/latest/modules/zend.service-manager.intro.html
3. http://www.stephenrhoades.com/?p=513
4. http://www.framework.zend.com/manual/2.0/en/user-guide/routing-and-controllers.html
5. http://framework.zend.com/manual/2.0/en/modules/zend.mvc.quick-start.html#create-a-route
Zend Framework 2 : Step by Step Create Custom View Strategy
Zend Framework 2 ships with three Rendering and Response Strategies that we can use within our application : PhpRendererStrategy, JsonStrategy, and FeedStrategy. If we want to use a custom strategy, for example : add content-type : image/png to all header response, we should create custom view strategy to create custom response. I will give you an example how to create it.
Zend Framework 2 : Using Zend Framework 1 libraries
Do you still need some components of Zend Framework 1 in your Project that use Zend Framework 2 ? It easy to use Zend Framework 1 libraries in Zend Framework 2 by register Zend Framework 1 libraries in Zend Framework 2 StandardAutoloader or by register at composer’s ClassLoader.
Zend Framework 2 : Disable Layout in specific Module
Based on definition of module in Zend Framework 2 : “all related code and assets that solve a specific problem”, sometime, for example, we need a module that provide Ajax only, and no need a layout in all actions. So, we can do a trick to reduce code redundancy in every controller/actions.
namespace YourModule; use Zend\Mvc\MvcEvent; class Module { public function onBootstrap(MvcEvent $e) { $sharedEvents = $e->getApplication()->getEventManager()->getSharedManager(); $sharedEvents->attach(__NAMESPACE__, 'dispatch', function($e) { $result = $e->getResult(); if ($result instanceof \Zend\View\Model\ViewModel) { $result->setTerminal($e->getRequest()->isXmlHttpRequest()); //if you want no matter request is, the layout is disabled, you can //set true : $result->setTerminal(true); } }); } }
How about all module ? attach into Zend\Mvc\Controller\AbstractActionController
namespace YourModule; use Zend\Mvc\MvcEvent; class Module { public function onBootstrap(MvcEvent $e) { $sharedEvents = $e->getApplication()->getEventManager()->getSharedManager(); $sharedEvents->attach('Zend\Mvc\Controller\AbstractActionController','dispatch', function($e) { $result = $e->getResult(); if ($result instanceof \Zend\View\Model\ViewModel) { $result->setTerminal($e->getRequest()->isXmlHttpRequest()); //if you want no matter request is, the layout is disabled, you can //set true : $result->setTerminal(true); } }); } }
Remember, you should return ViewModel() in every action in your module.
11 comments