Содержание


ServiceManager Quick Start


ServiceManager Quick Start, ЗФ2, Zend Framework 2, ZF2




По-умолчанию Zend Framework 2 использует Zend\ServiceManager с MVC. Поэтому в большинстве случаев Вы будете устанавливать сервисы, invoke классы, псевдонимы (aliases), фабрики и др. через конфигурационные файлы или классе module.

 

По-умолчанию слушатель менеджера модуля Zend\ModuleManager\Listener\ServiceListener деалет следующее:

 

1) Перед загрузкой модулей, Zend\ModuleManager\Feature\ServiceProviderinterfaceили метод getServiceConfig() -  вызовет этот метод и объединит содержимое конфигурационных файлов. 

2) После загрузки модулей, берет всю конфигруацию с Zend\ModuleManager\Feature\ConfigListener и делает её доступной по ключам «service_manager key»

3) В итоге, он использует созданную конфигурацию для настройки ServiceManager

 

В большинстве случаев, Вы не будете взаимодействовать с ServiceManager, кроме как добавления в него сервисов. Будьте особенно внимательны при настройке конфигов и ServiceManager. При создании фабрик Вы можете взаимодействовать с ServiceManager для внедрения зависимостей. Так же ServiceManager можно использовать для «ленивого» внедрения зависимостей через ServiceLocatorAwareInterface и API ServiceManager.

 



Использование конфигурации

 

При создании конфигурации необходимо использовать ключи «service_manager key» на самом верхнем уровне конфига с одним или более вспомогательных ключей:

 

1) abstract_factories, абстрактные фабрики, массив состоящий из имен классов абстрактных классов.

2) aliases, псевдонимы, ассоциативный массив состоящий из пар «имя псевдонима - соответствие»

3) factories, фабрики, массив состоящий из пар «имя сервиса – класс фабрики». Фабрикой должны быть либо классы реализующие Zend\ServiceManager\FactoryInterface либо invokable классы. При использовании файлов конфигурации, фабрикой может выступать функция замыкание.

4) invokables, вызовы, массив состоящий из пар «имя сервиса – имя класса». Имя класса должно соответствовать классу, который может отработать без обязательной передачи аргументов в конструктор.

5) services, сервисы, массив состоящий из пар «имя сервиса -  объект».

6) shared,общедоступность, массив состоящий из пар «имя сервиса – булево значение», указывающая на то, должен ли быть сервис доступным или нет.  По-умолчанию в ServiceManager все сервисы доступны. Однако вручную можно указать значение «false», то есть будет возвращаться каждый раз новый экземпляр, а не уже существующий.

 


Модули в качестве создателей сервисов (Service Providers)

 

 Модули могут выступать в качестве создателей сервисов. Для этого класс Moduleдолжен реализовать интерфейс Zend\ModuleManager\Feature\ServiceProviderInterface, или проще говоря метод getServiceConfig(). Этот метод должен возвращать что то из :

1) Массив (или Traversable object) конфигурации, совместимыйс Zend\ServiceManager\Config. Ключи массива должны быть из тех, что описаны выше.

2) Строка, содержащая имя класса, реализующего Zend\ServiceManager\ConfigInterface.

3) Экземпляр Zend\ServiceManager\Config илиобъектреализующий Zend\ServiceManager\ConfigInterface.

 

Как говорилось раньше, эта конфигурация будет объединена с конфигурацией с других модулей перед передачей в ServiceManager. Это позволяет при необходимость переопределять конфигурации, описанные в других модулях.

 


Примеры


Пример конфигурации

 В этом примере показана валидная конфигурация для приложения, демонстрирующая все возможные ключи. Конфигурации объединены в следующем порядке:

1) Конфигурация возвращаемая из класса Module с помощью метода getServiceConfig(), в порядке, в котором будут обработаны модули.

2) Конфигурация модуля с помощью ключей «service_manager key», в порядке, в котором будут обработаны модули.

3) Конфигурация приложения в директории «config/autoload/», в порядке, в котором будут обработаны модули.

 

Таким образом у Вас появляется множество возможностей для изменения настроек service manager:

