Simple Routing
Windwalker will auto map URL to package and controller.
/flower/sakura
==>Flower\Controller\Sakura\GetController
/foo/bar/baz
==>Foo\Bar\Controller\Baz\GetController
The flower
and foo/bar
will be namespace of this controller, and the last part (sakura
, baz
) will be controller name.
GetController
is auto added, which means this is a default GET
request, similar to indexAction
in other frameworks.
Since Windwalker uses single action controller, a controller class only handle one action.
If you send a POST
request, the SaveController
will be called instead. So we can use RESTful methods to handle our CRUD.
Simple routing has low performance so we can disable it in etc/config.yml
# etc/config.yml
routing:
simple_route: false
After disabled simple routing, we must register route profile to every page.
Register Routing
Open /etc/routing.yml
and add a new route profile.
sakura:
pattern: /flower/sakura
controller: Foo\Controller\Myflower
If you open /flower/sakura
, Windwalker will auto find Foo\Controller\Myflower\GetController
to handle this request.
Routing in Package
If you are writing routing profiles in package, the controller name can be simpler.
# In Flower package
# `src/Flower/routing.yml`
sakura:
pattern: /sakura
controller: Sakura
Then you can register flower package routing to the main etc/routing.yml
.
# etc/routing.yml
# ...
flower:
pattern: /flower
package: flower
After registered flower routing, all routes start with /flower
will be package route, and /flower/sakura
URI will still matched
Flower\Controller\Sakura\Controller
because package will help us find Sakura
controller under this namespace.
See Package -> Routing Section
Routing Params
Methods supported:
Method | Mapped Controller |
---|---|
GET |
GetController |
POST |
SaveController |
PUT |
SaveController |
PATCH |
SaveController |
DELETE |
DeleteController |
HEAD |
HeadController |
OPTIONS |
OptionsController |
NOTE: Windwalker mapped POST, PUT and PATCH to
SaveController
, which includes both create and update action. If you want to separate create and update to two controllers, see next section to override actions.
Override Actions
Add the action attribute:
flower:
pattern: /flower/sakura
controller: Flower\Controller\Sakura
action:
get: IndexController
Then the GET method will match Flower\Controller\Sakura\IndexController
because we set a map to find new name. We can set more
methods to map methods with controllers.
flower:
pattern: /flower/sakura
controller: Flower\Controller\Sakura
action:
get: IndexController
post: CreateController
put: UpdateController
delete: DeleteController
Use |
as OR condition:
flower:
pattern: /flower/sakura
controller: Flower\Controller\Sakura
action:
get|post|put: IndexController
delete: false # false means not allowed
Or use wildcard to map all methods to one controller:
action:
'*': SakuraController
Override Methods
If you want to send PUT
and DELETE
method from web form, you may add _method
params in URL query, this param will override
real HTTP method. For example, send &_method=DELETE
will ask Windwalker to use DeleteController
.
If you feel the HTTP standard methods are not enough to use for you, you can add your custom methods.
action:
export: ExportController
Then use &_method=EXPORT
and the ExportController
will be executed.
Custom Input Variables
pattern: /flower/(id)/(alias)
variables:
foo: bar
The attributes in variables
will auto set to request as default value if this route be matched and there is no same param name in HTTP query.
So if this route matched, you can get foo
value in controller:
$this->input->get('foo'); // bar
But if you type /flower/25/alias?foo=yoo
, then you will get yoo
, the variable will be override by HTTP query.
Extra Params
The variables
will auto set to input request so it is danger to store some sensitive settings in variables
, we can set
extra
params instead.
pattern: /flower/(id)/(alias)
extra:
layout: grid
user:
access: admin
Then you can get this extra params from global config.
// In enywhere
$config = Ioc::getConfig();
$config->get('route.extra.user.access'); // admin
// OR in controller
$this->app->get('route.extra.user.access'); // admin
Hooks
You can add match
and build
hooks to every route.
flower:
pattern: /flower/sakura
controller: Flower\Controller\Sakura
hook:
match: MyRouteHandler::match
build: MyRouteHandler::build
The hook example:
use Windwalker\Core\Router\RestfulRouter;
use Windwalker\Router\Route;
/**
* The MyRouteHelper class.
*
* @since {DEPLOY_VERSION}
*/
class MyRouteHandler
{
/**
* Match hook, will execute after route matched.
*
* @param RestfulRouter $router The Router object.
* @param Route $route The route object.
* @param array $method The method to match route.
* @param array $options The options to match route.
*
* @return void
*/
public static function match(RestfulRouter $router, Route $route, $method, $options)
{
// Do something
}
/**
* Build hook, will execute after every route building.
*
* @param RestfulRouter $router The Router object.
* @param string $route The route name.
* @param array $queries The HTTP query to build route.
* @param string $type Build type, 'raw', 'path' or 'full'.
* @param boolean $xhtml Encode special chars or not.
*
* @return void
*/
public static function build(RestfulRouter $router, &$route, &$queries, &$type, &$xhtml)
{
// Do something
}
}
Allow Methods
The yaml request will be ingnored according if it did not satisfy the given conditions. For example this config will only allow GET and POST, while PUT and DELETE will be ignored.
flower:
pattern: /flower/sakura
controller: Flower\Controller\Sakura
method:
- GET
- POST
Allow scheme
flower:
pattern: /flower/sakura
controller: Flower\Controller\Sakura
method:
- GET
- POST
## Only http & https
scheme: http
post: 80
sslPort: 443
Route Pattern
Simple Params
Use parenthesis ()
to wrap param name.
pattern: /flower/(id)/(alias)
For uri look like : /flower/25/article-alias-name
, above pattern will be matched and there will be two input params.
[id] => 25
[alias] => article-alias-name
Use Requirements to Validate Params
Use Regular Expression to validate type of input. For example \d+
indicates that only Integer
will be accepted as id
input.
pattern: /flower/(id)/(alias)
requirements:
id: \d+
Optional Params
Single Optional Params
Use (/{anyparam})
to wrap an Optional Param.
pattern: flower(/id)
Below 2 uris will be matched simultaneously.
/flower
/flower/25
Multiple Optional Params
pattern: flower(/year,month,day)
All uris below will be matched.
/flower
/flower/2014
/flower/2014/10
/flower/2014/10/12
Matched variables:
Array
(
[year] => 2014
[month] => 10
[day] => 12
)
Wildcards
Use Wildcards to match all the successive params in uri.
pattern: /king/(*tags)
Every param after /king
will all be matched. For example: /king/john/troilus/and/cressida
, will get these variables.
Array
(
[tags] => Array
(
[0] => john
[1] => troilus
[2] => and
[3] => cressida
)
)
Build Route
Every route in Windwalker has a key, which allows every single route pattern can be access by route name or route resources, this will be helpful building a route quickly.
echo \Windwalker\Core\Router\CoreRouter::route('{route name}', array('id' => 25, 'alias' => 'foo-bar-baz'));
The output will be:
{route name}/25/foo-bar-baz
This is a very useful function that you can change roue name but don't need to worry about invalid link.
For further information, see: Route and Redirect
Matchers
Windwalker Router provides some matchers to use different way to match routes.
You can set matcher name in /etc/config.yml
:
routing:
matcher: default
The default matcher is Sequential Matcher.
Sequential Matcher
Sequential Matcher use the Sequential Search Method to find route. It is the slowest matcher but much more customizable. It is the default matcher of Windwalker Router.
Binary Matcher
Binary Matcher use the Binary Search Algorithm to find route. This matcher is faster than Sequential Matcher but it will break the ordering of your routes. Binary search will re-sort all routes by pattern characters.
Trie Matcher
Trie Matcher use the Trie tree to search route. This matcher is the fastest method of Windwalker Router, but the limit is that it need to use an simpler route pattern which is not as flexible as the other two matchers.
Rules of TrieMatcher
Simple Params
only match when the uri segments all exists. If you want to use optional segments, you must add two or more patterns.
/flower
/flower/:id
/flower/:id/:alias
Wildcards
This pattern will convert all segments after /flower
to an array which named tags
:
/flower/*tags
If you found a typo or error, please help us improve this document.