1

I want to use two parameters within a fast route in zend expressive / laminas mezzio.

routes.php

$app->get('/api/users/{userId:\d+}/pages/[{id:\d+}]', [App\Page\PageHandler::class], 'api.pages');

ConfigProvider.php

 [
        '__class__' => RouteBasedResourceMetadata::class,
        'resource_class' => Page\PageEntity::class,
        'route' => 'api.page',
        'extractor' => ObjectPropertyHydrator::class,
  ],
  [
         '__class__' => RouteBasedCollectionMetadata::class,
         'collection_class' => Page\PageCollection::class,
         'collection_relation' => 'pages',
         'route' => 'api.pages',
  ],

This error occurs:

Route `api.page` expects at least parameter values for [userId,id], but received [id]

There is a problem with the mapping...

How can I add a second paramtere in de Metadata Mapping? I thought there would be an auto-mapping...

Daniel
  • 11
  • 1

1 Answers1

0

I guess the path configuration in the routes.php is faulty. Try this:

$app->get('/api/pages/{id:\d+}/users/{userId:\d+}', App\Page\PageHandler::class, 'api.pages');

In the handle function you can easily access userId and id via getAttributes function of the $request object:

public function handle(ServerRequestInterface $request) : ResponseInterface
{
    $userId = (int)$request->getAttribute('userId');
    $id = (int)$request->getAttribute('id');
}

The configuration in the ConfigProvider is not necessary for this.

If you want that getAttribute returns directly the corresponding entity objects and not the IDs, I would recommend you to use a middleware for it, which uses userId and id in order to loads the desired objects from the database or any other data source.

The following example uses Doctrine:

<?php
namespace App\Middleware;

class GetEntitiesFromQueryParamsMiddleware implements MiddlewareInterface
{
    private $entityManager;
    
    public function __construct(EntityManagerInterface $entityManager
    {
        $this->entityManager = $entityManager;
    }
    
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $pageId = (int)$request->getAttribute('id');
        $page = $this->entityManager
                ->getRepository(PageEntity::class)
                ->find($pageId);
        $userId = (int)$request->getAttribute('userId');
        $user = $this->entityManager
                ->getRepository(User::class)
                ->find($id);
        return $handler->handle($request
                ->withAttribute(PageEntity::class, $page)
                ->withAttribute(User::class, $user));
    }
}

Create a Factory for the middleware and register it in the ConfigProvider. Also register this middleware in pipeline.php after RouteMiddleware:

...
$app->pipe(RouteMiddleware::class);
$app->pipe('/api/pages', GetEntitiesFromQueryParamsMiddleware::class);
...

Now you can access the objects in the handler method:

class PageHandler 
{

    public function handle(ServerRequestInterface $request) : ResponseInterface
    {
        $page = $request->getAttribute(PageEntity::class);
        $user = $request->getAttribute(User::class);
    }
}
seboettg
  • 195
  • 8