Browse Source

Integrate plugin hooks in http & routing

Use the new hooks in the correct places to allow plugin routes,
bootstrap to be loaded after the application's configuration. This
allows plugins to define routes and configuration based on what the
application is doing/has set up.
Mark Story 8 years ago
parent
commit
e5322b050f

+ 3 - 8
src/Http/BaseApplication.php

@@ -53,9 +53,8 @@ abstract class BaseApplication implements
      * Constructor
      *
      * @param string $configDir The directory the bootstrap configuration is held in.
-     * @param string|null $pluginRegistry Plugin Registry Object
      */
-    public function __construct($configDir, $pluginRegistry = null)
+    public function __construct($configDir)
     {
         $this->configDir = $configDir;
         $this->plugins = new PluginCollection();
@@ -92,8 +91,6 @@ abstract class BaseApplication implements
     public function bootstrap()
     {
         require_once $this->configDir . '/bootstrap.php';
-
-        $this->pluginRegistry()->bootstrap();
     }
 
     /**
@@ -129,7 +126,7 @@ abstract class BaseApplication implements
     public function pluginRoutes($routes)
     {
         foreach ($this->plugins->with('routes') as $plugin) {
-            $routes = $plugin->routes($routes);
+            $plugin->routes($routes);
         }
 
         return $routes;
@@ -146,9 +143,7 @@ abstract class BaseApplication implements
      */
     public function console($commands)
     {
-        $commands->addMany($commands->autoDiscover());
-
-        return $this->pluginRegistry()->console($commands);
+        return $commands->addMany($commands->autoDiscover());
     }
 
     /**

+ 9 - 0
src/Http/Server.php

@@ -15,6 +15,7 @@
 namespace Cake\Http;
 
 use Cake\Core\HttpApplicationInterface;
+use Cake\Core\PluginApplicationInterface;
 use Cake\Event\EventDispatcherTrait;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
@@ -69,11 +70,19 @@ class Server
     public function run(ServerRequestInterface $request = null, ResponseInterface $response = null)
     {
         $this->app->bootstrap();
+        $hasPlugins = $this->app instanceof PluginApplicationInterface;
+        if ($hasPlugins) {
+            $this->app->pluginBootstrap();
+        }
 
         $response = $response ?: new Response();
         $request = $request ?: ServerRequestFactory::fromGlobals();
 
         $middleware = $this->app->middleware(new MiddlewareQueue());
+        if ($hasPlugins) {
+            $middleware = $this->app->pluginMiddleware($middleware);
+        }
+
         if (!($middleware instanceof MiddlewareQueue)) {
             throw new RuntimeException('The application `middleware` method did not return a middleware queue.');
         }

+ 8 - 3
src/Routing/Middleware/RoutingMiddleware.php

@@ -14,6 +14,7 @@
  */
 namespace Cake\Routing\Middleware;
 
+use Cake\Core\PluginApplicationInterface;
 use Cake\Http\BaseApplication;
 use Cake\Http\MiddlewareQueue;
 use Cake\Http\Runner;
@@ -56,9 +57,13 @@ class RoutingMiddleware
      */
     protected function loadRoutes()
     {
-        if ($this->app) {
-            $builder = Router::createRouteBuilder('/');
-            $this->app->routes($builder);
+        if (!$this->app) {
+            return;
+        }
+        $builder = Router::createRouteBuilder('/');
+        $this->app->routes($builder);
+        if ($this->app instanceof PluginApplicationInterface) {
+            $this->app->pluginRoutes($builder);
         }
     }
 

+ 39 - 0
tests/TestCase/Http/ServerTest.php

@@ -16,6 +16,7 @@ namespace Cake\Test\TestCase;
 
 use Cake\Event\Event;
 use Cake\Http\CallbackStream;
+use Cake\Http\MiddlewareQueue;
 use Cake\Http\Server;
 use Cake\TestSuite\TestCase;
 use TestApp\Http\BadResponseApplication;
@@ -98,6 +99,44 @@ class ServerTest extends TestCase
     }
 
     /**
+     * test run calling plugin hooks
+     *
+     * @return void
+     */
+    public function testRunCallingPluginHooks()
+    {
+        $response = new Response('php://memory', 200, ['X-testing' => 'source header']);
+        $request = ServerRequestFactory::fromGlobals();
+        $request = $request->withHeader('X-pass', 'request header');
+
+        $app = $this->getMockBuilder(MiddlewareApplication::class)
+            ->setMethods(['pluginBootstrap', 'pluginMiddleware'])
+            ->setConstructorArgs([$this->config])
+            ->getMock();
+        $app->expects($this->once())
+            ->method('pluginBootstrap');
+        $app->expects($this->once())
+            ->method('pluginMiddleware')
+            ->with($this->isInstanceOf(MiddlewareQueue::class))
+            ->will($this->returnCallback(function ($middleware) {
+                return $middleware;
+            }));
+
+        $server = new Server($app);
+        $res = $server->run($request, $response);
+        $this->assertEquals(
+            'source header',
+            $res->getHeaderLine('X-testing'),
+            'Input response is carried through out middleware'
+        );
+        $this->assertEquals(
+            'request header',
+            $res->getHeaderLine('X-pass'),
+            'Request is used in middleware'
+        );
+    }
+
+    /**
      * test run building a request from globals.
      *
      * @return void

+ 27 - 0
tests/TestCase/Routing/Middleware/RoutingMiddlewareTest.php

@@ -15,6 +15,7 @@
 namespace Cake\Test\TestCase\Routing\Middleware;
 
 use Cake\Routing\Middleware\RoutingMiddleware;
+use Cake\Routing\RouteBuilder;
 use Cake\Routing\Router;
 use Cake\TestSuite\TestCase;
 use TestApp\Application;
@@ -166,6 +167,32 @@ class RoutingMiddlewareTest extends TestCase
     }
 
     /**
+     * Test that pluginRoutes hook is called
+     *
+     * @return void
+     */
+    public function testRoutesHookCallsPluginHook()
+    {
+        Router::reload();
+        $this->assertFalse(Router::$initialized, 'Router precondition failed');
+
+        $request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/app/articles']);
+        $response = new Response();
+        $next = function ($req, $res) {
+            return $res;
+        };
+        $app = $this->getMockBuilder(Application::class)
+            ->setMethods(['pluginRoutes'])
+            ->setConstructorArgs([CONFIG])
+            ->getMock();
+        $app->expects($this->once())
+            ->method('pluginRoutes')
+            ->with($this->isInstanceOf(RouteBuilder::class));
+        $middleware = new RoutingMiddleware($app);
+        $middleware($request, $response, $next);
+    }
+
+    /**
      * Test that routing is not applied if a controller exists already
      *
      * @return void