Browse Source

Update MiddlewareQueue to use MiddlewareInterface instances instead of callables.

It's resolver also wraps callables with DoublePassMiddleware decorator for compatibility
with old callable middlewares.
ADmad 7 years ago
parent
commit
60118b8e41

+ 1 - 0
composer.json

@@ -35,6 +35,7 @@
         "cakephp/chronos": "^1.0.1",
         "composer/ca-bundle": "^1.0",
         "psr/http-client": "^1.0",
+        "psr/http-server-middleware": "^1.0",
         "psr/log": "^1.0.0",
         "psr/simple-cache": "^1.0.0",
         "zendframework/zend-diactoros": "^2.0",

+ 39 - 0
src/Http/Middleware/CallableMiddleware.php

@@ -0,0 +1,39 @@
+<?php
+declare(strict_types=1);
+/**
+ * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+ * @link          https://cakephp.org CakePHP(tm) Project
+ * @since         4.0.0
+ * @license       https://opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\Http\Middleware;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+
+class CallableMiddleware implements MiddlewareInterface
+{
+    protected $callable;
+
+    public function __construct(callable $callable)
+    {
+        $this->callable = $callable;
+    }
+
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
+    {
+        return $response = ($this->callable)(
+            $request,
+            $handler
+        );
+    }
+}

+ 52 - 0
src/Http/Middleware/DoublePassMiddleware.php

@@ -0,0 +1,52 @@
+<?php
+declare(strict_types=1);
+/**
+ * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+ * @link          https://cakephp.org CakePHP(tm) Project
+ * @since         4.0.0
+ * @license       https://opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\Http\Middleware;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+
+class DoublePassMiddleware implements MiddlewareInterface
+{
+    protected $callable;
+
+    public function __construct(callable $callable)
+    {
+        $this->callable = $callable;
+    }
+
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
+    {
+        return $response = ($this->callable)(
+            $request,
+            $this->responsePrototype,
+            $this->decorateHandler($handler)
+        );
+    }
+
+    public function getCallable(): callable
+    {
+        return $this->callable;
+    }
+
+    protected function decorateHandler(RequestHandlerInterface $handler): callable
+    {
+        return function ($request, $response) use ($handler) {
+            return $handler->handle($request);
+        };
+    }
+}

+ 16 - 10
src/Http/MiddlewareQueue.php

@@ -16,8 +16,10 @@ declare(strict_types=1);
 namespace Cake\Http;
 
 use Cake\Core\App;
+use Cake\Http\Middleware\DoublePassMiddleware;
 use Countable;
 use LogicException;
+use Psr\Http\Server\MiddlewareInterface;
 use RuntimeException;
 
 /**
@@ -34,11 +36,11 @@ class MiddlewareQueue implements Countable
     protected $queue = [];
 
     /**
-     * The queue of middleware callables.
+     * The queue of middlewares.
      *
-     * @var callable[]
+     * @var \Psr\Http\Server\MiddlewareInterface[]
      */
-    protected $callables = [];
+    protected $middlewares = [];
 
     /**
      * Constructor
@@ -54,13 +56,13 @@ class MiddlewareQueue implements Countable
      * Get the middleware at the provided index.
      *
      * @param int $index The index to fetch.
-     * @return callable|null Either the callable middleware or null
+     * @return \Psr\Http\Server\MiddlewareInterface|null Either the callable middleware or null
      *   if the index is undefined.
      */
