Download the PHP package snicco/http-routing without Composer
On this page you can find all versions of the php package snicco/http-routing. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download snicco/http-routing
More information about snicco/http-routing
Files in snicco/http-routing
Package http-routing
Short Description The HTTP and routing component of the snicco framework
License LGPL-3.0-only
Informations about the package http-routing
Snicco HTTP-Routing: A PSR7-/PSR-15 routing system and middleware-dispatcher for legacy CMSs
The HTTP-Routing component of the Snicco project is an opinionated
library that combines a routing system built upon FastRoute
with a power PSR-15
middleware dispatcher.
Although not a requirement, it was intentionally built to support legacy CMSs like WordPress where you don't have full control of the request-response lifecycle.
Features:
- Rich API to configure routes
- URL generation / reverse routing
- Attaching middleware on a per-route basis
- Route groups
- Completely cached in production
- Special handling for the admin area of a legacy CMS (if applicable)
- and much more.
Table of contents
- Installation
- Routing
- Creating a router
- Defining routes
- Defining HTTP verbs
- Route parameters
- Regex constraints
- Adding middleware
- Adding conditions
- Route groups
- Controllers
- Redirect routes
- View routes
- Admin routes
- API routes
- Route caching
- Matching a route
- Reverse routing / URL generation
- The Admin menu
- PSR-15 middleware dispatcher
- Creating a middleware pipeline
- Piping requests
- Middleware resolver
- PSR utilities
- Contributing
- Issues and PR's
- Security
Installation
Routing
Creating a router
The central class of the routing subcomponent is the Router
facade class. (no, not a laravel
facade)
The Router
serves as a factory for different parts of the routing system.
To instantiate a Router
we need the following collaborators:
- The
URLGenerationContext
, which is a value object that configures the URL generation. - A
RouteLoader
, which is responsible for loading and configuring your routes (only if nothing is cached yet.) - A
RouteCache
, which is responsible for caching the route definitions in production. - An instance of
AdminArea
, which serves as a bridge between the routing system and a legacy CMS admin area.
Once we have our Router
, we can use it to instantiate the different parts of the routing
system.
Defining routes
The included PHPFileRouteLoader
will search for files with a .php
extension inside each of the provided route directories. Nested directories are not used.
For now, we assume the following directory structure:
Each file inside a route directory must return a closure that accepts an instance
of RoutingConfigurator
A admin.php
route file is a special case. It will receive an instance
of AdminRoutingConfigurator
.
The RouteLoadingOptions
value object allows you to customize
some generic settings for all routes like automatically adding a middleware with the name of the
route file.
Check out the DefaultRouteLoadingOptions
for an example.
Defining HTTP verbs
Route parameters
The syntax of HTTP-Routing component offers an alternative syntax to the native syntax
of FastRoute
. This is highly opinionated, but we think that the
syntax of FastRoute
is a little to verbose, especially when
dealing with optional segments and regex requirements.
! For maximum performance, all routes will be compiled to match the native syntax of FastRoute before caching.
- Route segments enclosed within
{...}
are required. - Route segments enclosed within
{...?}
are optional.
The above route definition will match /posts/1/comments/2
and /posts/1/comments
.
The captured parameters will be available to the configured controller.
Trailing slashes can be used in combination with route segments.
The above route definition will match /posts/1/comments/2/
and /posts/1/comments/
.
Optional segments can only occur at the end of a route pattern.
Regex constraints
Adding Middleware
Middleware can be configured for each route individually.
A middleware can either be the fully qualified class name of a PSR-15 middleware or an alias that will later be resolved to the class name of a PSR-15 middleware.
Arguments can be passed to middleware (the constructor) as a comma separated list after a :
.
The following conversions are performed before instantiating a middleware with the passed arguments:
- (string) true => (bool) true
- (string) false => (bool) false
- (string) numeric => numeric
Adding conditions
In addition to matching a route by its URL pattern, you can also specify route conditions.
A route condition is any class that implements RouteCondition
.
Route groups
You can group routes with similar attributes together using route groups.
The following attributes can currently be grouped in some form:
- middleware: will be merged for all routes in the group.
- url prefix: will be added to all URL patterns in the group.
- route name: will be concatenated with a
.
for all routes. - namespace: will be set for all routes, but can be overwritten on a per-route basis.
Nested route groups are supported.
Controllers
The controller is the class method that is attached to route.
The controller will be used to transform a PSR-7 server request to a PSR-7 response. (more on that later)
For now, its only important how to define controllers and which arguments will be available in controllers.
If a controller is defined using the fully qualified class name it must have an __invoke
method.
It's possible to leave out the controller, in which case
a fallback controller will be added to the route. The fallback
controller will always return an instance of DelegatedResponse
which can be
used to express (to another system) that the current request should not be handled (by your code).
The first argument passed to all controller methods is an instance
of Snicco\Component\HttpRouting\Http\Psr7\Request
(if the controller method has that typehint).
Captured route segments are passed by order to the controller method. Method parameter names and segment names in the route definition are not important.
Captured route segments are always strings (in FastRoute), but numerical values are converted to integers for convenience.
Route conditions can also return "captured parameters". If a route has a condition that returned parameters, they will be passed to the controller methods after the parameters that were captured in the URL.
Redirect routes
You can directly configure redirects in your route file. Instead of defining a dedicated controller
all redirect routes will use the RedirectController
to directly create
a RedirectResponse
.
View routes
If you only want to return a simple template for a given URL without much logic
you can use the view()
method on the routing configurator.
When this route matches it will return an instance of ViewResponse
.
It's up to you how to convert this into the underlying template. You will probably want to use your favorite
template engine inside a custom middleware to achieve this.
Admin routes
Routes defined in a admin.php
file are special in a sense that they can be used to create routes to the admin area of
a CMS like WordPress where you usually don't have control ofter the "routing".
You can even create admin menu items directly from your route definitions.
All of these implementation details are abstracted away by the AdminArea
interface
and the AdminMenu
interface.
Admin routes are configured by using
the AdminRoutingConfigurator
.
Admin routes are limited to GET
requests.
Instead of using the WebRoutingConfigurator::get()
method you'll use the AdminRoutingConfigurator::page()
and AdminRoutingConfigurator::subPage()
methods.
The following is an example on how you would use this in WordPress where routing in the admin area is done by using
a page
query variable. Check out the WPAdminArea
for the WordPress
implementation of the AdminArea
interface.
In your default WordPress installation these routes would match the following path:
/wp-adming/admin.php?page=overview
/wp-adming/admin.php?page=settings
Based on your route name and route pattern an instance of AdminMenuItem
will
automatically be added to the AdminMenu
that
is available through the Router
.
API Routes
The difference between route files inside the api route directory and "normal" routes is that
the RouteLoadingOptions::getApiRouteAttributes()
method will be used to apply default settings for each route.
This allows for example:
- adding a base prefix like
/api
to all routes - prefixing route names with
api.
- parsing a version number from the filename and applying it as a prefix
/api/v1
Using API-routes is completely optional.
Route caching
Everything that was mentioned above will be cached in production into a single PHP file that can be returned very fast by OPcache.
For that exact reason this package intentionally does not support Closures
as a "route controller". Closures
can't
be serialized natively in PHP.
Internally, FastRoute
only contains the names of each route. Once a route is matched that single route only will be
hydrated and "run".
This provides a significant performance increase as the number of routes in your application grows.
Check out the SerializedRouteCollection
for details.
Matching a route
The first call to Router::urlMatcher()
will lazily load and configure all routes (or return the cached ones).
Reverse routing / URL generation
Routing systems are always bidirectional:
- URL => Route
- route name + parameters => URL
FastRoute
only provides the first part. This package fills in that void.
The first call to Router::urlGenerator()
will lazily load and configure all routes (or return the cached ones).
Regex constraints are taken into account when generating URLs and provided values that would cause to not match the route will throw an exception.
The AdminMenu
If you are using AdminMenu
will
automatically be configured based on your route definitions.
You can use the AdminMenu
object to configure some external system of a legacy
CMS (if applicable).
The first call to Router::adminMenu()
will lazily load and configure all routes (or return the cached ones).
PSR-15 Middleware dispatcher
This package comes with a very powerful PSR-15 middleware dispatcher that already incorporates the configured routing system.
The central piece is the MiddlewarePipeline
.
Creating a middleware pipeline
The middleware pipeline needs a PSR-11 container to lazily resolve your controllers and middleware.
Furthermore, an instance of HTTPErrorHanlder
is needed to handle
exceptions for each middleware.
Piping requests
At a basic level, the middleware pipeline takes a PSR-7 server request, pipes it through multiple PSR-15 middleware and returns a PSR-7 response. How you send that response object is up to you.
To connect the middleware pipeline with our routing system we use to inbuilt PSR-15 middleware of this package.
RoutingMiddleware
RouteRunner
The RoutingMiddleware
is responsible for matching the current request in the
pipeline to a route of the routing system.
The RouteRunner
is responsible for "running" the matched route.
If no route was matched an instance of DelegatedResponse
will be returned.
If a route was matched the following will happen:
- All middleware of the matched route will be resolved.
- A new (inner) middleware pipeline will be created that pipes the request through all route middleware.
- The last step of this inner middleware pipeline will resolve the route controller from the container and execute it.
To instantiate the RouteRunner
we first need
a MiddlewareResolver
.
MiddlewareResolver
As the class name suggests, the MiddlewareResolver
is responsible for
resolving all middleware that should be applied to an individual route and/or request.
The middleware resolver can be cached to maximize performance.
Caching the middleware resolver means, that for each routes in your application the middleware is already resolved recursively, groups are expanded, aliases are resolved etc.
PSR utilities
This package contains some classes that extend the PSR interfaces to provide some utility helpers.
Using them is entirely optional:
- The abstract
Middleware
and the abstractController
can be extended. They both give you access to theResponseUtils
class and contain a reference to theURLGenerator
. - The
Request
class wraps any PSR-7 request and provides some helpful methods not defined in the PSR-7 interface. - The
Response
class wraps any PSR-7 response and provides some helpful methods not defined in the PSR-7 interface.
Contributing
This repository is a read-only split of the development repo of the Snicco project.
This is how you can contribute.
Reporting issues and sending pull requests
Please report issues in the Snicco monorepo.
Security
If you discover a security vulnerability, please follow our disclosure procedure.
All versions of http-routing with dependencies
ext-filter Version *
ext-json Version *
ext-mbstring Version *
nikic/fast-route Version 1.3.0
psr/container Version ^1.1
psr/http-factory Version ^1.0.0
psr/http-message Version ^1.0.0
psr/http-server-handler Version ^1.0.0
psr/http-server-middleware Version ^1.0.0
snicco/psr7-error-handler Version ^2.0
snicco/str-arr Version ^2.0
webimpress/safe-writer Version ^2.2
webmozart/assert Version ^1.10