In this article we basicly talking about design concepts of router. For a quick glance of how to use, check our quickstart guide.
Routing is about answering "What should I do". There are two core concept in our routing machanism: router and dispatcher.
RouterDispatchHandler, act as dispatcher, implements
RequestHandlerInterface, call it's router to locate real business RequestHandler, and delegate request to it.
On the other side, router is a interface with a simple method, contains all routing logic.
function route(ServerRequestInterface $request): RequestHandlerInterface
The way you use a router looks like something like
$router = new MyCoolRouter(); //somehow register all the route entries $app = new App(new RouterDispatchHandler($router)); emit_response($app->handle($request));
AbstractRouter, we introduce another concept called stub. Stub breaks routing process into two phase, in the routing phase you just analyze the request and find the correct stub. In second phase, you resolve the stub to get the real
RequestHandlerInterface instance. The point here is, stub can be any type and should be a cheap one (one simple string, or some array of strings), while request handlers is likely to be the most complicated part in your application. It's very common that a handler instance will carry many other service instance. At worst they may carry external resources, like DB connections or things like that, at least the class / bytecode / autoload process do hurt performance.
There are two things need to be implemented to utilize
AbstractRouter: For the first phase, you need to implement
AbstractRouter::findStub to parse the request and find the corresponding stub, you may call your 3rd party routing component here, or implement your own routing logic; For the second phase, you need to implement a
RouterStubResolverInterface with the
resolve method, to convert your stub into some real request handler. If you somehow don't need the stub resolve mechanism, you may just use
\Lit\Voltage\RouteStubResolver which is a noop (just return the $stub itself). In this case, you need generate the request handler instance directly in
findStub and return the hander.
Spread the implementation in two class make it possible to reuse logic. You can change your router implementation, or even use two different router for dirrerent request (remember
RouterDispatchHandler is also a handler, you may somehow let your router A to return a
RouterDispatchHandler which contains another router B), keeping stub resolving untouched. Or change/add new stub resolving mechanism (e.g. implement old "controller" style routing, instantiate controller and wrap the controller + method in a handler instance inside your StubResolver)
\Lit\Voltage\BasicRouter implementation exists which just do routing by array with path/method as offset. See src/Lit/Core/_example/routing.php for a working example
\Lit\Bolt\Router\BoltStubResolver in bolt package is a more realistic stub resolver that use dependency inject to instantiate your handler. /* add link here */
litphp/router-fast-route package is there for