-    public function get(int $index): ?callable
+    public function get(int $index): ?MiddlewareInterface
     {
-        if (isset($this->callables[$index])) {
-            return $this->callables[$index];
+        if (isset($this->middlewares[$index])) {
+            return $this->middlewares[$index];
         }
 
         return $this->resolve($index);
@@ -70,11 +72,11 @@ class MiddlewareQueue implements Countable
      * Resolve middleware name to callable.
      *
      * @param int $index The index to fetch.
-     * @return callable|null Either the callable middleware or null
+     * @return \Psr\Http\Server\MiddlewareInterface|null Either the callable middleware or null
      *   if the index is undefined.
      * @throws \RuntimeException If Middleware not found.
      */
-    protected function resolve(int $index): ?callable
+    protected function resolve(int $index): ?MiddlewareInterface
     {
         if (!isset($this->queue[$index])) {
             return null;
@@ -94,7 +96,11 @@ class MiddlewareQueue implements Countable
             $callable = $this->queue[$index];
         }
 
-        return $this->callables[$index] = $callable;
+        if (!$callable instanceof MiddlewareInterface) {
+            $callable = new DoublePassMiddleware($callable);
+        }
+
+        return $this->middlewares[$index] = $callable;
     }
 
     /**

+ 57 - 56
tests/TestCase/Http/MiddlewareQueueTest.php

@@ -16,6 +16,7 @@ declare(strict_types=1);
 namespace Cake\Test\TestCase\Http;
 
 use Cake\Core\Configure;
+use Cake\Http\Middleware\CallableMiddleware;
 use Cake\Http\MiddlewareQueue;
 use Cake\TestSuite\TestCase;
 use TestApp\Middleware\DumbMiddleware;
@@ -52,8 +53,8 @@ class MiddlewareQueueTest extends TestCase
 
     public function testConstructorAddingMiddleware()
     {
-        $cb = function () {
-        };
+        $cb = new CallableMiddleware(function () {
+        });
         $queue = new MiddlewareQueue([$cb]);
         $this->assertCount(1, $queue);
         $this->assertSame($cb, $queue->get(0));
@@ -67,8 +68,8 @@ class MiddlewareQueueTest extends TestCase
     public function testGet()
     {
         $queue = new MiddlewareQueue();
-        $cb = function () {
-        };
+        $cb = new CallableMiddleware(function () {
+        });
         $queue->add($cb);
         $this->assertSame($cb, $queue->get(0));
         $this->assertNull($queue->get(1));
@@ -82,8 +83,8 @@ class MiddlewareQueueTest extends TestCase
     public function testAddReturn()
     {
         $queue = new MiddlewareQueue();
-        $cb = function () {
-        };
+        $cb = new CallableMiddleware(function () {
+        });
         $this->assertSame($queue, $queue->add($cb));
     }
 
@@ -94,10 +95,10 @@ class MiddlewareQueueTest extends TestCase
      */
     public function testAddOrdering()
     {
-        $one = function () {
-        };
-        $two = function () {
-        };
+        $one = new CallableMiddleware(function () {
+        });
+        $two = new CallableMiddleware(function () {
+        });
 
         $queue = new MiddlewareQueue();
         $this->assertCount(0, $queue);
@@ -119,8 +120,8 @@ class MiddlewareQueueTest extends TestCase
      */
     public function testPrependReturn()
     {
-        $cb = function () {
-        };
+        $cb = new CallableMiddleware(function () {
+        });
         $queue = new MiddlewareQueue();
         $this->assertSame($queue, $queue->prepend($cb));
     }
@@ -132,10 +133,10 @@ class MiddlewareQueueTest extends TestCase
      */
     public function testPrependOrdering()
     {
-        $one = function () {
-        };
-        $two = function () {
-        };
+        $one = new CallableMiddleware(function () {
+        });
+        $two = new CallableMiddleware(function () {
+        });
 
         $queue = new MiddlewareQueue();
         $this->assertCount(0, $queue);
@@ -161,8 +162,8 @@ class MiddlewareQueueTest extends TestCase
         $queue->add('Sample');
         $queue->prepend('TestApp\Middleware\SampleMiddleware');
 
-        $this->assertInstanceOf('TestApp\Middleware\SampleMiddleware', $queue->get(0));
-        $this->assertInstanceOf('TestApp\Middleware\SampleMiddleware', $queue->get(1));
+        $this->assertInstanceOf('TestApp\Middleware\SampleMiddleware', $queue->get(0)->getCallable());
+        $this->assertInstanceOf('TestApp\Middleware\SampleMiddleware', $queue->get(1)->getCallable());
     }
 
     /**
@@ -172,14 +173,14 @@ class MiddlewareQueueTest extends TestCase
      */
     public function testAddingPrependingUsingArray()
     {
-        $one = function () {
-        };
+        $one = new CallableMiddleware(function () {
+        });
 
         $queue = new MiddlewareQueue();
         $queue->add([$one]);
         $queue->prepend(['TestApp\Middleware\SampleMiddleware']);
 
-        $this->assertInstanceOf('TestApp\Middleware\SampleMiddleware', $queue->get(0));
+        $this->assertInstanceOf('TestApp\Middleware\SampleMiddleware', $queue->get(0)->getCallable());
         $this->assertSame($one, $queue->get(1));
     }
 
@@ -190,19 +191,19 @@ class MiddlewareQueueTest extends TestCase
      */
     public function testInsertAt()
     {
-        $one = function () {
-        };
-        $two = function () {
-        };
-        $three = function () {
-        };
+        $one = new CallableMiddleware(function () {
+        });
+        $two = new CallableMiddleware(function () {
+        });
+        $three = new CallableMiddleware(function () {
+        });
         $four = new SampleMiddleware();
 
         $queue = new MiddlewareQueue();
         $queue->add($one)->add($two)->insertAt(0, $three)->insertAt(2, $four);
         $this->assertSame($three, $queue->get(0));
         $this->assertSame($one, $queue->get(1));
-        $this->assertSame($four, $queue->get(2));
+        $this->assertSame($four, $queue->get(2)->getCallable());
         $this->assertSame($two, $queue->get(3));
 
         $queue = new MiddlewareQueue();
@@ -219,10 +220,10 @@ class MiddlewareQueueTest extends TestCase
      */
     public function testInsertAtOutOfBounds()
     {
-        $one = function () {
-        };
-        $two = function () {
-        };
+        $one = new CallableMiddleware(function () {
+        });
+        $two = new CallableMiddleware(function () {
+        });
 
         $queue = new MiddlewareQueue();
         $queue->add($one)->insertAt(99, $two);
@@ -239,10 +240,10 @@ class MiddlewareQueueTest extends TestCase
      */
     public function testInsertAtNegative()
     {
-        $one = function () {
-        };
-        $two = function () {
-        };
+        $one = new CallableMiddleware(function () {
+        });
+        $two = new CallableMiddleware(function () {
+        });
         $three = new SampleMiddleware();
 
         $queue = new MiddlewareQueue();
@@ -250,7 +251,7 @@ class MiddlewareQueueTest extends TestCase
 
         $this->assertCount(3, $queue);
         $this->assertSame($two, $queue->get(0));
-        $this->assertSame($three, $queue->get(1));
+        $this->assertSame($three, $queue->get(1)->getCallable());
         $this->assertSame($one, $queue->get(2));
     }
 
@@ -261,11 +262,11 @@ class MiddlewareQueueTest extends TestCase
      */
     public function testInsertBefore()
     {
-        $one = function () {
-        };
+        $one = new CallableMiddleware(function () {
+        });
         $two = new SampleMiddleware();
-        $three = function () {
-        };
+        $three = new CallableMiddleware(function () {
+        });
         $four = new DumbMiddleware();
 
         $queue = new MiddlewareQueue();
@@ -274,8 +275,8 @@ class MiddlewareQueueTest extends TestCase
         $this->assertCount(4, $queue);
         $this->assertSame($one, $queue->get(0));
         $this->assertSame($three, $queue->get(1));
-        $this->assertSame($four, $queue->get(2));
-        $this->assertSame($two, $queue->get(3));
+        $this->assertSame($four, $queue->get(2)->getCallable());
+        $this->assertSame($two, $queue->get(3)->getCallable());
 
         $two = SampleMiddleware::class;
         $queue = new MiddlewareQueue();
@@ -287,7 +288,7 @@ class MiddlewareQueueTest extends TestCase
         $this->assertCount(3, $queue);
         $this->assertSame($one, $queue->get(0));
         $this->assertSame($three, $queue->get(1));
-        $this->assertInstanceOf(SampleMiddleware::class, $queue->get(2));
+        $this->assertInstanceOf(SampleMiddleware::class, $queue->get(2)->getCallable());
     }
 
     /**
@@ -316,10 +317,10 @@ class MiddlewareQueueTest extends TestCase
     public function testInsertAfter()
     {
         $one = new SampleMiddleware();
-        $two = function () {
-        };
-        $three = function () {
-        };
+        $two = new CallableMiddleware(function () {
+        });
+        $three = new CallableMiddleware(function () {
+        });
         $four = new DumbMiddleware();
         $queue = new MiddlewareQueue();
         $queue
@@ -329,8 +330,8 @@ class MiddlewareQueueTest extends TestCase
             ->insertAfter(SampleMiddleware::class, $four);
 
         $this->assertCount(4, $queue);
-        $this->assertSame($one, $queue->get(0));
-        $this->assertSame($four, $queue->get(1));
+        $this->assertSame($one, $queue->get(0)->getCallable());
+        $this->assertSame($four, $queue->get(1)->getCallable());
         $this->assertSame($three, $queue->get(2));
         $this->assertSame($two, $queue->get(3));
 
@@ -342,7 +343,7 @@ class MiddlewareQueueTest extends TestCase
             ->insertAfter('Sample', $three);
 
         $this->assertCount(3, $queue);
-        $this->assertInstanceOf(SampleMiddleware::class, $queue->get(0));
+        $this->assertInstanceOf(SampleMiddleware::class, $queue->get(0)->getCallable());
         $this->assertSame($three, $queue->get(1));
         $this->assertSame($two, $queue->get(2));
     }
@@ -355,15 +356,15 @@ class MiddlewareQueueTest extends TestCase
     public function testInsertAfterInvalid()
     {
         $one = new SampleMiddleware();
-        $two = function () {
-        };
-        $three = function () {
-        };
+        $two = new CallableMiddleware(function () {
+        });
+        $three = new CallableMiddleware(function () {
+        });
         $queue = new MiddlewareQueue();
         $queue->add($one)->add($two)->insertAfter('InvalidClass', $three);
 
         $this->assertCount(3, $queue);
-        $this->assertSame($one, $queue->get(0));
+        $this->assertSame($one, $queue->get(0)->getCallable());
         $this->assertSame($two, $queue->get(1));
         $this->assertSame($three, $queue->get(2));
     }