Change Router::continue to Router::continueOnNotFound; update docs
This commit is contained in:
parent
0a0d3c3bc9
commit
677cdb4d7d
|
|
@ -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)``
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue