Routing
Default Routing Rules
The default routing rule for webman is http://127.0.0.1:8787/{controller}/{action}.
The default controller is app\controller\IndexController, and the default action is index.
For example:
http://127.0.0.1:8787will by default access theindexmethod of theapp\controller\IndexControllerclass.http://127.0.0.1:8787/foowill by default access theindexmethod of theapp\controller\FooControllerclass.http://127.0.0.1:8787/foo/testwill by default access thetestmethod of theapp\controller\FooControllerclass.http://127.0.0.1:8787/admin/foo/testwill by default access thetestmethod of theapp\admin\controller\FooControllerclass (see Multiple Applications).
Additionally, starting from webman 1.4, it supports more complex default routing, such as
app
├── admin
│ └── v1
│ └── v2
│ └── v3
│ └── controller
│ └── IndexController.php
└── controller
├── v1
│ └── IndexController.php
└── v2
└── v3
└── IndexController.php
When you want to change a request route, please modify the configuration file config/route.php.
If you want to disable the default route, add the following configuration to the end of the config/route.php file:
Route::disableDefaultRoute();
Closure Routes
Add the following routing code to config/route.php:
use support\Request;
Route::any('/test', function (Request $request) {
return response('test');
});
Note
Because closure functions do not belong to any controller,$request->app,$request->controller, and$request->actionare all empty strings.
When accessing http://127.0.0.1:8787/test, it will return the string test.
Note
The route path must start with/, for example:
use support\Request;
// Incorrect usage
Route::any('test', function (Request $request) {
return response('test');
});
// Correct usage
Route::any('/test', function (Request $request) {
return response('test');
});
Class Routes
Add the following routing code to config/route.php:
Route::any('/testclass', [app\controller\IndexController::class, 'test']);
When accessing http://127.0.0.1:8787/testclass, it will return the result of the test method of the app\controller\IndexController class.
Annotation Routing
Define routes using annotations on controller methods without configuring in config/route.php.
Note
This feature requires webman-framework >= v2.2.0
Basic Usage
namespace app\controller;
use support\annotation\route\DisableDefaultRoute;
use support\annotation\route\Get;
use support\annotation\route\Post;
use support\annotation\route\Route;
#[DisableDefaultRoute]
class UserController
{
#[Get('/user/{id}')]
public function show($id)
{
return "user $id";
}
#[Post('/user')]
public function store()
{
return 'created';
}
#[Route('/user/form', ['GET', 'POST'], 'user.form')]
public function form()
{
return 'form';
}
}
Available annotations: #[Get] #[Post] #[Put] #[Delete] #[Patch] #[Head] #[Options] #[Any] (any method). Paths must start with /. The second parameter may specify a route name for URL generation via route().
#[DisableDefaultRoute] disables default routing for the controller (optional); only routes defined by annotations are accessible.
#[Route] full syntax: #[Route(path, methods, name)]
path: Route path, must start with/; whennull, only restricts HTTP methods for the default route without registering a new routemethods: HTTP method(s), string or array of strings, e.g.'GET'or['GET','POST']name: Route name forroute('name')URL generation, can be omitted
Parameterless Annotations: Restrict HTTP Methods for Default Routes
When no path is specified, only the allowed HTTP methods for that action are restricted; the default route path is still used:
#[Post]
public function create() { ... } // POST only, path still /user/create
#[Get]
public function index() { ... } // GET only
Multiple annotations can be combined to allow several methods:
#[Get]
#[Post]
public function form() { ... } // Allows GET and POST
Undeclared HTTP methods will return 405.
Multiple path annotations register as separate routes: #[Get('/a')] #[Post('/b')] creates both GET /a and POST /b.
Route Group Prefix
Use #[RouteGroup] on a class to add a prefix to all method routes:
use support\annotation\route\RouteGroup;
use support\annotation\route\Get;
#[RouteGroup('/api/v1')]
class UserController
{
#[Get('/user/{id}')] // Actual path: /api/v1/user/{id}
public function show($id) { ... }
}
Custom HTTP Methods and Route Name
#[Route] supports custom HTTP methods and route names:
use support\annotation\route\Route;
#[Route('/user', ['GET', 'POST'], 'user.form')]
public function form() { ... }
// Path and method only, no route name
#[Route('/user/update', 'PUT')]
public function update() { ... }
Path Parameters and Regex
Annotation route paths support the same parameter syntax as config/route.php, including regex and optional parameters:
#[Get('/user/{id:\d+}')] // Numeric id only
public function show($id) { ... }
#[Get('/user[/{name}]')] // name optional: /user or /user/xxx
public function list($name = null) { ... }
#[Any('/user/[{path:.+}]')] // Matches /user and /user/ with any suffix
public function catchAll($path = null) { ... }
See the "Route Parameters" section in this document for details.
Middleware
#[Middleware] on a controller or method applies to annotation routes; usage is the same as support\annotation\Middleware:
use support\annotation\Middleware;
#[Middleware(\app\middleware\AuthMiddleware::class)]
class UserController { ... }
#[Get('/user/{id}')]
#[Middleware(\app\middleware\RateLimitMiddleware::class)]
public function show($id) { ... }
URL Generation with route()
When a route name is specified in an annotation, use route('name', $params) to generate the URL:
#[Get('/user/{id}', 'user.show')]
public function show($id) { ... }
// Usage: route('user.show', ['id' => 123]) => /user/123
Route Parameters
If there are parameters in the route, they can be matched using {key} and the matched result will be passed to the corresponding controller method parameter (starting from the second parameter), for example:
// Matching /user/123 /user/abc
Route::any('/user/{id}', [app\controller\UserController::class, 'get']);
namespace app\controller;
use support\Request;
class UserController
{
public function get(Request $request, $id)
{
return response('Received parameter'.$id);
}
}
More examples:
use support\Request;
// Matching /user/123, not matching /user/abc
Route::any('/user/{id:\d+}', function (Request $request, $id) {
return response($id);
});
// Matching /user/foobar, not matching /user/foo/bar
Route::any('/user/{name}', function (Request $request, $name) {
return response($name);
});
// Matching /user, /user/123, and /user/abc [] indicates optional
Route::any('/user[/{name}]', function (Request $request, $name = null) {
return response($name ?? 'tom');
});
// Matching all requests with /user/ prefix
Route::any('/user/[{path:.+}]', function (Request $request) {
return $request->path();
});
// Matching all options requests : followed by regex specifies the pattern for the named parameter
Route::options('[{path:.+}]', function () {
return response('');
});
Advanced usage summary
The
[]syntax in Webman routing mainly handles optional path segments or dynamic route matching, allowing you to define more complex path structures and matching rules
:is used to specify regular expressions
Route Groups
Sometimes, routes contain a lot of the same prefixes. In this case, we can use route groups to simplify the definition. For example:
Route::group('/blog', function () {
Route::any('/create', function (Request $request) {return response('create');});
Route::any('/edit', function (Request $request) {return response('edit');});
Route::any('/view/{id}', function (Request $request, $id) {return response("view $id");});
});
Equivalent to
Route::any('/blog/create', function (Request $request) {return response('create');});
Route::any('/blog/edit', function (Request $request) {return response('edit');});
Route::any('/blog/view/{id}', function (Request $request, $id) {return response("view $id");});
Nested group usage
Route::group('/blog', function () {
Route::group('/v1', function () {
Route::any('/create', function (Request $request) {return response('create');});
Route::any('/edit', function (Request $request) {return response('edit');});
Route::any('/view/{id}', function (Request $request, $id) {return response("view $id");});
});
});
Route Middleware
We can set a middleware for a specific route or a group of routes. For example:
Route::any('/admin', [app\admin\controller\IndexController::class, 'index'])->middleware([
app\middleware\MiddlewareA::class,
app\middleware\MiddlewareB::class,
]);
Route::group('/blog', function () {
Route::any('/create', function () {return response('create');});
Route::any('/edit', function () {return response('edit');});
Route::any('/view/{id}', function ($request, $id) {return response("view $id");});
})->middleware([
app\middleware\MiddlewareA::class,
app\middleware\MiddlewareB::class,
]);
# Incorrect usage example (valid in webman-framework >= 1.5.7)
Route::group('/blog', function () {
Route::group('/v1', function () {
Route::any('/create', function (Request $request) {return response('create');});
Route::any('/edit', function (Request $request) {return response('edit');});
Route::any('/view/{id}', function (Request $request, $id) {return response("view $id");});
});
})->middleware([
app\middleware\MiddlewareA::class,
app\middleware\MiddlewareB::class,
]);
# Correct usage example
Route::group('/blog', function () {
Route::group('/v1', function () {
Route::any('/create', function (Request $request) {return response('create');});
Route::any('/edit', function (Request $request) {return response('edit');});
Route::any('/view/{id}', function (Request $request, $id) {return response("view $id");});
})->middleware([
app\middleware\MiddlewareA::class,
app\middleware\MiddlewareB::class,
]);
});
Resourceful Routing
Route::resource('/test', app\controller\IndexController::class);
// Specify resource routes
Route::resource('/test', app\controller\IndexController::class, ['index','create']);
// Non-defining resource routes
// If accessing notify, it will be any type of route /test/notify or /test/notify/{id} and the routeName will be test.notify
Route::resource('/test', app\controller\IndexController::class, ['index','create','notify']);
| Verb | URI | Action | Route Name |
|---|---|---|---|
| GET | /test | index | test.index |
| GET | /test/create | create | test.create |
| POST | /test | store | test.store |
| GET | /test/{id} | show | test.show |
| GET | /test/{id}/edit | edit | test.edit |
| PUT | /test/{id} | update | test.update |
| DELETE | /test/{id} | destroy | test.destroy |
| PUT | /test/{id}/recovery | recovery | test.recovery |
URL Generation
Note
Route URL generation for nested groups is not supported yet
For example, with the route:
Route::any('/blog/{id}', [app\controller\BlogController::class, 'view'])->name('blog.view');
We can use the following method to generate the URL for this route:
route('blog.view', ['id' => 100]); // Result: /blog/100
When using route URLs in a view, this method can be used so that regardless of changes to the routing rules, the URL will be generated automatically, avoiding the need to modify a large number of view files due to changes in route addresses.
Get Route Information
We can obtain the current request route information through the $request->route object, for example:
$route = $request->route; // Equivalent to $route = request()->route;
if ($route) {
var_export($route->getPath());
var_export($route->getMethods());
var_export($route->getName());
var_export($route->getMiddleware());
var_export($route->getCallback());
var_export($route->param());
}
Note
If the current request does not match any routes configured inconfig/route.php,$request->routewill be null, meaning that the default route will result in$request->routebeing null.
Handling 404 Errors
When the route is not found, the default behavior is to return a 404 status code and output 404 content.
If developers want to intervene in the business process when a route is not found, they can use the fallback route provided by webman using the Route::fallback($callback) method. For example, the following code logic redirects to the homepage when the route is not found.
Route::fallback(function(){
return redirect('/');
});
Another example is returning a JSON response when the route does not exist, which is very useful when webman is used as an API endpoint.
Route::fallback(function(){
return json(['code' => 404, 'msg' => '404 not found']);
});
Add Middleware to 404 Requests
By default, 404 requests do not go through any middleware. If you need to add middleware to 404 requests, refer to the following code.
Route::fallback(function(){
return json(['code' => 404, 'msg' => '404 not found']);
})->middleware([
app\middleware\MiddlewareA::class,
app\middleware\MiddlewareB::class,
]);
Related link: Custom 404 and 500 Pages
Disable Default Route
// Disable main project default route, does not affect application plugins
Route::disableDefaultRoute();
// Disable admin application route of main project, does not affect application plugins
Route::disableDefaultRoute('', 'admin');
// Disable foo plugin default route, does not affect main project
Route::disableDefaultRoute('foo');
// Disable foo plugin admin application default route, does not affect main project
Route::disableDefaultRoute('foo', 'admin');
// Disable default route for controller [\app\controller\IndexController::class, 'index']
Route::disableDefaultRoute([\app\controller\IndexController::class, 'index']);
Annotation Disable Default Route
You can disable the default route for a controller using annotations, for example:
namespace app\controller;
use support\annotation\DisableDefaultRoute;
#[DisableDefaultRoute]
class IndexController
{
public function index()
{
return 'index';
}
}
Likewise, you can also disable the default route for a specific method of a controller using annotations, for example:
namespace app\controller;
use support\annotation\DisableDefaultRoute;
class IndexController
{
#[DisableDefaultRoute]
public function index()
{
return 'index';
}
}
Route Interface
// Set a route for any method request for $uri
Route::any($uri, $callback);
// Set a route for a get request for $uri
Route::get($uri, $callback);
// Set a route for a post request for $uri
Route::post($uri, $callback);
// Set a route for a put request for $uri
Route::put($uri, $callback);
// Set a route for a patch request for $uri
Route::patch($uri, $callback);
// Set a route for a delete request for $uri
Route::delete($uri, $callback);
// Set a route for a head request for $uri
Route::head($uri, $callback);
// Set a route for an options request for $uri
Route::options($uri, $callback);
// Set routes for multiple request types simultaneously
Route::add(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'], $uri, $callback);
// Group routes
Route::group($path, $callback);
// Resource routes
Route::resource($path, $callback, [$options]);
// Disable the default route
Route::disableDefaultRoute($plugin = '');
// Fallback route, set the default route fallback
Route::fallback($callback, $plugin = '');
// Get all route information
Route::getRoutes();
If there is no corresponding route for the URI (including the default route), and no fallback route is set, a 404 response will be returned.
Multiple Route Configuration Files
If you want to manage routes using multiple route configuration files, for example, in the case of multiple applications where each application has its own route configuration, you can load external route configuration files using the require statement.
For example, in config/route.php:
<?php
// Load the route configuration for the admin application
require_once app_path('admin/config/route.php');
// Load the route configuration for the api application
require_once app_path('api/config/route.php');