The hydrator settings are ignored in Apigility

2019-04-11 14:29发布

问题:

In Apigility it's possible to set a Hydrator for every Entity -- either over the Apigility UI

or directly in the module.config.php, e.g.:

return array(
    ...
    '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\\ObjectProperty',
                // 'hydrator' => 'MyNamespace\\Hydrator\\ProjectHydrator',
            ),
            ...
        ),
        ...
    ),
    ...
);

See also the documentation.

Currently I'm using the ClassMethods hydrator for all my entities.

Now I tried to change the setting to a custom hydrator. I've also tried another Zend hydrator. But whatever I do, only the hydrated I have defined in the `module.config.php is ignored.

EDIT: It works for sigle entities, but not for collections. I've checked this with the debugger and see: when I retieve a collection, my custom hydrator doesn't get called. I cannot find out, which hydrator is actually being used -- I set breakpoints and even wrote die()s in the extract() and hydrate() methods of all hydrators (ArraySerializable, ClassMethods, ObjectProperty, Reflection, and also in my custom ProjectHydrator), but the application didn't notice that at all and is still working. Seems so, that no hydration is made at all...

What is wrong here and how to get hydration settings working correctly?

回答1:

When you defined the Entity class for your service, you also have the option to configure the Collection entity for your service. You need to to associate your hydrator to the Collection entity in your metadata.

return [
    'zf-rest' => [
        'Portfolio\\V2\\Rest\\Project\\Controller' => [
            // other config
            'entity_class' => 'Portfolio\\V2\\Rest\\Project\\ProjectEntity',
            'collection_class' => 'Portfolio\\V2\\Rest\\Project\\ProjectCollection',
        ]
    ],
    'zf-hal' => [
        'metadata_map' => [
            'Portfolio\\V2\\Rest\\Project\\ProjectEntity' => [
                // other config
                'hydrator' => 'MyNamespace\\Hydrator\\ProjectHydrator'
            ],
            'Portfolio\\V2\\Rest\\Project\\ProjectCollection' => [
                // other config
                'hydrator' => 'MyNamespace\\Hydrator\\ProjectCollectionHydrator'
            ]
        ]
    ]
]


回答2:

Old but found this: For collectionRender the hydrator is not called https://github.com/zfcampus/zf-hal/blob/master/src/Plugin/Hal.php#L570

For entityRender is: https://github.com/zfcampus/zf-hal/blob/master/src/Plugin/Hal.php#L695

Need to call issue for that.

Edit[07.10.16]:

I was wrong with that.

My solution works with Apigility 1.3. Didn't test earlier versions.

You can use Zend\\Hydrator\\DelegatingHydrator

        'metadata_map' => array(
        'Test\\DomainModel\\UseCase\\Query\\ShowTask\\Response\\Task' => array(
            'entity_identifier_name' => 'uuid',
            'route_name' => 'descriptive-module.rest.task',
            'route_identifier_name' => 'task_id',
            'hydrator' => 'Zend\\Hydrator\\DelegatingHydrator',
        ),
        'Test\\DomainModel\\UseCase\\Query\\ListTask\\Response\\Task' => array(
            'entity_identifier_name' => 'uuid',
            'route_name' => 'descriptive-module.rest.task',
            'route_identifier_name' => 'task_id',
            'hydrator' => 'Zend\\Hydrator\\DelegatingHydrator',
        ),

First one, for entity. Second one, elements of returned Collection.

Then in module.config.php

   'hydrators' => array(
    'invokables' => array(
        \Test\DomainModel\UseCase\Query\ShowTask\Response\Task::class =>
            \TestApi\V1\Rest\Task\Hydrator\ShowTaskHydrator::class,
        \Test\DomainModel\UseCase\Query\ListTask\Response\Task::class =>
            \TestApi\V1\Rest\Task\Hydrator\ListTaskHydrator::class,
    ),
    'factories' => array(),
),

TaskShowHydrator/ListTaskHydrator need implement Zend\Hydrator\HydratorInterface