2

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?

3
  • And the array would then go to the listener? Commented Sep 1, 2017 at 18:54
  • yes, and the listener will define which response type(JsonResponse, Response) to use Commented Sep 1, 2017 at 20:16
  • Okay. Store your data in the request object with: $request->attributes->set('data',[whatever]); and then just return null from the controller. Have your view listener pull the data from the request. Commented Sep 1, 2017 at 20:27

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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 }

Comments

0

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

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

4 Comments

I don't want to add the response on controller, but outside in the Listener.
Why would you need a listener to create a json response? Also can you share your listener code if you have any? I'm not quite sure about what you want to do.
I need to create the response outside of the controller for making the development of a new controller more agile. In my idea, i send the response type in an annotation and return just the needed data in the function. Instead of public function home(Request $request) { $response = new Response(['asdf' => 123]); $response->headers->set('Content-Type', 'application/json');} will be /** * @ResponseType("JSON") */ public function home(Request $request) { return ['asdf' => 123]; }
Documentation says : "The JsonResponse class sets the Content-Type header to application/json and encodes your data to JSON when needed." You don't even need to set the header content type yourself if you use a JsonResponse. And if by "agile" you mean simple or flexible I think using a JsonResponse is the best way for that. You don't even need to add an annotation or use a listener.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.