The router is a system that Matches a request and extracts variables. The router class is responsible for loading up the correct controller. It does nothing else. The value of the controller comes from the URL. In Zend Framework 2 routing function is changed significantly. This will give developers a little weary and heavy for writing routing rules, however it makes applications run faster ZF2. This component of the framework has been rewritten from scratch and it’s really powerful and flexible, allowing you to create a lot of combination of routes. The main functionality of the router is matching a request to a given controller/action. It also assembles URLs based on the defined routes. This process is accomplished by inspecting the URI and attempting to match it with a given route that has some constraints, or by generating the URL based on the parameters defined on the routes.
The general flow of this component is as follows:
- A request arrives and the framework creates a request object
- Then the route parses the URI to identify the segments
- After that the router iterates through the list of routes previously ordered
- On each iteration, the segments of the URI are checked to see if it matches the current route
- When a route matches the URI, the request is dispatched to the specific controller and action is configured on the route
First we need to understand the URL structure. A typical URL from an HTTP request consists of segments. The segments are URL parts delimited by slash characters (‘/’): there are scheme, host name, path and query segments. For example, let’s look at the URL http://subdomain.yoursite.com/path/to/page?query=Search See Below:
Fig: Typical URL Structure
We seen the above URL begins with a scheme segment (the scheme typically looks like http or https).Then, the host name segment follows which is the domain name of your web server (like subdomain.yoursite.com). Optional path segments follow the host name. So if you have the path part “/path/to/page” then “path”, “to”, and “page” would each be a URL segment. Next, after the question mark, the optional query part follows. It consists of one or several “name=value” parameters separated from each other by an ampersand character (‘&’).
Each segment in a URL uses special character encoding, which is named the URL encoding. This encoding ensures that the URL contains only “safe” characters from the ASCII ¹ table. If a URL contains unsafe characters, they are replaced with a percentage character (‘%’) followed by two hexadecimal digits (for example, the space character will be replaced by ‘%20’).
There are several standard route types provided by Zend Framework 2 . These route types are implemented as classes living in the Zend\Mvc\Router\Http namespace.
Here is a detailed view of all of them.
'routeTestHostname' => array( 'type' => 'hostname', 'options' => array( 'route' => ':subdomain.site.com', 'defaults' => array( 'controller' => 'routeTest', 'action' => 'hostname', ), ), ),
Sample Example: http://subdomain.yoursite.com/
This is a usage example of how to configure a Hostname route. In the route parameter, we specify thehostname to match in the URI. Also, you can set up parameters, such as subdomain in this case.
You can set up constraints and default values on the route; in this particular example, we are specifying a regular expression that will limit the matching of the route to all the subdomains starting with the letters fwand followed by two digits. Sometimes you will need to pass values to the controllers based on the URL or define some default values for parameters on the URL. In this example we are setting the default value of type to the json string.
This route will match a URI path literally as specified by the route parameter. As usual, the default data will be the parameters you want returned on a match. This route is the easiest to understand and implement. Verification relates to a rough comparison of the route warp chain. This type of rout is very fast because it simply checks requests verification of equality:
'routeTestLiteral' => array( 'type' => 'Literal', 'options' => array( 'route' => '/route-test', 'defaults' => array( 'controller' => 'routeTest', 'action' => 'literal', ), ), ),
Sample Output: //http://yoursite.com/route-test
This type of route will match if the HTTP method used on the request matches the one configured in the route using the verb parameter. We can specify multiple methods on the same route if we separate them with comma.
// maches post methhod 'routeTestPost' => array( 'type' => 'Method', 'options' => array( 'verb' => 'post', 'defaults' => array( 'action' => 'methodpost' ), ), ), // maches get,head,put,delete methhods 'routeTestGetPut' => array( 'type' => 'Method', 'options' => array( 'verb' => 'get,head,put,delete', 'defaults' => array( 'action' => 'methodget' ), ), ),
A Regex route will be based on a regular expression test match of the URI. You need to specify regex in the regex parameter and it can be any valid regular expression.
When working with this route we have to keep two things in mind. The first one is to use named captures on regex for any value we want to return as parameter on a match, the second is that we need to specify a value for the spec parameter to map each regex capture to the specific parameter. This will be used by the URL helper when building URLs based on the routes. For instance:
'routeTestRegex' => array( 'type' => 'Regex', 'options' => array( 'regex' => '/route-test/page-(?<id>[0-9]+).html', 'spec' => '/route-test/%id%', 'defaults' => array( 'controller' => 'routeTest', 'action' => 'regex', ), ), ),
Sample Output: http://yoursite.com/route-test/page-33.html
In the previous example, you will notice that regex is using named captures enclosed in <> and we are specifying the format of the URL in the spec parameter, identifying each parameter with a text between percentage symbols. This will help the router to put the value of the parameters in the correct place in the URL while assembling it.
The Scheme route type will match a URI based only on the URI scheme. This route type is similar to theLiteral route because the match has to be exact and will return the default parameters on a successful match.
'routeTestScheme' => array( 'type' => 'scheme', 'options' => array( 'scheme' => 'https', 'defaults' => array( 'https' => true, 'controller' => 'routeTest', 'action' => 'scheme',
Sample Output: https://yoursitename.com
As you can see in the previous code example, if the route matches, we will return a parameter called httpswith a true value.
'routeTestSegment' => array( 'type' => 'Segment', 'options' => array( 'route' => '/route-test[/:controller][/:action][/:id]', 'constraints' => array( 'controller' => '[a-zA-Z][a-zA-Z0-9_-]*', 'action' => '[a-zA-Z][a-zA-Z0-9_-]*', 'id' => '[0-9]+', ), 'defaults' => array( 'controller' => 'routeTest', 'action' => 'default', ), ), ),
Sample Output: http://site.com/route-test/controller/action/34
This is an example of how to use the Segment route that will allow us to match against any segment of the URI path. In the route parameter, the segments are defined using a specific notation; this is a colon followed by alphanumeric characters. The segments on a URI can be optional and that will be denoted by enclosing the segment in brackets.
Each segment must have constraints associated with it; the constraint will be a regular expression defining the requirements for a positive match.
This type of route allows you to get all the segments of a URI specifying the separator between keys and values. Consider the following code example to get a better understanding:
'route_name' => array( 'type' => 'Zend\Mvc\Router\Http\Wildcard', 'options' => array( 'key_value_delimiter' => '/', 'param_delimiter' => '/', ) )
That’s how the route looks when configured, and it will work like this. If you have a URI such as/id/1/name/john, this route will return the two variables id and name. The first one will contain the number1 and the second will contain the string john.
Combining Route Types
Routes may be combined with the help of “aggregate” route types (shown in below). The compound route types allow defining arbitrarily complex URL mapping rules.
This is a basic router that gets all the configured routes and loops through them in a LIFO order until a match is found. The routes have priority and as the router is looping them in a LIFO order, the routes that are more likely to be matched (the ones that match more often) should be registered last, and the one that matches less should be registered first. Also, an easy way to set up the priority of the routes is using the third parameter of the AddRoute() method.
$router->addRoute('foo', $route, 10);
That’s an example of how you can specify priorities on routes; just pass a number and the routes will be ordered by those values.
This router is a little bit more complex than SimpleRouteStack because this allows you to create a tree of routes and will use a binary-tree algorithm to match the routes. The basic configuration of a TreeRouteStack route will consist of the following:
- A base route that will be the root of the tree and all the following routes will extend this one.
- An optional configured instance of RoutePluginManager to be able to lazy-load routes.
- Another optional parameter will be may_terminate that tells the router that no other route will follow this one.
- Finally, a child_routes array that can also be optional. If we specify routes here, they will extend the main one; also, a child route can be another TreeRouteStack.
You can add routes one by one on both routers by using the AddRoute() method or in batches using AddRoutes().
$route = Part::factory(array( 'route' => array( 'type' => 'literal', 'options' => array( 'route' => '/', 'defaults' => array( 'controller' => 'Application\Controller\IndexController', 'action' => 'index' ) ), ), 'child_routes' => array( 'forum' => array( 'type' => 'literal', 'options' => array( 'route' => 'forum', 'defaults' => array( 'controller' => 'Application\Controller\ForumController', 'action' => 'index' ) ) ) ) ));
As you can see, the first route we defined is the home page – the root of the domain. Then we defined the route for the forum extending from the base one.
A Part route allows crafting a tree of possible routes based on segments of the URI path. It actually extends the TreeRouteStack. Part routes are difficult to describe, so we’ll simply provide a sample one here.
<?php $route = <b>new</b> Http\Part(<b>new</b> Http\Literal( '/bacon', <b>array</b>('controller' => 'bacon') ), <b>true</b>); $route->addRoutes(<b>array</b>( 'definition' => <b>new</b> Http\Segment( '/is/:something' ), 'greater' => <b>new</b> Http\Literal( '/greater-than-cookies' <b>array</b>('controller' => 'cookies') ), ));
Aggregates different route types in a chain (degenerated subtree).
Shortly The TreeRouteStack and SimpleRouteStack are used as the “top-level” route types. The SimpleRouteStack allows organizing different routing rules in a priority list. The TreeRouteStack allows nesting different routing rules, forming a “tree. Below shown the route class inheritance diagram.
Fig: Route class inheritance diagram
The SimpleRouteStack is a parent class for TreeRouteStack class, which inherits the behavior of the simple route stack (allows to organize routes in priority list) and extends it (allows to organize routes in subtrees). The Part and Chain classes are derived from TreeRouteStack class and are used internally by the TreeRouteStack for building subtrees and chains of child routes.
Note: the SimpleRouteStack class lives in the Zend\Mvc\Router namespace, while other route classes live in its sub-namespace Zend\Mvc\Router\Http.
zend framework 2 routing