Using PHP8 attributes with Symfony Value Resolvers

Version 8 of PHP was released just over 2 months ago, and among the most important changes there is the introduction of attributes, which will allow you to create with native syntax what has been achieved up to now with PHPDoc and Doctrine annotations.

The Symfony framework makes extensive use of them, for example to specify routing directly in controllers and validation rules in entities. Version 5.2 already supports PHP8 attributes in both cases.

Value Resolvers

  • services registered in the application container
  • session object or logged in user
  • request or a single request attribute

exploiting the metadata of the arguments themselves, including the type and name, but also the PHP8 attribute, if specified.

You can implement your own Value Resolver writing a class that implements the ArgumentValueResolverInterface interface and, if necessary, declaring it as a service to specify a priority, since multiple Value Resolvers can support the resolution of the same argument, and in that case the order of evaluation matters.

The ArgumentValueResolverInterface interface consists of two methods, supports and resolve, the first checks if a Value Resolver is able to handle an argument, the second performs the resolution. Both methods receive the HTTP request and an object containing the argument metadata.

Translate the request into a DTO

But it does not always include all the information needed to process the request, for example the URI could contain the id of the resource to be modified.

Value Resolvers and PHP8 attributes

and use it within our controller, in the arguments of an action:

while the implementation of the resolve method of our Value Resolver takes advantage of the fact that among the metadata of the argument it is also possible to retrieve the PHP8 attribute, if defined:

A slightly more complex use case is the one that involves the translation of our data into a doctrine object. Using reflections it is possible to know the type of the object in the DTO and use the corresponding repository to obtain the object by making a call to the findOneBy method, always using the information present in the invoked URI.