Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : Automatic Controller Invokables via Abstract Factories

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on December 23, 2012

zf2-zendframework2 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

Advertisements

Zend Framework 2 : Step by Step Create Custom View Strategy

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on December 10, 2012

zf2-zendframework2 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.

Continue Reading

Zend Framework 2 : Using Zend Framework 1 libraries

Posted in Tutorial PHP, Zend Framework, Zend Framework 2 by samsonasik on December 4, 2012

zf2-zendframework2 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.

Continue Reading

Zend Framework 2 : Disable Layout in specific Module

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on December 2, 2012

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.