A free and open-source book on ZF3 for beginners


4.9. Регистрация контроллера

Все классы контроллера, принадлежащие модулю, должны быть зарегистрированы в файле конфигурации module.config.php. Если вашему контроллеру не нужно вызывать какие либо сервисы (если у него нет зависимостей), то вы можете зарегистрировать его следующим образом:

<?php
use Zend\ServiceManager\Factory\InvokableFactory;

return [
    // ...
    
    'controllers' => [
        'factories' => [
            Controller\IndexController::class => InvokableFactory::class
            // Вставьте сюда регистрацию других контроллеров
        ],
    ],
    
    // ...
];

В строке 7 у нас есть ключ controllers, который содержит подключ factories. Чтобы зарегистрировать класс контроллера, нужно добавить строку в виде пары key=>value. Ключом должно быть полностью квалифицированное имя класса контроллера, например, \Application\Controller\IndexController (мы можем использовать ключевое слово PHP ::class для разрешения имен) и значение должно быть именем фабричного класса. В нашем случае, мы используем стандартную фабрику InvokableFactory, но, если хотите, можете создать свою фабрику.

Используя InvokableFactory, вы говорите Zend Framework'у, что он может вызвать контроллер, инстанцировав его с помощью оператора new. Это самый простой способ инстанциации контроллера. В качестве альтернативы, вы можете создать свою фабрику для создания экземпляров контроллера и внедрить зависимости (inject dependencies) в контроллер.

4.9.1. Регистрация фабрики контроллера

Если в вашем контроллере вам нужно будет вызвать какой либо сервис (а это случается очень часто), вам нужно будет извлечь этот сервис из менеджера сервисов (мы обсуждали менеджер сервисов в главе Как работает вебсайт) и передать этот сервис в конструктор класса контроллера, и затем контроллер должен сохранить переданный сервис в виде приватного свойства для своего внутреннего использования (dependency injection).

Эта процедура обычно реализуется внутри фабрики. Например, предположим, что в нашем контроллере мы хотим иметь возможность вызова некого сервиса CurrencyConverter, который умеет конвертировать валюту USD в EUR. Класс фабрики для нашего контроллера будет выглядеть следующим образом:

<?php 
namespace Application\Controller\Factory;

use Zend\ServiceManager\Factory\FactoryInterface;
use Application\Service\CurrencyConverter;
use Application\Controller\IndexController;

// Класс фабрики
class IndexControllerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, 
                     $requestedName, array $options = null) 
    {
        // Извлечь экземпляр сервиса CurrencyConverter из менеджера сервисов.
        $currencyConverter = $container->get(CurrencyConverter::class);
        
        // Создать экземпляр контроллера и передать сервис в его конструктор.
        return new IndexController($currencyConverter);	
    }
}

Далее вы регистрируете контроллер обычным путем, но указываете фабрику, которую мы только что написали:

<?php
return [
    // ...
    
    'controllers' => [
        'factories' => [
            Controller\IndexController::class => Controller\Factory\IndexControllerFactory::class
        ],
    ],
    
    // ...
];

Если у вас есть опыт работы с Zend Framework 2, вы можете заметить, что в ZF3 все стало немного по-другому. В ZF2 у класса AbstractActionController был метод getServiceLocator(), который позволял извлекать зависимости даже и без фабрики контроллера. В ZF3 вы должны передавать зависимости принудительно. Это немного более утомительно, но зато удаляет "скрытые" зависимости и делает код легче для понимания.

4.9.2. LazyControllerAbstractFactory

Написание фабрики для почти каждого контроллера может показаться утомительным на первый взгляд. Если вы настолько ленивы, что не хотите этого делать, вы можете использовать стандартную фабрику LazyControllerAbstractFactory.

Фабрика LazyControllerAbstractFactory использует reflection для определения того, какие сервисы ваш контроллер хочет использовать. Вам просто нужно указать тип (typehint) аргументов конструктора контроллера, и фабрика сама извлечет нужные сервисы и передаст их конструктору.

Например, чтобы внедрить сервис CurrencyConverter в ваш контроллер, убедитесь, что конструктор контроллера выглядит следующим образом:

namespace Application\Controller;

use Application\Service\CurrencyConverter;

class IndexController extends AbstractActionController
{
    // Здесь мы сохраним сервис для внутреннего использования.
    private $currencyConverter;
    
    // Укажите тип аргументов конструктора, чтобы получить сервисы этого типа.
    public function __construct(CurrencyConverter $currencyConverter)
    {
        $this->currencyConverter = $currencyConverter;
    }
}

Затем вы регистрируете контроллер точно также, но указываете фабрику LazyControllerAbstractFactory:

<?php
use Zend\Mvc\Controller\LazyControllerAbstractFactory;

return [
    // ...
    
    'controllers' => [
        'factories' => [
            Controller\IndexController::class => LazyControllerAbstractFactory::class
        ],
    ],
    
    // ...
];

Top