-
Notifications
You must be signed in to change notification settings - Fork 0
Dev.Module Route
Introduction
Creating configuration file
Route Class
A 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
,admin
andfeed
; -
priority
field - 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_delimiter
andkey_value_delimiter
- defines the delimiter of url, it will be used in router class. -
defaults
array - describes the default action to request if there is not set thecontroller
andaction
field 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')));