Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Batch requests on Symfony

Tags:

symfony

I am trying to reproduce the behaviour of the facebook batch requests function on their graph api.

So I think that the easiest solution is to make several requests on a controller to my application like:

public function batchAction (Request $request)
{
    $requests = $request->all();
    $responses = [];

    foreach ($requests as $req) {
        $response = $this->get('some_http_client')
            ->request($req['method'],$req['relative_url'],$req['options']);

        $responses[] = [
            'method' => $req['method'],
            'url' => $req['url'],
            'code' => $response->getCode(),
            'headers' => $response->getHeaders(),
            'body' => $response->getContent()
        ]
    }

    return new JsonResponse($responses)
}

So with this solution, I think that my functional tests would be green.

However, I fill like initializing the service container X times might make the application much slower. Because for each request, every bundle is built, the service container is rebuilt each time etc...

Do you see any other solution for my problem?

In other words, do I need to make complete new HTTP requests to my server to get responses from other controllers in my application?

Thank you in advance for your advices!

like image 576
Hammerbot Avatar asked Nov 23 '16 14:11

Hammerbot


1 Answers

Internally Symfony handle a Request with the http_kernel component. So you can simulate a Request for every batch action you want to execute and then pass it to the http_kernel component and then elaborate the result.

Consider this Example controller:

/**
 * @Route("/batchAction", name="batchAction")
 */
public function batchAction()
{
    // Simulate a batch request of existing route
    $requests = [
        [
            'method' => 'GET',
            'relative_url' => '/b',
            'options' => 'a=b&cd',
        ],
        [
            'method' => 'GET',
            'relative_url' => '/c',
            'options' => 'a=b&cd',
        ],
    ];

    $kernel = $this->get('http_kernel');

    $responses = [];
    foreach($requests as $aRequest){

        // Construct a query params. Is only an example i don't know your input
        $options=[];
        parse_str($aRequest['options'], $options);

        // Construct a new request object for each batch request
        $req = Request::create(
            $aRequest['relative_url'],
            $aRequest['method'],
            $options
        );
        // process the request
        // TODO handle exception
        $response = $kernel->handle($req);

        $responses[] = [
            'method' => $aRequest['method'],
            'url' => $aRequest['relative_url'],
            'code' => $response->getStatusCode(),
            'headers' => $response->headers,
            'body' => $response->getContent()
        ];
    }
    return new JsonResponse($responses);
}

With the following controller method:

/**
 * @Route("/a", name="route_a_")
 */
public function aAction(Request $request)
{
    return new Response('A');
}

/**
 * @Route("/b", name="route_b_")
 */
public function bAction(Request $request)
{
    return new Response('B');
}

/**
 * @Route("/c", name="route_c_")
 */
public function cAction(Request $request)
{
    return new Response('C');
}

The output of the request will be:

[
{"method":"GET","url":"\/b","code":200,"headers":{},"body":"B"},
{"method":"GET","url":"\/c","code":200,"headers":{},"body":"C"}
]

PS: I hope that I have correctly understand what you need.

like image 53
Matteo Avatar answered Sep 21 '22 23:09

Matteo