-
Couldn't load subscription status.
- Fork 0
Dev.Module Route
IntroductionCreating configuration fileRoute ClassA Simple Case To Create Custom Route
What is a router? Before answer this question, we should introduce something else. Generally, we access a page by inputting the file path into browser such as localhost/index.html, this is almost used in static pages. In dynamic page, especial in MVC, a page is define as a controller/action, so user can not use file name as url path to access the page. Users must put the controller and action information into the url and then framework will resolve the url and then access the right controller/action, and return data. A router is such a method used to assemble url by passed parameter and resolve the url to right action.
The following flow chart is a simple introduction on url resolving of Pi:
Create router instance -> Reading all routers from database -> Trigger route event
Route event: this event will match all existing router with current url, if the url is match correctly,
the router and passed parameters will be saved into Zend\Mvc\Router\RouteMatch instance.
If a user want to create custom router, the following thing must be done:
- Adding a route configuration in module;
- Creating route class for url assembling and route resloving;
- Assembling url.
A configuration is generally known as route.php in config folder, this configuration will helps defining basic route information and adding router into database (core_route table). Therefore the application will get the router and add it into routers parameter for later use.
config/route.php
return array(
'default' => array(
'section' => 'front',
'priority' => -999,
'type' => 'Standard',
'options' =>array(
'structure_delimiter' => '/',
'param_delimiter' => '/',
'key_value_delimiter' => '-',
'defaults' => array(
'module' => 'system',
'controller' => 'index',
'action' => 'index',
)
)
),
);
In this code, the default field is the route name:
-
section- decides which section's action to request, it can befront,adminandfeed; -
priorityfield - defines the priority of the url resolving, the smaller digit the lower priority, generally we recommend set lower priority to the common router.
The type field defines which class is used to resolve the url, there has three types recommend, which are: Standard, Home and User. If user want to create custom router, other name should be used, such as: Module\Channel\Route\Channel.
The options array defines how to display the url:
-
structure_delimiter,param_delimiterandkey_value_delimiter- defines the delimiter of url, it will be used in router class. -
defaultsarray - describes the default action to request if there is not set thecontrollerandactionfield in navigation file.
A route class is custom class inherit from Pi\Mvc\Router\Http\Standard class. This class contains two method which is used to assemble url and match url, it will be call automatically when application runs.
A module custom route class should be created in the Route folder of module, such as:
usr
|-- module
|-- channel
|-- src
|-- Route
|-- Channel.php
This class must has a name match to that declares in configuration files. This structure of this class is:
namespace Module\{Module name}\Route;
use Pi\Mvc\Router\Http\Standard;
use Zend\Mvc\Router\Http\RouteMatch;
use Zend\Stdlib\RequestInterface as Request;
use Pi;
class {Route name} extend Standard
{
protected $prefix = '';
protected $defaults = array(
'module' => {module name},
'controller' => {controller name},
'action' => {action name},
);
public function match(Request $request, $pathOffset = null)
{
$result = $this->canonizePath($request, $pathOffset);
// Route not match
if (null === $result) {
return null;
}
list($path, $pathLength) = $result;
// Add yourselves route matching codes
...
// Route matched
return new RouteMatch(array_merge($this->defaults, $matches), $pathLength);
}
public function assemble(array $params = array(), array $options = array())
{
$mergedParams = array_merge($this->defaults, $params);
if (!$mergedParams) {
return $this->prefix;
}
// Adding yourselves assemble codes
...
return $this->paramDelimiter . $url;
}
}
In the class the prefix and defaults parameters will be overridden by the value defines in configuration. The prefix parameter is used to assemble url, and it can be null, the defaults parameter defines the default action to access if no controller and action is resolved in match method.
The match method will override the same method define in Standard class, it is used to match url. In the method, the canonizePath method is used to resolve path and its length.
The return null will tell the application the url not match this route, and application will choose the next route to match, and the return new RouteMatch tell the application this route is match with the url, and the resolving data will be passed to the RouteMatch instance.
note: the $match parameter contain resolving data, such as action, module or other parameters post by GET method.
In the assemble method, parameters passed to assemble url are assign to $params, users can assemble url by these parameters and return.
In this case, we will introduce how to add a custom route step by step. A demo module will be took as an example, and its Slug route will resolve a url such as:
-
url/$id-$slug; -
url/$id; -
url/$slug.
defining configuration files
module/demo/config/route.php
return array(
'slug' => array(
'section' => 'front',
'priority' => 1,
'type' => 'Module\\Demo\\Route\\Slug',
'options' => array(
'prefix' => '/demo-route',
'defaults' => array(
'module' => 'demo',
'controller' => 'route',
'action' => 'slug'
),
),
),
);
module/demo/config/module.php
The configuration file should be added into module.php after create.
return array(
...
'route' => 'route.php',
);
Then a route class should be created to achieve route assembling and matching. Creating the following file and add codes.
module/demo/src/Route/Slug.php
namespace Module\Demo\Route;
use Pi\Mvc\Router\Http\Standard;
use Zend\Mvc\Router\Http\RouteMatch;
use Zend\Stdlib\RequestInterface as Request;
class Slug extends Standard
{
protected $prefix = '/demo-route';
protected $defaults = array(
'module' => 'demo',
'controller' => 'route',
'action' => 'slug'
);
public function match(Request $request, $pathOffset = null)
{
$result = $this->canonizePath($request, $pathOffset);
if (null === $result) {
return null;
}
list($path, $pathLength) = $result;
if (empty($path)) {
return null;
}
// Adding matching codes
list($id, $slug) = array(null, null);
if (false === ($pos = strpos($path, '-'))) {
if (is_numeric($path)) {
$id = $path;
} else {
$slug = $path;
}
} else {
list($id, $slug) = explode('-', $path, 2);
if (!is_numeric($id)) {
$id = null;
$slug = $path;
}
}
// Assigning match parameters
$matches = array(
'action' => (null === $slug) ? 'id' : 'slug',
'id' => $id,
'slug' => urldecode($slug),
);
return new RouteMatch(array_merge($this->defaults, $matches), $pathLength);
}
public function assemble(array $params = array(), array $options = array())
{
$mergedParams = array_merge($this->defaults, $params);
if (!$mergedParams) {
return $this->prefix;
}
$url = isset($mergedParams['id']) ? intval($mergedParams['id']) : '';
if (isset($mergedParams['slug'])) {
$url .= ($url ? '-' : '') . urlencode($mergedParams['slug']);
}
return $this->paramDelimiter . trim($this->prefix, $this->paramDelimiter) . $this->paramDelimiter . $url;
}
}
So far, we have achieved the custom route Slug, users should reinstall the module to enable this route.
Now let's learn how to get custom url, it is very simple by using $this->url() in action method or phtml
file.
In action and template:
echo $this->url('demo-slug', array('id' => 88453));
echo $this->url('demo-slug', array('slug' => 'hello'));
echo $this->url('demo-slug', array(
'id' => '63354',
'slug' => 'nice',
));
The codes will call assemble method, and output:
'domain/demo-route/88453'
'domain/demo-route/hello'
'domain/demo-route/63354-nice'
We can notice that, the route name is consist by module name and route name, if the above code is
used in demo module, the demo- can be replaced by ..
In demo module:
$this->url('.slug', array('id' => 88453));
If assemble url is not realize in action and template, using the following code:
Pi::engine()->application()
->getRouter()
->assemble(array('id' => 88453, array('name' => 'demo-slug')));