Routes

Routes are stored in a separate file, .e.g routes.php. It should be a regular self-contained PHP-script, any dependencies it need should be included directly in the file as it will be included both from within you application but also by bin/php-routes.

At the global scope the following functions exists:

  • $get to match GET /foo
  • $post to match POST /foo
  • $put to match PUT /foo
  • $delete to match DELETE /foo
  • $resource creates a CRUD resource at /foo
  • $scope creates a new scope /foo

The first four of the functions will create direct routes like $get(‘foo’) will match GET /foo etc. Each function takes a pattern to match and an option array.

$get('foo', [
    'as' => 'foo',
    'to' => 'Foo#get',
]);

In the above example the following routes will be generated as well as the $router->foo_path() method:

NAME    METHOD    PATTERN    TO         REGEXP
foo     GET       /foo       Foo#get    #^/foo(\.\w+)?$#

Patterns

Patterns defines the allowed urls.

When requests are dispatched each pattern is matched (as regexp) in order and the once a hit is found the dispatch calls the appropriate controller and method.

Patterns may contain variables by using : followed by a variable name, e.g. /article/:id will match requests to /article/12. Variables are passed to the dispatcher which may pass them on to the controller.

By default variables matches alphanumerical characters and a few special characters. To change the allowed characters set the _format option.

Given the following routes.php:

$get('article/:id', [
    'as' => 'article',
    'to' => 'Article#show',
    'id_format' => '\d+',
]);

the following routes will be generated:

NAME       METHOD    PATTERN         TO              REGEXP
article    GET       /article/:id    Article#show    #^/article/(\d+)(\.\w+)?$#

The article_path function will be generated but needs an additional argument: the article ID. The ID can be passed in three different ways:

  1. Positional arguments will be applied in order, first argument fills the first variable etc. $router->article_path(12) yields /article/12.
  2. Associative array where variable names will be matched with keys. $router->article_path([‘id’ => 12]) yields /article/12.
  3. Objects where variables names is matched with members. $router->article_path($article) yields /article/12 (assuming $article->id is set to 12).

Extensions

All routes matches an optional file extension. Given the route $get(‘foo’) which normally matches GET /foo it will also match GET /foo.html, GET /foo.json, etc.

Note

The dispatcher may or may not consider the requested extension. It is recommended to use content negotiation for the actual format but the extension can still be used for cosmetic purposes.

CRUD-resouces

When dealing with CRUD-like resources the $resource function can be used:

$resource('article');

The following routes will be generated by default:

NAME               METHOD    PATTERN              TO                 REGEXP
article            GET       /article             Article#index      #^/article(\.\w+)?$#
create_article     POST      /article             Article#create     #^/article(\.\w+)?$#
new_article        GET       /article/new         Article#make       #^/article/new(\.\w+)?$#
update_article     PUT       /article/:id         Article#update     #^/article/(\d+)(\.\w+)?$#
                   PATCH     /article/:id         Article#update     #^/article/(\d+)(\.\w+)?$#
article            GET       /article/:id         Article#show       #^/article/(\d+)(\.\w+)?$#
edit_article       GET       /article/:id/edit    Article#edit       #^/article/(\d+)/edit(\.\w+)?$#
destroy_article    DELETE    /article/:id         Article#destroy    #^/article/(\d+)(\.\w+)?$#

To customize what routes get added use the only or except options, see option for details. The target controller can be set with to without ‘#’, .e.g [‘to’ => ‘Foo’].

Additional routes can be added with a function callback:

$resource('article', ['only' => []], function($r){
    $r->members(function($r){
        $r->get('foo');
    });
    $r->collection(function($r){
        $r->get('bar');
    });
});

which will generate:

NAME    METHOD    PATTERN             TO             REGEXP
        GET       /article/:id/foo    Article#foo    #^/article/(\d+)/foo(\.\w+)?$#
        GET       /article/bar        Article#bar    #^/article/bar(\.\w+)?$#

Scopes

Sometimes many URLs will share a common prefix (with or without variables). Scopes are used to group these urls together:

$scope(':lang', ['lang_format' => 'en|ru|zh'], function($r){
    $r->get('/');
    $r->get('/article/:id');
});

$scope('admin', [], function($r){
    $r->get('edit');
});

The following routes will be generated:

NAME    METHOD    PATTERN               TO               REGEXP
        GET       /:lang                Index#:lang      #^/(en|ru|zh)(\.\w+)?$#
        GET       /:lang/article/:id    Index#article    #^/(en|ru|zh)/article/([A-Za-z0-9\-_\.]+)(\.\w+)?$#
        GET       /admin/edit           Index#edit       #^/admin/edit(\.\w+)?$#

Do note that $scope takes a function with an argument: the scope itself. It has the same methods as the global scope.