<?php
// a module configuration, "module/SomeModule/config/module.config.php"
return array(
    'service_manager' => array(
        'abstract_factories' => array(
            // Valid values include names of classes implementing
            // AbstractFactoryInterface, instances of classes implementing
            // AbstractFactoryInterface, or any PHP callbacks
            'SomeModuleServiceFallbackFactory',
        ),
        'aliases' => array(
            // Aliasing a FQCN to a service name
            'SomeModule\Model\User' => 'User',
            // Aliasing a name to a known service name
            'AdminUser' => 'User',
            // Aliasing to an alias
            'SuperUser' => 'AdminUser',
        ),
        'factories' => array(
            // Keys are the service names.
            // Valid values include names of classes implementing
            // FactoryInterface, instances of classes implementing
            // FactoryInterface, or any PHP callbacks
            'User'     => 'SomeModule\Service\UserFactory',
            'UserForm' => function ($serviceManager) {
                $form = new SomeModule\Form\User();
 
                // Retrieve a dependency from the service manager and inject it!
                $form->setInputFilter($serviceManager->get('UserInputFilter'));
                return $form;
            },
        ),
        'invokables' => array(
            // Keys are the service names
            // Values are valid class names to instantiate.
            'UserInputFiler' => 'SomeModule\InputFilter\User',
        ),
        'services' => array(
            // Keys are the service names
            // Values are objects
            'Auth' => new SomeModule\Authentication\AuthenticationService(),
        ),
        'shared' => array(
            // Usually, you'll only indicate services that should _NOT_ be
            // shared -- i.e., ones where you want a different instance
            // every time.
            'UserForm' => false,
        ),
    ),
);

Важно: Конфигурация и PHP.

В файлах конфигураций не рекомендуется создание новых объектов и экземпляров, фабрик в замыканиях. Так как эти файлы могут быть расположены не на своих местах и не будут автоматически загружены, или могут быть перезаписаны, если произойдет совпадение имен, что в свою очередь ведь к потерям процессорного времени и возможной нестабильной работы Вашего приложения.

Например, если есть необходимость в фабрике -  создайте отдельную фабрику. Если же нужно создать какую то специфическую зависимость (DI) -  используйте для этого класс Module или слушателей.

 


Module возвращает массив

 

В этом пример демонстрируется, как класс Module возвращает массив настроек. В общем -  это тоже самое, что и в предыдущем примере.

namespace SomeModule;
 
class Module
{
    public function getServiceConfig()
    {
        return array(
            'abstract_factories' => array(),
            'aliases' => array(),
            'factories' => array(),
            'invokables' => array(),
            'services' => array(),
            'shared' => array(),
        );
    }
}


Возвращается экземпляр настроек

 

Для начала создадим класс, содержащий настройки:

namespace SomeModuleService;
 
use SomeModule\Authentication;
use SomeModule\Form;
use Zend\ServiceManager\Config;
use Zend\ServiceManager\ServiceManager;
 
class ServiceConfiguration extends Config
{
    /**
     * This is hard-coded for brevity.
     */
    public function configureServiceManager(ServiceManager $serviceManager)
    {
        $serviceManager->setFactory('User', 'SomeModule\Service\UserFactory');
        $serviceManager->setFactory('UserForm', function ($serviceManager) {
            $form = new FormUser();
 
            // Retrieve a dependency from the service manager and inject it!
            $form->setInputFilter($serviceManager->get('UserInputFilter'),
            return $form;
        });
        $serviceManager->setInvokableClass('UserInputFilter', 'SomeModule\InputFilter\User');
        $serviceManager->setService('Auth', new Authentication\AuthenticationService());
        $serviceManager->setAlias('SomeModuleModelUser', 'User');
        $serviceManager->setAlias('AdminUser', 'User');
        $serviceManager->setAlias('SuperUser', 'AdminUser');
        $serviceManager->setShared('UserForm', false);
    }
}

Затем используем его в нашем классе Module:

namespace SomeModule;
 
// We could implement ZendModuleManagerFeatureServiceProviderInterface.
// However, the module manager will still find the method without doing so.
class Module
{
    public function getServiceConfig()
    {
        return new Service\ServiceConfiguration();
        // OR:
        // return 'SomeModule\Service\ServiceConfiguration';
    }
}


Создание класса  ServiceLocator- Аware

 

По-умолчанию Zend Framework 2 MVC регистрирует инициализатора, который инъекцирует экземпляр ServiceManager, который в свою очередь является реализацией Zend\ServiceManager\ServiceLocatorInterface, в любой класс, реализующий Zend\ServiceManager\ServiceLocatorAwareInterface. Простой пример выглядит так:

namespace SomeModuleControllerBareController;
 
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Stdlib\DispatchableInterface as Dispatchable;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Stdlib\ResponseInterface as Response;
 
class BareController implements
    Dispatchable,
    ServiceLocatorAwareInterface
{
    protected $services;
 
    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->services = $serviceLocator;
    }
 
    public function dispatch(Request $request, Response $response = null)
    {
        // ...
 
        // Retrieve something from the service manager
        $router = $this->services->get('Router');
 
        // ...
    }
}



Автор статьи: DuB