3

在 Apigility 驱动的 ZF2 应用程序中,我想使用自定义的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',
        ),
        ...
    ),
),
...

当一个集合被检索到时,它会被忽略,但这是另一个问题(s. here)。当需要单个实体时,hydratin 机制启动,但它不使用我的工厂来创建实例。

经过一些调试后,我来到了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(of type Zend\Stdlib\Hydrator\HydratorPluginManager),发现只有四个 default invocables,这就是为什么null !== $this->hydrators && $this->hydrators->has($hydrator)isfalse并尝试了直接实例化。

所以,我想,我必须注册我的定制保湿剂。我在哪里/如何做到这一点?


编辑

我将工厂代码从移动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

4

2 回答 2

5

您在编辑中所做的使用getHydratorConfig是正确的,您看到的错误消息是因为在您的工厂方法中您试图从 hydrator 插件管理器中获取您的图像服务。

解决方案很简单,与其他插件管理器一样,您需要调用getServiceLocator()hydrator 管理器实例以获取主服务定位器(也称为服务管理器)

所以,对你的工厂方法做一个小改动应该可以解决这个问题......

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整个可用服务集。

顺便说一句,我通常更喜欢在工厂方法($serviceManager在您的代码中)中命名 serviceLocator 变量,以便它反映实际使用的插件管理器,因此对于水合器工厂,$hydrators对于表单工厂,$formElemements等等。我保留使用 of$services仅指主要服务管理器。我发现这样做是一个有用的提醒,即getServiceLocator()对于不在该特定管理器中的任何依赖项都需要调用。

于 2015-03-12T17:48:05.487 回答
-1

快速响应。替换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()

于 2015-03-12T17:31:43.883 回答