Repository: symfony/symfony
File: src/Symfony/Component/HttpKernel/EventListener/SerializeControllerResultAttributeListener.php (PHP)

Code before:
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\Serialize;
use Symfony\Component\HttpKernel\Event\ControllerAttributeEvent;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Serializer\SerializerInterface;

/**
 * @author Konstantin Myakshin <molodchick@gmail.com>
 */
final class SerializeControllerResultAttributeListener implements EventSubscriberInterface
{
    public function __construct(private readonly ?SerializerInterface $serializer)
    {
    }

    public function onView(ControllerAttributeEvent $event): void
    {
        $kernelEvent = $event->kernelEvent;

        if (!$kernelEvent instanceof ViewEvent) {
            return;
        }

        /** @var Serialize $attribute */
        $attribute = $event->attribute;

        if (!$this->serializer) {
            throw new \LogicException(\sprintf('The "symfony/serializer" component is required to use the "%s" attribute. Try running "composer require symfony/serializer".', Serialize::class));
        }

        $request = $kernelEvent->getRequest();
        $controllerResult = $kernelEvent->getControllerResult();
        $format = $request->getRequestFormat('json');

        $data = $this->serializer->serialize($controllerResult, $format, $attribute->serializationContext);

        $headers = $attribute->headers + ['Content-Type' => $request->getMimeType($format)];
        $response = new Response($data, $attribute->code, $headers);

        $kernelEvent->setResponse($response);
    }

    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::VIEW.'.'.Serialize::class => 'onView',
        ];
    }
}

Review comment (suggestion):
instead: `@param ControllerAttributeEvent<Serialize> $event` on the method

Code after:
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\Serialize;
use Symfony\Component\HttpKernel\Event\ControllerAttributeEvent;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Serializer\Exception\UnsupportedFormatException;
use Symfony\Component\Serializer\SerializerInterface;

/**
 * @author Konstantin Myakshin <molodchick@gmail.com>
 */
final class SerializeControllerResultAttributeListener implements EventSubscriberInterface
{
    public function __construct(private readonly ?SerializerInterface $serializer)
    {
    }

    /**
     * @param ControllerAttributeEvent<Serialize> $event
     */
    public function onView(ControllerAttributeEvent $event): void
    {
        $kernelEvent = $event->kernelEvent;

        if (!$kernelEvent instanceof ViewEvent) {
            return;
        }

        if (!$this->serializer) {
            throw new \LogicException(\sprintf('The "symfony/serializer" component is required to use the "#[%s]" attribute. Try running "composer require symfony/serializer".', Serialize::class));
        }

        $request = $kernelEvent->getRequest();
        $controllerResult = $kernelEvent->getControllerResult();
        $format = $request->getRequestFormat('json');

        try {
            $data = $this->serializer->serialize($controllerResult, $format, $event->attribute->context);
        } catch (UnsupportedFormatException $exception) {
            throw new UnsupportedMediaTypeHttpException(\sprintf('Unsupported format "%s".', $format), $exception->getPrevious());
        }

        $headers = $this->mergeHeaders($event->attribute, $request, $format);
        $response = new Response($data, $event->attribute->code, $headers);

        $kernelEvent->setResponse($response);
    }