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

Code before:
    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 (security):
let's not call getMimeType is the header is already set in the attribute? also, the current logic is case-sensitive, this can give weird results


Code after:
 */
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);
    }

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

    /**
     * @return array<string, scalar>
     */
    private function mergeHeaders(Serialize $attribute, Request $request, string $format): array
    {
        $headers = array_combine(