Eduardo Ugolini
Eduardo Ugolini

Reputation: 23

Symfony Controller return array

I am trying to create a listener that configures the Response using annotations and sets the response content as the controller return.

The Controller code:

use PmtVct\PhotoBookBundle\Annotations\ResponseType;
use Symfony\Component\HttpFoundation\Request;

/**
* @ResponseType("JSON")
*/
public function home(Request $request) {
    return ['asdf' => 123];
}

But I receive the 'The controller must return a response' error.

There is a way to return an array on Controller instead a Response?

Upvotes: 2

Views: 3511

Answers (3)

vodevel
vodevel

Reputation: 506

Explain https://stackoverflow.com/a/46007749/21333278:

Controller:

class YourController extends AbstractController
{
    #[Route('your/route', methods: ['GET'])]
    public function __invoke(): YourRouteResponseDTO
    {
        return new YourRouteResponseDTO();
    }
}

Instead of YourRouteResponseDTO class, you can use an array, but the more typing, the better.

class YourRouteResponseDTO implements ResponseJsonInterface
{
    public int $param1;
    public YourAnotherResponseDTO $param2;
}

And listener


namespace App\Listener;

use App\Contract\ResponseJsonInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\Serializer\SerializerInterface;

class ResponseListener
{
    public function __construct(
        private readonly SerializerInterface $serializer,
    ) {
    }

    public function __invoke(ViewEvent $event): void
    {
        $response = $event->getControllerResult();
        if (!($response instanceof ResponseJsonInterface)) {
            return;
        }
        $jsonResponse = $this->json($response);

        $event->setResponse($jsonResponse);
    }

    protected function json(mixed $data, int $status = 200, array $headers = [], array $context = []): JsonResponse
    {
        $json = $this->serializer->serialize($data, 'json', array_merge([
            'json_encode_options' => JsonResponse::DEFAULT_ENCODING_OPTIONS
                | JSON_UNESCAPED_UNICODE
                | JSON_UNESCAPED_SLASHES
                | JSON_PRETTY_PRINT,
        ], $context));

        return new JsonResponse($json, $status, $headers, true);
    }
}
#services.yaml
services
    App\Listener\ResponseListener:
        tags:
            - { name: kernel.event_listener, event: kernel.view, priority: 10 }

Upvotes: 1

Maksym  Moskvychev
Maksym Moskvychev

Reputation: 1674

You are trying to do a similar thing to FOSRestBundle. Maybe consider using this bundle? It will allow:

  • Return arrays in controller, exactly in a way you want
  • Serialise response into Json, or other format you wish, also it can detect format automatically from Request.

In case you still want to build such listener yourself - look how it's done in FOSRestBundle - https://github.com/FriendsOfSymfony/FOSRestBundle/blob/master/EventListener/ViewResponseListener.php - they are using "kernel.view" event.

Upvotes: 2

A. Atallah
A. Atallah

Reputation: 35

According to the documentation you can return a JsonResponse like this:

return new JsonResponse(['asdf' => 123]);

Upvotes: 0

Related Questions