Change Router::continue to Router::continueOnNotFound; update docs

This commit is contained in:
PJ Dietz 2018-06-28 16:52:36 -04:00
parent 0a0d3c3bc9
commit 677cdb4d7d
6 changed files with 20 additions and 102 deletions

View File

@ -3,19 +3,10 @@ Changes from Version 3
If your project uses WellRESTed version 3, you can most likely upgrade to to version 4 without making any changes to your code. However, there are a few changes that may affect some users. If your project uses WellRESTed version 3, you can most likely upgrade to to version 4 without making any changes to your code. However, there are a few changes that may affect some users.
Unhandled Requests
^^^^^^^^^^^^^^^^^^
In version 3, when a router fails to match the route for a request, the router returns a response with a 404 status code and stops delegating to upstream middleware. Version 4 changes this to allow for multiple routers. In verson 4, when a router fails to match a route, it sends the request up to the next middleware to give it a change to handle the request.
The server now provides the mechanism for responding with a 404 error when no handlers handle the request. This occurs when a request is dispatched all through through the server's middleware stack.
For most applications, this should not cause a problem. However, if your application uses "double pass" middleware—such as legacy ``WellRESTed\MiddlewareInterface`` implementations—and your handlers call ``$next`` after assembling the handled response, you will need to make adjustments. Return the response without calling ``$next`` in these handlers to avoid returning a 404 response.
Server Configuration Server Configuration
^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
Version 4 allows for easier customization of the server than version 3. Previously, to customize the Server, you would need subclass Server and override protected methods that provided a default request, response, transmitter, etc. The Server in version 4 now provides the following setters for providing custom behaviour: Version 4 allows for easier customization of the server than version 3. Previously, to customize the Server, you would need to subclass Server and override protected methods that provided a default request, response, transmitter, etc. The Server in version 4 now provides the following setters for providing custom behavior:
- ``setAttributes(array $attributes)`` - ``setAttributes(array $attributes)``
- ``setDispatcher(DispatcherInterface $dispatcher)`` - ``setDispatcher(DispatcherInterface $dispatcher)``
@ -23,4 +14,3 @@ Version 4 allows for easier customization of the server than version 3. Previous
- ``setRequest(ServerRequestInterface $request)`` - ``setRequest(ServerRequestInterface $request)``
- ``setResponse(ResponseInterface $response)`` - ``setResponse(ResponseInterface $response)``
- ``setTransmitter(TransmitterInterface $transmitter)`` - ``setTransmitter(TransmitterInterface $transmitter)``
- ``setUnhandledResponse(ResponseInterface $response)``

View File

@ -123,6 +123,7 @@ A router will often contain many routes, and sometimes more than one route will
#. If one prefix route matches the beginning of the path, dispatch it. #. If one prefix route matches the beginning of the path, dispatch it.
#. If multiple prefix routes match, dispatch the longest matching prefix route. #. If multiple prefix routes match, dispatch the longest matching prefix route.
#. Inspect each pattern route (template and regular expression) in the order in which they were added to the router. Dispatch the first route that matches. #. Inspect each pattern route (template and regular expression) in the order in which they were added to the router. Dispatch the first route that matches.
#. If no pattern routes match, return a response with a ``404 Not Found`` status. (**Note:** This is the default behavior. To configure a router to delegate to the next middleware when no route matches, call the router's ``continueOnNotFound()`` method.)
Static vs. Prefix Static vs. Prefix
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
@ -304,13 +305,15 @@ This feature allows you to build a site where some sections use certain middlewa
$server = new Server(); $server = new Server();
// Add the "public" section. // Add the "public" router.
$public = $server->createRouter(); $public = $server->createRouter();
$public->register('GET', '/', $homeHandler); $public->register('GET', '/', $homeHandler);
$public->register('GET', '/about', $homeHandler); $public->register('GET', '/about', $homeHandler);
// Set the router call the next middleware when no route matches.
$public->continueOnNotFound();
$server->add($public); $server->add($public);
// Add the "private" section. // Add the "private" router.
$private = $server->createRouter(); $private = $server->createRouter();
// Authorizaiton middleware checks for an Authorization header and // Authorizaiton middleware checks for an Authorization header and
// responds 401 when the header is missing or invalid. // responds 401 when the header is missing or invalid.

View File

