Routing maps Request URI to a specific controller's method. In this chapter, we will see how to implement the routes in a Zend Framework.
In general, any URI has three parts −
For example, in URI / URL − http://www.example.com/index?q=data, www.example.com is the Hostname Segment, index is the Path Segment and q=data is the Query Segment. Generally, routing checks the Page segment against a set of constrain. If any constrain matches, then it returns a set of values. One of the main value is the controller.
Routing also checks the host segment, query segment, request HTTP methods, request HTTP headers, etc., in a certain situation.
Route is the main object in routing. Zend Framework has a special interface for route object, RouteInterface. All route object needs to implement RouteInterface. The complete listing of the RouteInterface is as follows −
namespace Zend\Mvc\Router; use Zend\Stdlib\RequestInterface as Request; interface RouteInterface { public static function factory(array $options = []); public function match(Request $request); public function assemble(array $params = [], array $options = []); }
The main method is match. This match method checks the given request against the constrain defined in it. If any match is found, it returns the RouteMatch object. This RouteMatch object provides the details of the matched request as parameters. These parameters can be extracted from RouteObject using the getParams method.
The complete listing of the RouteObject is as follows −
namespace Zend\Mvc\Router; class RouteMatch { public function __construct(array $params); public function setMatchedRouteName($name); public function getMatchedRouteName(); public function setParam($name, $value); public function getParams(); public function getParam($name, $default = null); }
In general, a typical MVC application has many routes. Each of this route will be processed in LIFO order and a single route will be matched and returned. If no route is matched / returned, then the application returns “Page not found” error. Zend Framework provides an interface to process the routes, RouteStackInterface. This RouteStackInterface has the option to add / remove routes.
The complete listing of the RouteStackInterface is as follows −
namespace Zend\Mvc\Router; interface RouteStackInterface extends RouteInterface { public function addRoute($name, $route, $priority = null); public function addRoutes(array $routes); public function removeRoute($name); public function setRoutes(array $routes); }
Zend framework provides two implementations of the RouteStack interface and they are as follows −
Zend framework provides a lot of readymade route objects for all the situations under "Zend\Mvc\Router\Http" namespace. It is enough to select and use proper route object for the given situation.
The available routes are as follows −
Hostname − Used to match host part of the URI.
Literal − Used to match exact URI.
Method − Used to match HTTP method of the incoming request.
Part − Used to match the part of the URI path segment using custom logic.
Regex − Used to match the URI path segment by Regex Pattern.
Schema − Used to match the URI Schema such as http, https, etc.
Segment − Used to match URI path by splitting it into multiple segment.
Let us see how to write the most commonly used literal and segment Route. Routes are usually specified in each module's configuration file – module.config.php.
Typically, routes are queried in a LIFO order. The Literal route is for doing the exact matching of the URI path.
It is defined as shown below −
$route = Literal::factory(array( 'route' => '/path', 'defaults' => array('controller' => 'Application\Controller\IndexController', 'action' => 'index',), ));
The above route matches the /path in the request url and returns index as the action and IndexController as controller.
A segmented route is used for whenever your url is supposed to contain variable parameters.
It is described as given below −
$route = Segment::factory(array( 'route' => '/:controller[/:action]', 'constraints' => array( 'controller' => '[a-zA-Z][a-zA-Z0-9_-]+', 'action' => '[a-zA-Z][a-zA-Z0-9_-]+', ), 'defaults' => array( 'controller' => 'Application\Controller\IndexController', 'action' => 'index',), ));
Here, Segments are denoted by a colon and followed by alphanumeric characters. If you keep a segment is optional then it is enclosed by brackets. Each segment may have constraints associated with it. Each constraint is a regular expression.
Let us add a segment route in our Tutorial module. Update the tutorial module configuration file – module.config.php available at myapp/module/Tutorial/config.
<?php namespace Tutorial; use Zend\ServiceManager\Factory\InvokableFactory; use Zend\Router\Http\Segment; return [ 'controllers' => [ 'factories' => [ Controller\TutorialController::class => InvokableFactory::class, ], ], 'router' => [ 'routes' => [ 'tutorial' => [ 'type' => Segment::class, 'options' => [ 'route' => '/tutorial[/:action[/:id]]', 'constraints' => [ 'action' => '[a-zA-Z][a-zA-Z0-9_-]*', 'id' => '[0-9]+', ], 'defaults' => [ 'controller' => Controller\TutorialController::class, 'action' => 'index', ], ], ], ], ], 'view_manager' => [ 'template_path_stack' => ['tutorial' => __DIR__ . '/../view',], ], ];
We have successfully added the routing for our Tutorial module. We are just one step behind in completing our Tutorial module. We need to add View for our module, which we will learn in the subsequent chapter.