Browse Source

Merge pull request #17545 from cakephp/terminate-event

Simplify the terminate event
othercorey 2 years ago
parent
commit
f6cbbb4526
2 changed files with 32 additions and 22 deletions
  1. 19 16
      src/Http/Server.php
  2. 13 6
      tests/TestCase/Http/ServerTest.php

+ 19 - 16
src/Http/Server.php

@@ -23,6 +23,7 @@ use Cake\Event\EventDispatcherInterface;
 use Cake\Event\EventDispatcherTrait;
 use Cake\Event\EventManager;
 use Cake\Event\EventManagerInterface;
+use Cake\Routing\Router;
 use InvalidArgumentException;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
@@ -128,6 +129,14 @@ class Server implements EventDispatcherInterface
     /**
      * Emit the response using the PHP SAPI.
      *
+     * After the response has been emitted, the `Server.terminate` event will be triggered.
+     *
+     * The `Server.terminate` event can be used to do potentially heavy tasks after the
+     * response is sent to the client. Only the PHP FPM server API is able to send a
+     * response to the client while the server's PHP process still performs some tasks.
+     * For other environments the event will be triggered before the response is flushed
+     * to the client and will have no benefit.
+     *
      * @param \Psr\Http\Message\ResponseInterface $response The response to emit
      * @param \Cake\Http\ResponseEmitter|null $emitter The emitter to use.
      *   When null, a SAPI Stream Emitter will be used.
@@ -137,23 +146,17 @@ class Server implements EventDispatcherInterface
     {
         $emitter ??= new ResponseEmitter();
         $emitter->emit($response);
-    }
 
-    /**
-     * Trigger the Server.terminate event.
-     *
-     * The event is used to do potentially heavy tasks after the response is sent
-     * to the client. Only the PHP FPM server API is able to send a response to
-     * the client while the server's PHP process still performs some tasks. For
-     * other environments the event will be triggered before the response is flushed
-     * to the client and will have no benefit.
-     *
-     * @param \Psr\Http\Message\ServerRequestInterface $request Request instance.
-     * @param \Psr\Http\Message\ResponseInterface $response Response instance.
-     * @return void
-     */
-    public function terminate(ServerRequestInterface $request, ResponseInterface $response): void
-    {
+        $request = null;
+        if ($this->app instanceof ContainerApplicationInterface) {
+            $container = $this->app->getContainer();
+            if ($container->has(ServerRequest::class)) {
+                $request = $container->get(ServerRequest::class);
+            }
+        }
+        if (!$request) {
+            $request = Router::getRequest();
+        }
         $this->dispatchEvent('Server.terminate', compact('request', 'response'));
     }
 

+ 13 - 6
tests/TestCase/Http/ServerTest.php

@@ -33,7 +33,6 @@ use Laminas\Diactoros\Response as LaminasResponse;
 use Laminas\Diactoros\ServerRequest as LaminasServerRequest;
 use Mockery;
 use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
 use TestApp\Http\MiddlewareApplication;
 
 require_once __DIR__ . '/server_mocks.php';
@@ -356,21 +355,29 @@ class ServerTest extends TestCase
         $this->assertInstanceOf(ResponseInterface::class, $server->run($request));
     }
 
-    public function testTerminate(): void
+    public function testTerminateEvent(): void
     {
-        /** @var \Cake\Core\HttpApplicationInterface|\PHPUnit\Framework\MockObject\MockObject $app */
-        $app = $this->createMock(HttpApplicationInterface::class);
+        $request = new ServerRequest();
+        $app = new MiddlewareApplication($this->config);
+        $app->getContainer()->add(ServerRequest::class, $request);
         $server = new Server($app);
 
         $triggered = false;
         $server->getEventManager()->on(
             'Server.terminate',
-            function (EventInterface $event, ServerRequestInterface $request, ResponseInterface $response) use (&$triggered) {
+            function ($event, $request, $response) use (&$triggered) {
                 $triggered = true;
+                $this->assertInstanceOf(ServerRequest::class, $request);
+                $this->assertInstanceOf(Response::class, $response);
             }
         );
 
-        $server->terminate(new ServerRequest(), new Response());
+        $emitter = $this->getMockBuilder(ResponseEmitter::class)->getMock();
+        $emitter->expects($this->once())
+            ->method('emit')
+            ->willReturn(true);
+
+        $server->emit(new Response(), $emitter);
 
         $this->assertTrue($triggered);
     }