Alexander Goncharov
Alexander Goncharov

Reputation: 1662

Zend2 - how to forward other module controller?

Controller forwarding - is a great feauture, and I made widget conception with it. But by default it can't dispatch controller of non-self module. To resolve this problem(and also to avoid contoller configuration at all), I added abstaract_factory for controller constructon:

namespace Engine\Mvc\Controller;

use Zend\ServiceManager\AbstractFactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class Autoloader implements AbstractFactoryInterface
{
    public function canCreateServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName)
    {
        return true;
    }

    public function createServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName)
    {
        $class = ucfirst(str_replace('/', '\\', $requestedName)).'Controller';
        if (!class_exists($class)){
            return false;
        }
        return new $class;
    }
}

/*In Module class*/
public function getControllerConfig()
    {
        return array(
            'abstract_factories' => array(
                'Engine\Mvc\Controller\Autoloader'
            ),
        );
    }

It works fine. But only for invokable controllers - without constructor arguments. When I try to embed controller from module, that i can't change (ZfcUser , installed with composer, for example) - it may fail, because theese controllers can have non invokable init:

/*in zfc-user/module.config.php */
'controllers' => array(
        'factories' => array(
            'zfcuser' => 'ZfcUser\Factory\Controller\UserControllerFactory',
        ),
    ),

/*factory for controller*/
class UserControllerFactory implements FactoryInterface
{
    /**
     * Create controller
     *
     * @param ControllerManager $serviceLocator
     * @return UserController
     */
    public function createService(ServiceLocatorInterface $controllerManager)
    {
        /* @var ServiceLocatorInterface $serviceLocator */
        $serviceLocator = $controllerManager->getServiceLocator();

        $userService = $serviceLocator->get('zfcuser_user_service');
        $registerForm = $serviceLocator->get('zfcuser_register_form');
        $loginForm = $serviceLocator->get('zfcuser_login_form');
        $options = $serviceLocator->get('zfcuser_module_options');

        $controller = new UserController($userService, $options, $registerForm, $loginForm);

        return $controller;
    }
}

Froward in module1 not see UserControllerFactory of ZfcUser module, it try to construct controller with my abstract_factory, and gives an error, because UserController needs all arguments.

It may resolve by swapping Zend\Mvc\Controller\Plugin\Service\ForwardFactory - just need to construct Forward with "global" ControllerManager . But I'm not sure, "global" ControllerManager is exists in Zend2 .

Questions:

  1. Is there global ControllerManager , how can i get it from ServiceManager ?
  2. Any other ways to dispatch with controller plugin forward non-self module controllers( with constructing controllers by non-self module controller config)?

Upvotes: 1

Views: 161

Answers (1)

Alexander Goncharov
Alexander Goncharov

Reputation: 1662

Question is gone, I'm stupid. Forward has access to all controllers, also to non-self controllers. But by controller pseudo (name in controller manager) - not by class name, for example we have controller definition:

/*in zfc-user/module.config.php - here we have 'zfcuser' as controller pseudo */
'controllers' => array(
        'factories' => array(
            'zfcuser' => 'ZfcUser\Factory\Controller\UserControllerFactory',
        ),
 ),

We can forward this controller from any module this code:

$widgetLogin = $this->forward()->dispatch('zfcuser', ['action' => 'login']);

Thanks.

UPD:

If you want to use name of class only, to accessing controllers from forward (to work with same names Engine\Mvc\Controller\Autoloader from question resolves) - you can add alias to non-self controller in your module, for example:

/*in module.config.php of your module*/
'controllers' => [
    'abstract_factories' => [
        'Engine\Mvc\Controller\Autoloader'
    ],
    'aliases' => [
        'ZfcUser/Controller/User' => 'zfcuser'
    ]
]

Upvotes: 0

Related Questions