@ -6,12 +6,11 @@ use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use WellRESTed\Dispatching\Dispatcher; use WellRESTed\Dispatching\Dispatcher;
use WellRESTed\Dispatching\DispatcherInterface; use WellRESTed\Dispatching\DispatcherInterface;
use WellRESTed\Message\Response;
use WellRESTed\Routing\Route\RouteFactory; use WellRESTed\Routing\Route\RouteFactory;
use WellRESTed\Routing\Route\RouteFactoryInterface; use WellRESTed\Routing\Route\RouteFactoryInterface;
use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Routing\Route\RouteInterface;
class Router implements RouterInterface class Router
{ {
/** @var string attribute name for matched path variables */ /** @var string attribute name for matched path variables */
private $pathVariablesAttributeName; private $pathVariablesAttributeName;
@ -30,7 +29,7 @@ class Router implements RouterInterface
/** @var mixed[] List array of middleware */ /** @var mixed[] List array of middleware */
private $stack; private $stack;
/** @var bool Call the next middleware when no route matches */ /** @var bool Call the next middleware when no route matches */
private $continue = false; private $continueOnNotFound = false;
/** /**
* Create a new Router. * Create a new Router.
@ -94,7 +93,7 @@ class Router implements RouterInterface
} }
} }
if (!$this->continue) { if (!$this->continueOnNotFound) {
return $response->withStatus(404); return $response->withStatus(404);
} }
@ -179,9 +178,15 @@ class Router implements RouterInterface
return $this; return $this;
} }
public function continue() /**
* Configure the instance to delegate to the next middleware when no route
* matches.
*
* @return static
*/
public function continueOnNotFound()
{ {
$this->continue = true; $this->continueOnNotFound = true;
return $this; return $this;
} }

View File

@ -1,80 +0,0 @@
<?php
namespace WellRESTed\Routing;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use WellRESTed\MiddlewareInterface;
/**
* Maps HTTP methods and paths to middleware
*/
interface RouterInterface extends MiddlewareInterface
{
/**
* Evaluate $request's path and method and dispatches matching middleware.
*
* Implementations MUST pass $request, $response, and $next to the matching
* middleware.
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param callable $next
* @return ResponseInterface
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next);
/**
* Register handlers and middleware with the router for a given path and
* method.
*
* $method may be:
* - A single verb ("GET"),
* - A comma-separated list of verbs ("GET,PUT,DELETE")
* - "*" to indicate any method.
*
* $target may be:
* - An exact path (e.g., "/path/")
* - A prefix path ending with "*"" ("/path/*"")
* - A URI template with variables enclosed in "{}" ("/path/{id}")
* - A regular expression ("~/cat/([0-9]+)~")
*
* $dispatchable may be:
* - An instance implementing one of these interfaces:
* - Psr\Http\Server\RequestHandlerInterface
* - Psr\Http\Server\MiddlewareInterface
* - WellRESTed\MiddlewareInterface
* - Psr\Http\Message\ResponseInterface
* - A string containing the fully qualified class name of a class
* implementing one of the interfaces listed above.
* - A callable that returns an instance implementing one of the
* interfaces listed above.
* - A callable with a signature matching the signature of
* WellRESTed\MiddlewareInterface::__invoke
* - An array containing any of the items in this list.
* @see DispatchedInterface::dispatch
*
* @param string $target Request target or pattern to match
* @param string $method HTTP method(s) to match
* @param mixed $dispatchable Middleware to dispatch
* @return static
*/
public function register($method, $target, $dispatchable);
/**
* Push a new middleware onto the stack. Middleware for a router runs only
* when the router has a route matching the request.
*
* $middleware may be:
* - An instance implementing MiddlewareInterface
* - A string containing the fully qualified class name of a class
* implementing MiddlewareInterface
* - A callable that returns an instance implementing MiddleInterface
* - A callable matching the signature of MiddlewareInterface::dispatch
* @see DispatchedInterface::dispatch
*
* @param mixed $middleware Middleware to dispatch in sequence
* @return static
*/
public function addMiddleware($middleware);
}

View File

@ -129,7 +129,7 @@ class RoutingTest extends TestCase
'Content-type', 'application/cat')) 'Content-type', 'application/cat'))
->register('GET', '/molly', new StringHandler('Molly')) ->register('GET', '/molly', new StringHandler('Molly'))
->register('GET', '/oscar', new StringHandler('Oscar')) ->register('GET', '/oscar', new StringHandler('Oscar'))
->continue(); ->continueOnNotFound();
$this->server->add($catRouter); $this->server->add($catRouter);
$dogRouter = $this->server->createRouter() $dogRouter = $this->server->createRouter()
@ -156,7 +156,7 @@ class RoutingTest extends TestCase
'Content-type', 'application/cat')) 'Content-type', 'application/cat'))
->register('GET', '/molly', new StringHandler('Molly')) ->register('GET', '/molly', new StringHandler('Molly'))
->register('GET', '/oscar', new StringHandler('Oscar')) ->register('GET', '/oscar', new StringHandler('Oscar'))
->continue(); ->continueOnNotFound();
$this->server->add($catRouter); $this->server->add($catRouter);
$dogRouter = $this->server->createRouter() $dogRouter = $this->server->createRouter()

View File

@ -381,7 +381,7 @@ class RouterTest extends TestCase
public function testWhenNoRouteMatchesAndContinueModePropagatesToNextMiddleware() public function testWhenNoRouteMatchesAndContinueModePropagatesToNextMiddleware()
{ {
$this->request = $this->request->withRequestTarget("/no/match"); $this->request = $this->request->withRequestTarget("/no/match");
$this->router->continue(); $this->router->continueOnNotFound();
$this->router->__invoke($this->request, $this->response, $this->next); $this->router->__invoke($this->request, $this->response, $this->next);
$this->assertTrue($this->next->called); $this->assertTrue($this->next->called);
} }