Внедрение зависимостей в фикстуры
Класс является фикстурой, если он реализует интерфейс \Doctrine\Fixture\Fixture. В интерфейсе определены, два метода import и purge. При использовании фикстур в реальных условиях, зачастую возникает потребность, использовать различные компоненты из приложения. Например, в фикстурах может потребоваться ObjectManager Doctrine2, или сервис для загрузки данных из xml формата. Далее будут описываться способ внедрения зависимостей в фикстуры.
Внедрение зависимостей через FixtureInitializer
Быстрый старт
- Создать Aware интерфейс. Если фикстура реализует данный интерфейс, то значит в нее требуется внедрить зависимость
- Aware интерфейс, должен определять setter'ы, позволяющие передать зависимость
interface DependencyServiceAwareInterface
{
function setDependencyService(DependencyService $dependencyService);
}
- Создать FixtureInitializer
- Создать класс реализующий интерфейс Nnx\DoctrineFixtureModule\FixtureInitializer\FixtureInitializerInterface
- В качестве аргументов constructor указать сервисы которые необходимо внедрить в фикстуру
- В классе реализовать метод getSubscribedEvents, возвращающий массив с двумя значениями "import" и "purge"
- Реализовать в классе два метода import и purge
- В методах import и purge проверяется, что если фикстура реализует заданный Aware интерфейс, то в нее устанавливается требуемая зависимость
use Doctrine\Fixture\Event\ImportFixtureEventListener;
use Doctrine\Fixture\Event\PurgeFixtureEventListener;
use Nnx\DoctrineFixtureModule\FixtureInitializer\FixtureInitializerInterface;
class MyFixtureInitializer implements
FixtureInitializerInterface,
ImportFixtureEventListener,
PurgeFixtureEventListener
{
/**
* Constructor.
*
* @param DependencyService $dependencyService
*/
public function __construct(DependencyService $dependencyService)
{
$this->dependencyService = $dependencyService;
}
/**
* {@inheritdoc}
*/
public function getSubscribedEvents()
{
return array(
ImportFixtureEventListener::IMPORT,
PurgeFixtureEventListener::PURGE,
);
}
/**
* {@inheritdoc}
*/
public function purge(FixtureEvent $event)
{
if ( ! ($fixture instanceof MyServiceAwareInterface)) {
return;
}
$fixture->setDependencyService($this->dependencyService);
}
/**
* {@inheritdoc}
*/
public function import(FixtureEvent $event)
{
if ( ! ($fixture instanceof MyServiceAwareInterface)) {
return;
}
$fixture->setDependencyService($this->dependencyService);
}
}
- Создать фабрику для FixtureInitializer
- Создать стандартную фабрику (реализует интерфейс \Zend\ServiceManager\FactoryInterface )
- Из ServiceLocator (необходимо помнить что serviceLocator в фабриках используемых для менеджеров плагинов, является самим менеджером плагинов), получить необходимые зависимости
- Создать FixtureInitializer и передать в конструктор необходимые зависимости
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class MyFixtureInitializerFactory implements FactoryInterface
{
/**
* @inheritDoc
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$appServiceLocator = $serviceLocator instanceof AbstractPluginManager ? $serviceLocator->getServiceLocator() : $serviceLocator;
/** @var DependencyService $dependencyService */
$dependencyService = $appServiceLocator->get(DependencyService::class);
return new MyFixtureInitializer($dependencyService);
}
}
- Зарегестрировать FixtureInitializer в менеджере плагинов \Nnx\DoctrineFixtureModule\Executor\FixtureExecutorManagerInterface
- В секцию ['nnx_fixture_initializer']['factories'] конфигурационных файлов приложения, добавить созданный FixtureInitializer
return [
'nnx_fixture_initializer' => [
'factories' => [
MyFixtureInitializer::class => MyFixtureInitializerFactory::class,
]
],
];
- Добавить FixtureInitializer в список тех FixtureInitializer, которые запускаются для фикстур
- Добавить в секцию ['nnx_doctrine_fixture_module']['fixtureInitializer'] имя FixtureInitializer
return [
'nnx_doctrine_fixture_module' => [
'fixtureInitializer' => [
MyFixtureInitializer::class
]
],
];
Описание FixtureInitializer
Для внедрения зависимостей используется модификация паттерна "Method Injection", а именно "Interface Injection". Непосредственно после создания фикстуры, запускаются FixtureInitializer.
FixtureInitializer это класс реализующий \Nnx\DoctrineFixtureModule\FixtureInitializer\FixtureInitializerInterface. Интерфейс \Nnx\DoctrineFixtureModule\FixtureInitializer\FixtureInitializerInterface, расширяет \Doctrine\Common\EventSubscriber.
Таким образом в классе FixtureInitializer, необходимо реализовать метод getSubscribedEvents, в котором нужно вернуть, массив с именами событий, на которые подписываемся.
Для реализации FixtureInitializer, необходимо подписаться на два события
- import - событие бросаемое, когда происходит запуск процесса импорта
- purge - событие бросаемое, когда происходит запуск процесса удаления данных
Пример FixtureInitializer
use Doctrine\Fixture\Event\ImportFixtureEventListener;
use Doctrine\Fixture\Event\PurgeFixtureEventListener;
use Nnx\DoctrineFixtureModule\FixtureInitializer\FixtureInitializerInterface;
class MyFixtureInitializer implements
FixtureInitializerInterface,
ImportFixtureEventListener,
PurgeFixtureEventListener
{
/**
* Constructor.
*
* @param DependencyService $dependencyService
*/
public function __construct(DependencyService $dependencyService)
{
$this->dependencyService = $dependencyService;
}
/**
* {@inheritdoc}
*/
public function getSubscribedEvents()
{
return array(
ImportFixtureEventListener::IMPORT,
PurgeFixtureEventListener::PURGE,
);
}
/**
* {@inheritdoc}
*/
public function purge(FixtureEvent $event)
{
if ( ! ($fixture instanceof MyServiceAwareInterface)) {
return;
}
$fixture->setDependencyService($this->dependencyService);
}
/**
* {@inheritdoc}
*/
public function import(FixtureEvent $event)
{
if ( ! ($fixture instanceof MyServiceAwareInterface)) {
return;
}
$fixture->setDependencyService($this->dependencyService);
}
}
В фикстуре необходимо реализовать два метода import и purge. В методах обычно происходит проверка, того что фикстура, реализует заданный интерфейс. В случае если фикстура, интерфейс реализует, то происходит внедрение соответствующей зависимости в фиктсуру.
Регистрация FixtureInitializer
Для работы с FixtureInitializer используется специальный менеджер плагинов \Nnx\DoctrineFixtureModule\FixtureInitializer\FixtureInitializerManagerInterface. Для регистрации FixtureInitializer в менеджере плагинов, необходимо добавить соответствующий плагин в секцию nnx_fixture_initializer.
return [
'nnx_fixture_initializer' => [
'invokables' => [
],
'factories' => [
MyFixtureInitializer::class => MyFixtureInitializerFactory::class,
],
'abstract_factories' => [
],
'shared' => [
]
],
];
FixtureInitializer бывают двух типов:
- Initializer для контекста - такие FixtureInitializer, создаются и подписываются на события import и purge, в качестве аргумента, передаются данные переданные в аргументах import и purge , объекта имплементирующего \Nnx\DoctrineFixtureModule\Executor\ExecutorInterface
- Статические Initializer - такие FixtureInitializer, не создаются каждый раз заново, также они подписываются единожды на события import и purge всех FixtureInitializer
Добавление Initializer для контекста
Для добавления Initializer для контекста, необходимо в секции ['nnx_doctrine_fixture_module']['contextInitializer'] добавить имя Initializera'a (по этому имени он будет получен из \Nnx\DoctrineFixtureModule\Executor\FixtureExecutorManagerInterface)
Добавление статического Initializer
Для добавления Initializer для контекста, необходимо в секции ['nnx_doctrine_fixture_module']['fixtureInitializer'] добавить имя Initializera'a (по этому имени он будет получен из \Nnx\DoctrineFixtureModule\Executor\FixtureExecutorManagerInterface)