Как зарегистрировать собственный гидратор в Zend Framework 2?

В приложении ZF2, управляемом Apigility, я хочу использовать пользовательский Hydrator,

Module учебный класс

class Module implements ApigilityProviderInterface {
...
public function getServiceConfig() {
return array(
'factories' => array(
...
'MyNamespace\\Hydrator\\ProjectHydrator' => function(ServiceManager $serviceManager) {
$projectHydrator = new ProjectHydrator();
$projectHydrator->setImageService($serviceManager->get('Portfolio\V2\Rest\ImageService'));
return $projectHydrator;
}
),
...
);
}
}

module.config.php

...
'zf-hal' => array(
'metadata_map' => array(
...
'Portfolio\\V2\\Rest\\Project\\ProjectEntity' => array(
'entity_identifier_name' => 'id',
'route_name' => 'portfolio.rest.project',
'route_identifier_name' => 'id',
// 'hydrator' => 'Zend\\Stdlib\\Hydrator\\ClassMethods',
'hydrator' => 'MyNamespace\\Hydrator\\ProjectHydrator',
),
...
),
),
...

Это игнорируется, когда коллекция извлекается, но это другая проблема. Вот). Когда требуется одна сущность, запускается гидратиновый механизм, но он не использует мою фабрику для создания экземпляра.

После некоторой отладки я пришел в это место в ZF\Hal\Metadata\Metadata#setHydrator(...) код:

if (is_string($hydrator)) {
if (null !== $this->hydrators
&& $this->hydrators->has($hydrator)
) {
$hydrator = $this->hydrators->get($hydrator);
} elseif (class_exists($hydrator)) {
$hydrator = new $hydrator(); // <-- here
}
}

Обычай Hydrator создается напрямую. (В моем случае это приводит к фатальной ошибке, так как он пытается затем выполнить метод на ProjectHydrator#imageService, это не установлено). Я посмотрел на Metadata#hydrators (типа Zend\Stdlib\Hydrator\HydratorPluginManager) и нашел только четыре по умолчанию invocables, вот почему null !== $this->hydrators && $this->hydrators->has($hydrator) является false и прямой экземпляр судят.

Итак, я думаю, я должен зарегистрировать свой гидратор. Где / как я могу это сделать?


РЕДАКТИРОВАТЬ:

Я перемещаю заводской код из Module#getServiceConfig() в Module#getHydratorConfig():

public function getHydratorConfig() {
return array(
'factories' => array(
// V2
'MyNamespace\\Hydrator\\ProjectHydrator' => function(ServiceManager $serviceManager) {
$projectHydrator = new ProjectHydrator();
$projectHydrator->setImageService($serviceManager->get('Portfolio\V2\Rest\ImageService'));
return $projectHydrator;
}
),
);
}

То же самое над массивом конфигурации в module.config.php (нужен Factory учебный класс):

module.config.php

return array(
...
'hydrators' => array(
'factories' => array(
'MyNamespace\\Hydrator\\ProjectHydrator' => 'MyNamespace\\Hydrator\\ProjectHydratorFactory',
),
),
);

Но это заканчивается ошибкой:

Zend \ ServiceManager \ Exception \ ServiceNotFoundException

Файл:
/var/www/my-project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:550
Сообщение: Zend \ Stdlib \ Hydrator \ HydratorPluginManager :: get не удалось
получить или создать экземпляр для портфолио \ V2 \ Rest \ ImageService

2

Решение

Что вы сделали в своем редактировании, используя getHydratorConfig было правильно, сообщение об ошибке, которое вы видите, вызвано тем, что в вашем заводском методе вы пытаетесь получить службу изображений из диспетчера подключаемых модулей гидратора.

Решение простое, так как с другими менеджерами плагинов вам нужно позвонить getServiceLocator() на экземпляре диспетчера гидраторов, чтобы получить основной локатор сервиса (он же менеджер сервиса)

Итак, небольшое изменение в вашем заводском методе должно решить проблему …

public function getHydratorConfig() {
return array(
'factories' => array(
// V2
'MyNamespace\\Hydrator\\ProjectHydrator' => function(ServiceManager $serviceManager) {
$projectHydrator = new ProjectHydrator();
// get the image service from the main service locator
$imageService = $serviceManager->getServiceLocator()->get('Portfolio\V2\Rest\ImageService');
$projectHydrator->setImageService($imageService);
return $projectHydrator;
}
),
);
}

Как это работает: экземпляр передается в замыкание в качестве аргумента Zend\Stdlib\Hydrator\HydratorPluginManager, HydratorPluginManager наследует от Zend\ServiceManager\AbstractPluginManagerдитя Zend\ServiceManager\ServiceManager, Но метод ServiceManager#get(...) логически переопределяется в HydratorPluginManager и предоставляет только гидраторы. Тем не менее, родительский класс реализует Zend\ServiceManager\ServiceLocatorAwareInterfaceтак что мы доступ к его внутреннему ServiceLocator и над ServiceLocator на весь набор доступных услуг.

Кроме того, я обычно предпочитаю называть переменную serviceLocator в методе фабрики ($serviceManager в вашем коде), чтобы он отражал фактический менеджер плагинов в использовании, так для фабрики гидратора, $hydratorsдля фабрики форм, $formElemements, и так далее. Я резервирую использование $services обращаться только к главному сервис-менеджеру. Я считаю, что это полезное напоминание о том, что getServiceLocator() Вызов необходим для любых зависимостей, не расположенных в этом конкретном менеджере.

5

Другие решения

Быстрый ответ. замещать HydratorManager с заказным.

В вашем глобальном конфиге:

return array(
'service_manager' => array(
'factories' => (
'HydratorManager' => 'MyNamespace\Hydrator\HydratorManagerFactory',
),
),
);

MyNamespace \ Hydrator \ HydratorManagerFactory.php:

<?php

namespace MyNamespace\Hydrator;

use Zend\Mvc\Service\HydratorManagerFactory as BaseHydratorManagerFactory;

class HydratorManagerFactory extends BaseHydratorManagerFactory
{
const PLUGIN_MANAGER_CLASS = 'MyNamespace\Hydrator\HydratorPluginManager';
}

MyNamespace \ Hydrator \ HydratorPluginManager.php

<?php

namespace MyNamespace\Hydrator;

use Zend\Stdlib\Hydrator\HydratorPluginManager as BaseHydratorPluginManager;

class HydratorPluginManager extends BaseHydratorPluginManager
{
protected $factories = array(
'mynamespacehydratorprojecthydrator' => 'MyNamespace\\Hydrator\\ProjectHydratorFactory',
);
}

Заметка завод получит экземпляр Zend\ServiceManager\AbstractPluginManager, Вы можете получить общий ServiceLocator, вызывающий метод $services->getServiceLocator()

-1

По вопросам рекламы [email protected]