Using same class for multiple resources in zend expressive Hal

I am using Zend Expressive Hal to generate a Hal Response. The problem is that when I use the same resource_class for 2 routes in Hal metadata, it throws an exception and does not work. I was wondering if there is a way where I can use the same object for more than one route. Here is my Hal metadata code:

return [
     MetadataMap::class => [
        [
            '__class__' => RouteBasedResourceMetadata::class,
            'resource_class' => ImmutablePropertyObject::class,
            'route' => 'api.ping',
            'extractor' => ArraySerializableHydrator::class,
        ],
         [
             '__class__' => RouteBasedResourceMetadata::class,
             'resource_class' => \Abstracts\PropertyObject::class,
             'route' => 'api.getEventById',
             'extractor' => \Event\EventHydrator::class,
         ],
         [
             '__class__' => RouteBasedResourceMetadata::class,
             'resource_class' => \Abstracts\PropertyObject::class,
             'route' => 'api.postEvent',
             'extractor' => \Event\EventHydrator::class,
         ]
    ]
];

Here are my routes:

return function (Application $app, MiddlewareFactory $factory, ContainerInterface $container) : void {
    $app->get('/', App\Handler\HomePageHandler::class, 'home');
    $app->get('/api/ping', App\Handler\PingHandler::class, 'api.ping');
    $app->get('/api/event/:id', Event\Handler\EventReadHandler::class, 'api.getEventById');
    $app->post('/api/event', Event\Handler\EventPostHandler::class, 'api.postEvent');
    $app->put('/api/event', Event\Handler\EventUpdateHandler::class, 'api.updateEvent');

};

This is by design. Why? Because a given resource should have only one associated endpoint. It can be embedded in other resources, but it should only have one canonical URL associated.

In your example above, you don’t need to define a resource for the api.postEvent route; when that route is called, you will be creating a PropertyObject, and the representation will use the resource for the api.getEventById route, which will generate the canonical URL for the resource.

If you absolutely need a different URL to be used, extend the original class and map that extension class. However, based on what you have above, I’d remove the resource associated with the api.postEvent as it’s redundant.

1 Like