public function testVerifyRequestStackPushPopDuringHandle()
 {
     $request = new Request();
     $stack = $this->getMock('Symfony\\Component\\HttpFoundation\\RequestStack', array('push', 'pop'));
     $stack->expects($this->at(0))->method('push')->with($this->equalTo($request));
     $stack->expects($this->at(1))->method('pop');
     $dispatcher = new EventDispatcher();
     $kernel = new AsyncHttpKernel($dispatcher, $this->getResolver(), $stack);
     $kernel->handle($request, HttpKernelInterface::MASTER_REQUEST);
 }
Beispiel #2
0
 public function onKernelController(FilterControllerEvent $event)
 {
     if (!$event->isMasterRequest()) {
         return;
     }
     $request = $event->getRequest();
     if (!$request->attributes->has('_api')) {
         return;
     }
     /** @var Api $api */
     $api = $request->attributes->get('_api');
     $subRequests = $this->getSubRequests($request);
     $bulk = $api->isBulkable() && $subRequests;
     $stream = ($api->isStreamable() || $bulk) && $this->shouldStream($request);
     if (!$bulk && !$stream) {
         $request->attributes->set('stream', $this->noop);
         return;
     }
     // This listener will unwind/spread the calls, so don't trigger other Api listeners.
     $request->attributes->remove('_api');
     if ($stream) {
         $headers = ['content-type' => 'application/json; boundary=NL', 'x-accel-buffering' => 'no'];
     } else {
         $headers = ['content-type' => 'application/json'];
     }
     if ($subRequests) {
         $event->setController(function () use($request, $headers, $subRequests, $stream) {
             return new StreamedResponse(function () use($request, $subRequests, $stream) {
                 $promises = [];
                 foreach ($subRequests as $i => $requestParams) {
                     // Forward the query string without the 'payload', and put all the parameters in the body.
                     $query = $request->query->all();
                     if (isset($query['payload'])) {
                         unset($query['payload']);
                     }
                     $subRequest = $request->duplicate([], $requestParams);
                     // Also force-make it a POST request, so it can contain a body.
                     $subRequest->setMethod('POST');
                     $subRequest->attributes->set('stream', $stream ? $this->createStreamer($i) : $this->noop);
                     /* @var PromiseInterface $promise */
                     $promises[] = $promise = $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true, false);
                     if ($stream) {
                         $streamer = $this->createStreamer($i);
                         $promise->then(function (Response $response) use($streamer) {
                             $streamer($response->getContent(), true);
                         });
                     }
                 }
                 $responses = \GuzzleHttp\Promise\all($promises)->wait();
                 if (!$stream) {
                     echo '[';
                     for (reset($responses); $response = current($responses); next($responses)) {
                         echo $response->getContent();
                         if (current($responses)) {
                             echo ',';
                         }
                     }
                     echo ']';
                 }
             }, 200, $headers);
         });
     } else {
         $event->setController(function () use($request, $headers) {
             return new StreamedResponse(function () use($request) {
                 $request->attributes->set('stream', $this->createStreamer());
                 // We duplicate the request because the profiler component's token keeps a reference to the parent request's token,
                 // creating an infinite loop when attempting to display profiler info.
                 $response = $this->httpKernel->handle($request->duplicate(), HttpKernelInterface::SUB_REQUEST, true, true);
                 // The streamer outputs a new line as the ending delimiter. In single action calls, the ending line should be
                 // the actual response without a new line at the end. That's why streaming single calls have a resulting
                 // response, but bulk calls don't have one.
                 echo $response->getContent();
             }, 200, $headers);
         });
     }
 }