Home / Symfony / New in Symfony 7.4: Attribute Improvements

New in Symfony 7.4: Attribute Improvements

PHP attributes let you define structured metadata directly in your code, right
next to the classes, methods, or properties they configure. Although using them
in Symfony is optional, they greatly improve developer experience and productivity.
That’s why every new Symfony version adds new attributes and improves the existing ones.

Union Types in #[CurrentUser]


Vincent Langlet
Contributed by
Vincent Langlet
in
#61204

The #[CurrentUser] attribute can be used in controller arguments to get the
currently authenticated user. In Symfony 7.4, we’ve improved it so you can use
a union type, allowing your controller to handle multiple possible user types:

use AppEntityAdminUser;
use AppEntityCustomer;
use SymfonyComponentSecurityHttpAttributeCurrentUser;

class ApiLoginController extends AbstractController
{
    #[Route('/api/login', name: 'api_login', methods: ['POST'])]
    public function index(#[CurrentUser] AdminUser|Customer $user): Response
    {
        // ...
    }
}

Multiple Environments in #[Route]


Santiago San Martin
Contributed by
Santiago San Martin
in
#61358

The #[Route] attribute lets you define routes directly in controller methods
instead of separate configuration files. The env option restricts a route
to certain configuration environments.

In Symfony 7.4, this option now supports multiple environments:

#[Route('/_debug/mail-preview', name: 'debug_mail_preview', env: ['dev', 'test'])]
public function previewEmail(MailerInterface $mailer): Response
{
    // ...
}

#[Route('/healthcheck', name: 'healthcheck', env: ['staging', 'prod'])]
public function healthCheck(): JsonResponse
{
    // ...
}

Repeatable #[AsDecorator]


Hubert Lenoir
Contributed by
Hubert Lenoir
in
#61575

The #[AsDecorator] attribute helps configure how a service decorates another
service using the decorator pattern. In Symfony 7.4, this attribute is now
repeatable, allowing a single class/service to decorate multiple others:

// ...
use SymfonyComponentDependencyInjectionAttributeAsDecorator;

#[AsDecorator('api1.client')]
#[AsDecorator('api2.client')]
#[AsDecorator('api3.client')]
class LoggableService implements HttpClientInterface
{
    public function __construct(
        private HttpClientInterface $client,
        private readonly LoggerInterface $logger,
    ) {
    }

    public function request(string $method, string $url, array $options = []): ResponseInterface
    {
        try {
            $response = $this->client->request($method, $url, $options);

            $this->logger->info('API call: {method} {url}.', ['method'= > $method, 'url' => $url]);

            return $response;
        } catch (Throwable $e) {
            $this->logger->error('API call failed: {method} {url}.', ['method'= > $method, 'url' => $url, 'exception' => $e]);

            throw $exception;
        }
    }
}

Union Types in #[AsEventListener]


Pierre Ambroise
Contributed by
Pierre Ambroise
in
#61252

The #[AsEventListener] attribute configures event listeners directly on their
classes. When the related listener method type-hints the expected event object,
you can omit the event argument in the attribute.

In Symfony 7.4, union types are now supported in these method signatures:

use SymfonyComponentEventDispatcherAttributeAsEventListener;

final class SomeListener
{
    #[AsEventListener]
    public function doSomething(CustomEvent|AnotherCustomEvent $event): void
    {
        // ...
    }
}

#[IsGranted] Methods


Santiago San Martin
Contributed by
Santiago San Martin
in
#61358

The #[IsGranted] attribute performs access control checks before running
certain code, such as controller actions. In Symfony 7.4, it now supports a
new methods option to restrict checks to specific HTTP methods.

If the current request method matches one of the configured methods, the access
check runs; otherwise, the attribute is ignored:

#[IsGranted('ROLE_ADMIN', methods: ['GET', 'POST'])]
public function someAction()
{
    // ...
}

#[IsGranted('ROLE_ADMIN', methods: 'POST')]
public function otherAction()
{
    // ...
}

Route Attribute Auto Registration


Nicolas Grekas
Contributed by
Nicolas Grekas
in
#61492

Symfony applications use by default this route configuration to load all the
#[Route] attributes (type: attribute) from your default controller
directory (path: ../src/Controller/):

# config/routes.yaml
controllers:
    resource:
        path: ../src/Controller/
        namespace: AppController
    type: attribute

In Symfony 7.4, we’re improving this feature so you can now use #[Route]
attributes in any directory of your application. It works like this:

  • Symfony applies a service tag called routing.controller to any class that
    uses the #[Route] attribute.
  • A compiler pass collects those tagged services and automatically registers
    their routes.

With this, your config/routes.yaml file can be simplified to:

controllers:
    resource: routing.controllers

When using the default Symfony recipes, this configuration becomes optional,
so the config/routes.yaml file will be empty by default.

New #[IsSignatureValid] Attribute


Santiago San Martin
Contributed by
Santiago San Martin
in
#61358

Symfony provides utilities to sign and verify URIs in services and controllers.
In Symfony 7.4, a new #[IsSignatureValid] attribute simplifies this feature
by performing signature validation automatically:

// ...
use AppSecurityAttributeIsSignatureValid;

class SomeController extends AbstractController
{
    #[IsSignatureValid]
    public function someAction(): Response
    {
        // ...
    }

    // you can also check signatures for specific HTTP methods
    #[IsSignatureValid(methods: ['POST', 'PUT'])]
    public function updateItem(): Response
    {
        // ...
    }
}

You can also apply this attribute at the class level to validate signatures
across all controller methods.


Sponsor the Symfony project.
Tagged:

Leave a Reply

Your email address will not be published. Required fields are marked *