Router

Routing can be used in addition to the default mechanism that associates controller/action/{parameters} with an url.

Dynamic routes

Dynamic routes are defined at runtime.
It is possible to define these routes in the app/config/services.php file.

Important

Dynamic routes should only be used if the situation requires it:

  • in the case of a micro-application
  • if a route must be dynamically defined

In all other cases, it is advisable to declare the routes with annotations, to benefit from caching.

Callback routes

The most basic Ubiquity routes accept a Closure.
In the context of micro-applications, this method avoids having to create a controller.

app/config/services.php
1
2
3
4
5
     use Ubiquity\controllers\Router;

     Router::get("foo", function(){
             echo 'Hello world!';
     });

Callback routes can be defined for all http methods with:

  • Router::post
  • Router::put
  • Router::delete
  • Router::patch
  • Router::options

Controller routes

Routes can also be associated more conventionally with an action of a controller:

app/config/services.php
1
2
3
     use Ubiquity\controllers\Router;

     Router::addRoute("bar", \controllers\FooController::class,'index');

The method FooController::index() will be accessible via the url /bar.

In this case, the FooController must be a class inheriting from UbiquitycontrollersController or one of its subclasses, and must have an index method:

app/controllers/FooController.php
1
2
3
4
5
6
7
8
     namespace controllers;

     class FooController extends ControllerBase{

             public function index(){
                     echo 'Hello from foo';
             }
     }

Default route

The default route matches the path /.
It can be defined using the reserved path _default

app/config/services.php
1
2
3
     use Ubiquity\controllers\Router;

     Router::addRoute("_default", \controllers\FooController::class,'bar');

Static routes

Static routes are defined using the @route annotation on controller methods.

Note

These annotations are never read at runtime.
It is necessary to reset the router cache to take into account the changes made on the routes.

Creation

app/controllers/ProductsController.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
namespace controllers;
 /**
 * Controller ProductsController
 **/
class ProductsController extends ControllerBase{

     /**
     * @route("products")
     */
     public function index(){}

}

The method Products::index() will be accessible via the url /products.

Route parameters

A route can have parameters:

app/controllers/ProductsController.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
namespace controllers;
 /**
 * Controller ProductsController
 **/
class ProductsController extends ControllerBase{
     ...
     /**
     * Matches products/*
     *
     * @route("products/{value}")
     */
     public function search($value){
             // $value will equal the dynamic part of the URL
             // e.g. at /products/brocolis, then $value='brocolis'
             // ...
     }
}

Route optional parameters

A route can define optional parameters, if the associated method has optional arguments:

app/controllers/ProductsController.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
namespace controllers;
 /**
 * Controller ProductsController
 **/
class ProductsController extends ControllerBase{
     ...
     /**
     * Matches products/all/(.*?)/(.*?)
     *
     * @route("products/all/{pageNum}/{countPerPage}")
     */
     public function list($pageNum,$countPerPage=50){
             // ...
     }
}

Route requirements

php being an untyped language, it is possible to add specifications on the variables passed in the url via the attribute requirements.

app/controllers/ProductsController.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
namespace controllers;
 /**
 * Controller ProductsController
 **/
class ProductsController extends ControllerBase{
     ...
     /**
     * Matches products/all/(\d+)/(\d?)
     *
     * @route("products/all/{pageNum}/{countPerPage}","requirements"=>["pageNum"=>"\d+","countPerPage"=>"\d?"])
     */
     public function list($pageNum,$countPerPage=50){
             // ...
     }
}
The defined route matches these urls:
  • products/all/1/20
  • products/all/5/
but not with that one:
  • products/all/test

Route http methods

It is possible to specify the http method or methods associated with a route:

app/controllers/ProductsController.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
namespace controllers;
 /**
 * Controller ProductsController
 **/
class ProductsController extends ControllerBase{

     /**
 * @route("products","methods"=>["get"])
 */
     public function index(){}

}

The methods attribute can accept several methods:
@route("testMethods","methods"=>["get","post","delete"])

It is also possible to use specific annotations @get, @post
@get("products")

Route name

It is possible to specify the name of a route, this name then facilitates access to the associated url.
If the name attribute is not specified, each route has a default name, based on the pattern controllerName_methodName.

app/controllers/ProductsController.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
namespace controllers;
 /**
 * Controller ProductsController
 **/
class ProductsController extends ControllerBase{

     /**
     * @route("products","name"=>"products_index")
     */
     public function index(){}

}

URL or path generation

Route names can be used to generate URLs or paths.

Linking to Pages in Twig

<a href="{{ path('products_index') }}">Products</a>

Global route

The @route annotation can be used on a controller class :

app/controllers/ProductsController.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
namespace controllers;
 /**
 * @route("/product")
 * Controller ProductsController
 **/
class ProductsController extends ControllerBase{

 ...
     /**
 * @route("/all")
 **/
     public function display(){}

}

In this case, the route defined on the controller is used as a prefix for all controller routes :
The generated route for the action display is /product/all

automated routes

If a global route is defined, it is possible to add all controller actions as routes (using the global prefix), by setting the automated parameter :

app/controllers/ProductsController.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
namespace controllers;
 /**
 * @route("/product","automated"=>true)
 * Controller ProductsController
 **/
class ProductsController extends ControllerBase{

     public function generate(){}

     public function display(){}

}

inherited routes

With the inherited attribute, it is also possible to generate the declared routes in the base classes, or to generate routes associated with base class actions if the automated attribute is set to true in the same time.

The base class:

app/controllers/ProductsBase.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
namespace controllers;
 /**
 * Controller ProductsBase
 **/
abstract class ProductsBase extends ControllerBase{

     /**
     *@route("(index/)?")
     **/
     public function index(){}

     /**
     *@route("sort/{name}")
     **/
     public function sortBy($name){}

}

The derived class using inherited attribute:

app/controllers/ProductsController.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
namespace controllers;
 /**
 * @route("/product","inherited"=>true)
 * Controller ProductsController
 **/
class ProductsController extends ProductsBase{

     public function display(){}

}
The inherited attribute defines the 2 routes contained in ProductsBase:
  • /products/(index/)?
  • /products/sort/{name}

If the automated and inherited attributes are combined, the base class actions are also added to the routes.

Route priority

The prority parameter of a route allows this route to be resolved more quickly.

The higher the priority parameter, the more the route will be defined at the beginning of the stack of routes in the cache.

In the example below, the products/all route will be defined before the /products route.

app/controllers/ProductsController.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
namespace controllers;
 /**
 * Controller ProductsController
 **/
class ProductsController extends ControllerBase{

     /**
 * @route("products","priority"=>1)
 */
     public function index(){}

     /**
 * @route("products/all","priority"=>10)
 */
     public function all(){}

}

Routes response caching

It is possible to cache the response produced by a route:

In this case, the response is cached and is no longer dynamic.

/**
* @route("products/all","cache"=>true)
*/
public function all(){}

Cache duration

The duration is expressed in seconds, if it is omitted, the duration of the cache is infinite.

    /**
* @route("products/all","cache"=>true,"duration"=>3600)
*/
    public function all(){}

Cache expiration

It is possible to force reloading of the response by deleting the associated cache.

Router::setExpired("products/all");

Dynamic routes caching

Dynamic routes can also be cached.

Important

This possiblity is only useful if this caching is not done in production, but at the time of initialization of the cache.

Router::get("foo", function(){
        echo 'Hello world!';
});

Router::addRoute("string", \controllers\Main::class,"index");
CacheManager::storeDynamicRoutes(false);

Checking routes with devtools :

Ubiquity info:routes
../_images/ubi-version.png