8

I know that this has been covered extensively in other threads, but I'm struggling to work out how to replicate the effect of $this->getServiceLocator() from ZF2 controllers in ZF3 ones.

I have tried creating a factory using the various other answers and tutorials that I've found here and elsewhere, but ended up in a mess with each of them, so I'm pasting my code as it was when I started in the hope that someone can point me in the right direction?

From /module/Application/config/module.config.php

'controllers' => [
    'factories' => [
        Controller\IndexController::class => InvokableFactory::class,
    ],
],

From /module/Application/src/Controller/IndexController.php

public function __construct() {
    $this->objectManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
    $this->trust = new Trust;
}
Max Griffin
  • 439
  • 2
  • 5
  • 11

2 Answers2

15

You can not use $this->getServiceLocator() in controller any more.

You should add one more class IndexControllerFactory where you will get dependencies and inject it in IndexController

First refactor your config:

'controllers' => [
    'factories' => [
        Controller\IndexController::class => Controller\IndexControllerFactory::class,
    ],
],

Than create IndexControllerFactory.php

<?php

namespace ModuleName\Controller;

use ModuleName\Controller\IndexController;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;

class IndexControllerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container,$requestedName, array $options = null)
    {
        return new IndexController(
            $container->get(\Doctrine\ORM\EntityManager::class)
        );
    }
}

At the end refactor you IndexController to get dependencies

public function __construct(\Doctrine\ORM\EntityManager $object) {
    $this->objectManager = $object;
    $this->trust = new Trust;
}

You should check official documentation zend-servicemanager and play around a little bit...

tasmaniski
  • 4,767
  • 3
  • 33
  • 65
  • Thank you! It's the config where I'd been making a mistake. – Max Griffin Feb 11 '17 at 15:49
  • Nice example! Considering that you have more than one action per controller, but you have one factory per controller. If you use an object on specific action that dont use on other, you're initializing extra objects on same cases. What should be the solution on this case? – Diogo Alves Jul 07 '17 at 13:41
  • Simple :) create only one action per controller. Actually that is trend now with micro frameworks and PHP middlewares... – tasmaniski Jul 07 '17 at 14:20
0

Whilst the accepted answer is correct, I will implement mine a bit differently by injecting the container into the controller and then get other dependencies in constructor like so...

<?php

namespace moduleName\Controller\Factory;

use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
use moduleName\Controller\ControllerName;

class ControllerNameFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        return new ControllerName($container);
    }

}

Your controller should look something like this:

namespace ModuleName\Controller;


use Doctrine\ORM\EntityManager;
use Zend\ServiceManager\ServiceManager;


class ControllerName extends \App\Controller\AbstractBaseController
{

    private $orm;

    public function __construct(ServiceManager $container)
    {
        parent::__construct($container);

        $this->orm = $container->get(EntityManager::class);
    }

In your module.config, be sure to register the factory like so:

'controllers' => [
    'factories' => [
        ControllerName::class => Controller\Factory\ControllerNameFactory::class,
],
J.Ewa
  • 205
  • 3
  • 14