Section: Powerful significant url engine
« basic significant url engine | ^ jUrl: automatic urls |
− Table of content
Here is how you can configure the significant engine for the url system of Jelix.
The configuration principle of this engine is to indicate in a var/config/urls.xml file all the possible url forms in the application, and the actions that will be associated to them. Here is an example of file :
<urls xmlns="http://jelix.org/ns/urls/1.0">
<classicentrypoint name="index" default="true">
<url pathinfo="/news/:annee/:mois/:id-:title" module="news" action="view">
<param name="annee" type="year"/>
<param name="mois" type="month" />
<param name="id" type="number" />
<param name="title" escape="true" />
</url>
<url pathinfo="/articles/:rubrique/:id_art" module="cms" action="show">
<param name="id_art" regexp="\d+"/>
</url>
</classicentrypoint>
<classicentrypoint name="shop">
<url pathinfo="/:category/:product" module="unittest" action="url2">
<param name="product" regexp="\d{2}" />
<static name="mystatic" value="valeur statique" />
</url>
</classicentrypoint>
<classicentrypoint name="foo/bar">
<url handler="urlsig" module="unittest" action="url4" />
</classicentrypoint>
<classicentrypoint name="news">
<url module="news" />
</classicentrypoint>
<xmlrpcentrypoint name="xmlrpc" default="true" />
<jsonrpcentrypoint name="jsonrpc" default="true" />
</urls>
Entrypoint tags ¶
The urls
root tag contains the same number of *entrypoint
tags as entrypoints available in your application. Their exact name gives the type of request they are affected to :
classicentrypoint
for classical request,xmlrpcentrypoint
for xmlrpc- etc...
Each of these tags has a name
attribute specifying the name of the entry point (without the .php extension), or, precisely, its relative path to the basePath
indicated into the main configuration. And you could set eventually a default
attribute specifying if this entry point is the default one for the actual type of request.
Url tag ¶
Each entry point defines one or more possible url forms, knowing that those that are not defined will be accepted on an entry point defined as the default one.
Specify a complete url form ¶
According to a pathinfo ¶
You want to indicate the module and the action to execute for a particular url form. You will then indicate a pathinfo attribute, specifying the model of the pathinfo part the url must be like, and the module and the action in the module and action attributes.
The pathinfo attribute must then contain the value of a pathinfo. In this example, every url with "/foo/bar" pathinfo will correspond to the module and the action indicated.
<url pathinfo="/foo/bar" module="hello" action="world" />
According to a pathinfo with undefined parts ¶
It is possible to indicate "dynamic" parts in the pathinfo. They are defined as two points (:) followed by a name. The retrieved value will then be placed in a paramete with the same name. In the following example, the pathinfo contains two dynamical parts : rubrique
and id_art
.
<url pathinfo="/articles/:rubrique/:id_art" module="cms" action="show" />
If we use the "/articles/aviation/544" url, then the rubrique
and id_art
parameters will be created and will the the "aviation" and "544" value respectively.
Be careful : to avoid the resemblances with other urls, at least one static part is needed (here "/articles/" in the url to distinguish it from the others).
The typed and formatted undefined parts ¶
Another way to avoid resemblances is to specify the format or the type of each parameter. By default, the type is a classical string.
For this, you have to indicate param
tags for each parameter which you want to specify the type/format of. They will have to contain a name
attribute indicating the parameter, and either a type
attribute or a regexp
attribute, containing a regular expression of the format (without delimiter). In our example, we want to specify that rubrique
is a string, and a regular expression for id_art
:
<url pathinfo="/articles/:rubrique/:id_art" module="cms" action="show">
<param name="rubrique" type="string" />
<param name="id_art" regexp="\d+" />
</url>
if the regular expression of the attribute regexp contains parentheses, it's necessary to say that this one should not be catched
Example :
<param name="type" regexp="(?:0|1|2){1}" />When the parameter is of string type, it is not mandatory to specify a param tag. The available types are :
string | a string |
letter | one letter alone |
number | an integer number,equivalent to 'int' et 'integer' too |
digit | a digit |
date | a date according to the AAAA-MM-JJ format |
year | a year on four digits |
month | a month on two digits |
day | a day on two digits |
Notice : you should of course indicate the values of these parameters when calling jUrl.
Static parameters ¶
It can be sometimes necessary to add "static" parameters, awaited by the action (which can be attributed to several different urls), but not present in the url. For this you have to add <static> tags, with value and name like in this example :
<url pathinfo="/:category/:product" module="shop" action="view">
<param name="product" regexp="\d{2}" />
<static name="details" value="0" />
</url>
<url pathinfo="/:category/:product/details" module="shop" action="view">
<param name="product" regexp="\d{2}" />
<static name="details" value="1" />
</url>
Here, we use the same action for two different urls. The processing will be partly different according to the details
parameter. In this case, we would display the product of a catalog, with general characteristics, and in the other its general and detailed characteristics. This avoids to create to different actions for so small difference.
We can use this mechanism for example to support language :
<url pathinfo="/articles/en/:page" module="cms" action="page:view">
<param name="page"/>
<static name="lang" value="en_EN" />
</url>
<url pathinfo="/articles/fr/:page" module="cms" action="page:view">
<param name="page"/>
<static name="lang" value="fr_FR" />
</url>
You should not forget to give the lang parameter to jUrl.
Using an handler ¶
We saw how to use a system to analyse the content of the pathinfo. However, sometimes it is not enough, and we need a more complicated parsing. For example, parts of a pathinfo can be some datas stored in a database, and we need to search in the database this parts to get some ids or whatever..
So in some case, we want to create our own parser, called an "handler" (an other solution is to create a new url engine but it is more complicated).
To create an handler, you create a specific class:
class myHandlerUrlsHandler implements jIUrlSignificantHandler {
function parse($url){
if(preg_match("/^\/(.*)$/",$url->pathInfo,$match)){
$urlact = new jUrlAction($url->params);
$urlact->setParam('page',jUrl::unescape($match[1]));
return $urlact;
}else
return false;
}
function create($urlact, $url){
$p=jUrl::escape($url->getParam('page'));
$url->pathInfo = "/$f";
$url->delParam('page');
}
}
The class name should end by UrlsHandler
, and the name of the handler is the prefix (here "myHandler"). Then the class should be stored in the "classes" directory of a module. The file should be named like prefix
.urlhandler.php. In our example, it should be myhandler.urlhandler.php.
The method parse should parse the url given as argument (a jUrl object). If your handler recognize the url, it should return a jUrlAction object, else it should return false.
The method create is called each time the application ask the url corresponding to an action. This method receive a jUrlAction object and a jUrl object. $urlaction contains the parameters of the action. This parameters are already stored in the $url object. Then you should modify the $url object in order to generate the corresponding true url. So in fact, you should generate the pathinfo, and/or delete some parameters...
Note that you can use jUrl::escape() and jUrl::unescape(), to cleanup strings (by removing some special characters for example).
Then, in the urls.xml file, you have to specify the handler:
<classicentrypoint name="wiki">
<url handler="myHandler" module="unittest" action="url4" />
</classicentrypoint>
Of course, the handler can be stored in any module:
<classicentrypoint name="wiki">
<url handler="othermodule~myHandler" module="unittest" action="url4" />
</classicentrypoint>
The same url for several possible actions ¶
Let's imagine that we have a url of the following type : "/article/54-titre" and this displays the article number 54 with a view action associated for example :
<url pathinfo="/article/:id_art-:title" module="cms" action="view" />
We want to able to indicate other actions in some case without changing the url, with an action parameter :
- "/article/54-titre?action=edit"
- "/article/54-titre?action=delete"
Notice : we could also do /article/54-titre/edit or /article/54-titre/delete, with thus several url tags, which would avoid what follows. But this would not be very good when the url is called by a form for example.
To specify the authorized alternative actions, we add an actionoverride attribute, containing the list of the actions separated by a space or a comma :
<url pathinfo="/article/:id_art-:title" module="cms" action="view" actionoverride="edit,delete" />
Specify that an entry point is dedicated to a particular module ¶
You not always want to indicate a significant url for the actions of particular module. However, you have created an entrypoint dedicated to this module. All these actions will pass through this entry point. You just then have to do it like this :
<classicentrypoint name="news">
<url module="news" />
</classicentrypoint>
Specify some secured urls (https) for specific actions ¶
For some actions, you could want to access them throw an https access. So you should add a https attribute (with "true" as a value) on the <url> elements you want. If you want to specify https on all actions of an entrypoint, then you can put the https attribute on the entrypoint element instead of each url element.
Mod_rewrite and just removing the name of the entry point in the url ¶
Perhaps you would prefer that the parsing of the urls will be done by the web server, by using for example the rewrite mod in Apache.
Full use of mod_rewrite ¶
You can use mod_rewrite to parse the urls and so to rewrite urls to simple urls (index.php?module=...&action=...).
For that, you should inform jelix that it doesn't have to parse the urls:
[urlengine]
..
enableParser = off
However you should create a urls.xml file, so jelix can generate significant urls when your application need it.
In your .htaccess file, you should write all rewrite rules. (see the apache manual).
If you want to define urls which don't contain the entry point (index.php for example), you should tell to Jelix that it musn't insert the entry point into generated urls. So you you have to add entrypoint="true" on the <url> element or on the <*entrypoint> urls.
Just remove the entry point ¶
Perhaps you would like to remove the name of the entry point in the urls generated and parsed by Jelix. But to do it, you have to use and configure the mod_rewrite module of apache.
For example, you want to have
http://monsite.com/news/2007-02-08-il-neige-a-lille.html
instead of
http://monsite.com/index.php/news/2007-02-08-il-neige-a-lille.html
First, in the urls.xml file, put the attribute noentrypoint="true" on the <url> elements or <entrypoint> elements.
Second, you should create a .htacces file in the www directory, which should contains this rules:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L,QSA]
</IfModule>
- second line: you don't need it if you write these instructions into an
.htaccess
in the www directory of your app. However, in an other.htaccess
or in the virtual host configuration, you have to write it, and you must indicate the right path to the www directory:/
if the documentRoot is the www directory, or the path to access this www directory from the documentRoot of the website (basePath). Example:RewriteBase /myapp/www/
if you access to your application withhttp://localhost.local/myapp/www/index.php
- third and forth lines: url will be rewritten only if doesn't correspond to a real file or a real directory. (for css files, images etc..).
- fifth line: we get all the content of the url and put it after index.php/, so the url become the pathinfo of the new url.
In some apache configuration, you could have an apache error "Error: No input file specified" (this is the case for example when PHP is executed in cgi mode and cgi.fix_pathinfo=0 in php.ini).
Since Jelix 1.0.2, there is a solution. You should change the last rule to:
RewriteRule ^(.*)$ index.php?jpathinfo=/$1 [L,QSA]
So the url is not put as the pathinfo, but as a query parameters. Of course, you should inform jelix of this parameter. You have to add the pathInfoInQueryParameter parameter in the urlengine section in the jelix configuration file. pathInfoInQueryParameter should contains the name of the parameter (here in the example, jpathinfo)
[urlengine]
...
pathInfoInQueryParameter = jpathinfo