Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : Using __invoke(PluginManager $manager) in Service’s Factory

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on March 31, 2015

zf2-zendframework2I assume you already knew about registering service with factories type via closure or factory class that implements Zend\ServiceManager\FactoryInterface which is quite complex to do, and if we use pluginManager, for example, on Controller creation, we pushed to use :

namespace Application\Factory\Controller;

use Application\Controller\IndexController;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManger\ServiceLocatorInterface;

class IndexControllerFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $services  = $serviceLocator->getServiceLocator();    
        $myService = $services->get('MyService');
        
        return new IndexController($myService);
    }
}

Although above way will work, if you check above code with scrutinizer, you will get error :
interface-error-implementation

This is because the getServiceLocator() only exists in the concrete implementation(the ControllerManager class), not in the ServiceLocatorInterface interface.

__invoke(PluginManager $manager) for the rescue

If you read the documentation, you can get quote :

The factories should be either classes implementing Zend\ServiceManager\FactoryInterface 
or invokable classes.

That mean, you can use class that has __invoke() method, so you can pass the PluginManager instead of ServiceLocatorInterface.

namespace Application\Factory\Controller;

use Application\Controller\IndexController;
use Zend\Mvc\Controller\ControllerManager;

class IndexControllerFactory
{
    public function __invoke(ControllerManager $controllerManager)
    {
        $services  = $controllerManager->getServiceLocator();
        $myService = $services->get('MyService');
        
        return new IndexController($myService);
    }
}

Now, your scrutinizer check will be happy ;).

Note :
As Lucas Suggestion, if you still want to use createService(), you can check it with whenever $serviceLocator instanceof Zend\ServiceManager\ServiceLocatorAwareInterface, then we call getServiceLocator() :

// ...
function createService(ServiceLocatorInterface $serviceLocator)
{
   if ($serviceLocator instanceof ServiceLocatorAwareInterface) {
       $serviceLocator = $serviceLocator->getServiceLocator();
   }
   // ...
}
// ...

References :
1. http://blog.alejandrocelaya.com/2014/10/09/advanced-usage-of-service-manager-in-zend-framework-2/#comment-1627763990
2. https://samsonasik.wordpress.com/2013/01/02/zend-framework-2-cheat-sheet-service-manager/
3. http://framework.zend.com/manual/current/en/modules/zend.service-manager.quick-start.html#using-configuration

6 Responses

Subscribe to comments with RSS.

  1. Israel Pacheco said, on March 31, 2015 at 6:39 am

    great!!!

  2. Lucas CORBEAUX said, on April 6, 2015 at 1:17 am

    Hi Abdul Malik,

    Great article, thanks 🙂

    I’m not using scrutinizer so I don’t check if it works, but maybe you can solve this problem without using a callable (which is less performant and a bit less clear/clean than a FactoryInterface).

    My idea is to delegate to a protected method the responsibility to retrieve the inner ServiceLocator, you can then use another Type Hint:

    public function createService(ServiceLocatorInterface $serviceLocator)
    {
    $services = $this->getInnerServiceLocator($sla);
    $myService = $services->get(‘MyService’);

    return new IndexController($myService);
    }

    protected function getInnerServiceLocator(ServiceLocatorAwareInterface $sla)
    {
    return $sla->getServiceLocator();
    }

    A bit more code, but you can reuse it with a trait for other factories with the same needs.

  3. Lucas CORBEAUX said, on April 6, 2015 at 1:18 am

    Erratum, there is a typo in my code line 3:
    $services = $this->getInnerServiceLocator($sla);

    Should be:
    $services = $this->getInnerServiceLocator($serviceLocator);


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: