Search code examples
phpdependency-injectionzend-framework2factoryservice-layer

How do I inject dependency in service layer?


I am new to Zend Framework 2 and I am new to the concept of dependency injection, service layer and factory.

I am currently trying to create a service layer that required Service Locator. Once that works then I need to pass this service to a controller but I can't quite get it to work. I always get this error message in PageControllerFactory.php

Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for `Template\Service\PageService` 

Can anybody help guiding me into the right direction on why I am unable to fetch or create an instance for Template\Service\PageService?

I was thinking maybe I didn't include it module.config.php but isn't that what's service_manager factories supposed to do?

module.config.php

'controllers' => array(
    'factories' => array(
        'Template\Controller\Factory\PageControllerFactory',
    ),
),

'service_manager' => array(
    ...
    'factories' => array(
        'Template\Service\Factory\PageServiceFactory',
        'Template\Service\Factory\SharedServiceFactory',
    ),
    ...
),

Here is a Factory that I inject Service Locator in for SharedService

SharedServiceFactory.php

namespace Template\Service\Factory;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Template\Service\SharedService;

class SharedServiceFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        return new SharedService($serviceLocator->getServiceLocator());
    }
}

I then use __construct() to retrieve the Service Locator.

SharedService.php

namespace Template\Service;

use Zend\ServiceManager\ServiceLocatorInterface;
use Template\Service\SharedServiceInterface;

class SharedService implements SharedServiceInterface
{
    protected $serviceLocator;
    ...

public function __construct(ServiceLocatorInterface $serviceLocator)
{
    $this->serviceLocator = $serviceLocator;
}
...

The code breaks here in PageControllerFactory.php. I assume that $parentService->get('Template\Service\PageService') can't retrieve Template\Service\PageService here. That's why it throws an error.

PageControllerFactory.php

namespace Template\Controller\Factory;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Template\Controller\PageController;

class PageControllerFactory implements FactoryInterface
{
     public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $parentService = $serviceLocator->getServiceLocator();
        $pageService = $parentService->get('Template\Service\PageService');
        $sharedService = $parentService->get('Template\Service\SharedService');

        return new PageController($pageService, $sharedService);
    }
}

PageController.php

namespace Template\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Template\Service\PageServiceInterface;
use Template\Service\SharedServiceInterface;

class PageController extends AbstractActionController
{
    protected $pageService;
    protected $sharedService;

    public function __construct(
        PageServiceInterface $pageService,
        SharedServiceInterface $sharedService
    ) {
        $this->pageService = $pageService;
    }
...

Solution

  • Instead of this :

    'service_manager' => array(
        ...
        'factories' => array(
            'Template\Service\Factory\PageServiceFactory',
            'Template\Service\Factory\SharedServiceFactory',
        ),
        ...
    ),
    

    declare this :

    'service_manager' => array(
        ...
        'factories' => array(
            'Template\Service\PageService' => 'Template\Service\Factory\PageServiceFactory',
            'Template\Service\SharedService' => 'Template\Service\Factory\SharedServiceFactory',
        ),
        ...
    ),
    

    Factories in config has ot be declared on this format : [Alias => [FQCN of factory]]

    And via the service locator you have to call the alias.