− Table of content
The configuration principle of this engine is to indicate in a
app/system/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">
<entrypoint name="index" default="true">
<url pathinfo="/" module="main" action="default:index" />
<url module="main" />
<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>
</entrypoint>
<entrypoint name="shop" type="classic">
<url pathinfo="/:category/:product" module="unittest" action="url2">
<param name="product" regexp="\d{2}" />
<static name="mystatic" value="valeur statique" />
</url>
</entrypoint>
<classicentrypoint name="foo/bar">
<url handler="urlsig" module="unittest" action="url4" />
</classicentrypoint>
<classicentrypoint name="news">
<url module="news" />
</classicentrypoint>
<entrypoint name="xmlrpc" default="true" type="xmlrpc"/>
<entrypoint name="jsonrpc" default="true" type="jsonrpc"/>
</urls>
Entrypoint tags ¶
The urls
root tag contains the same number of entrypoint
tags as
entrypoints available in your application.
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.
An entrypoint
tag should also have a type
attribute which indicates
the type of the entry point : classic
, xmlrpc
, soap
etc. If this
attribute is not present, the default value is classic
.
For compatibility reasons with older version of jelix, you can use other name
for entrypoint
elements. Their exact name gives the type of request they
are affected to:
classicentrypoint
for classical request,xmlrpcentrypoint
for xmlrpc- etc...
However this kind of names are now deprecated.
Url tag ¶
Each module is accessible through a specific entry point, so you should declare urls of modules in the corresponding entry point element.
Specify the default action, the homepage ¶
Every application has an homepage at the /
url.
So you have at least one url to define on each "classic" entry points:
<urls xmlns="http://jelix.org/ns/urls/1.0">
<entrypoint name="index" default="true">
<url pathinfo="/" module="main" action="default:index" />
</entrypoint>
</url>
So here the url index.php/
correspond to the method index
of the controller
default
in the module main
.
Before Jelix 1.7, the home page was defined in the startModule
and startAction
parameters in the configuration of each entry points.
Automatic urls for modules ¶
As you will see below, you can define url for each action. But it is not required.
By default, urls are like <entrypoint>.php/<module>/<controller>/<method>
.
You have at least to indicate on which entry point the module is
accessible, and so to specify the url tag for module
: a <url>
indicating
only a module name.
<entrypoint name="index" default="true">
<url pathinfo="/" module="main" action="default:index" />
<url module="main" />
</entrypoint>
<entrypoint name="blog">
<url module="news" />
</entrypoint>
Here all urls of the news
module are like blog.php/blog/<controller>/<method>
.
You can also indicate a pathinfo: it then replaces the module name into the url.
With this example:
<entrypoint name="index" default="true">
<url pathinfo="/" module="main" action="default:index" />
<url pathinfo="/awesome/informations/" module="news" />
</entrypoint>
The urls of the news
module are like index.php/awesome/informations/<controller>/<method>
.
If there isn't an url tag for module
for a specific module, only actions of this module
that are defined by an url tag for action
, will be accessible from the web.
In the previous example, there is only one action for the main
module that is defined,
in an url tag, with the pathinfo /
, so only the default:index
will be accessible
from the web. For any other actions of the module main
, you should also declare
an url tag, or you can define <url module="main" />
to automatically declare automatic
url for other actions.
If there isn't no url tag that targets a module, the actions of this module will be accessible by the default entry point.
Automatic urls for controllers ¶
You can define a pathinfo for a controller, and then the method name is the last component of the path.
On an url tag, you have to indicate the module, the pathinfo, and the controller in a
controller
attribute.
<entrypoint name="index" default="true">
<!-- ... -->
<url pathinfo="/cool" module="main" controller="system" />
</entrypoint>
Urls of all actions of the controller system
, will be like index.php/cool/<method>
.
Specifying url for actions ¶
According to a pathinfo ¶
You want to indicate the module and the action to execute for a particular url.
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 indicated module
and action .
<url pathinfo="/foo/bar" module="hello" action="world" />
You can set the attribute optionalTrailingSlash="true"
if you want that if
there is a trailing slash or not, it correspond to the same action, ie,
/foo/bar/
and /foo/bar
are the same action (by default, it is not the
case). You can set this attribute on the entrypoint
element, so all it is
activated for all defined urls.
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
parameter with the same name for the controller. In the following example, the
pathinfo contains two dynamical parts: chapter
and id_art
.
<url pathinfo="/articles/:chapter/:id_art" module="cms" action="default:show" />
If we use the "/articles/planes/544" url, then the chapter
and id_art
parameters will be created and will have the "planes" and "544" value
respectively.
Be careful: to avoid the confusion 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 chapter
is a string, and
a regular expression for id_art
:
<url pathinfo="/articles/:chapter/:id_art" module="cms" action="show">
<param name="chapter" 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 |
path | a sub-path of the url. this parameter must be the last one in the URL |
lang | lang code (2 or 3 letters) |
locale | locale code (lang code + country code) |
Notice: you must 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>
elements, 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 catalogue, with general characteristics, and in the
other its general and detailed characteristics. This avoids to create two
different actions for so small differences.
We can use this mechanism to support language, for instance:
<url pathinfo="/articles/en/:page" module="cms" action="page:view">
<param name="page"/>
<static name="lang" value="en_US" />
</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.
jUrl::get('cms~page:view', array('page'=>'foo', 'lang'=>jApp::config()->locale));
// or
jUrl::get('cms~page:view', array('page'=>'foo', 'lang'=>"en_US"));
<a href="{jurl 'cms~page:view', array('page'=>'foo', 'lang'=>$j_locale}">my link</a>
<a href="{jurl 'cms~page:view', array('page'=>'foo', 'lang'=>'fr_FR'}">my link</a>
Automatic parameters for language ¶
with static parameters ¶
We saw that we could declare static parameters containing the code of the language, to have different URLs pointing to the same action. However, it causes some issues:
- you have to give the parameter to
jUrl::get()
, and in most of case, you use the current language code (jApp::config()->locale
). - in the action you have to set yourself the language code in the configuration, with the given value in the parameter.
The url engine brings some improvements about these issues. You just have to add the
attribute type="locale"
or type="lang"
, and then, everything is automatic.
You can define for example:
<url pathinfo="/articles/english/:page" module="cms" action="page:view">
<param name="page"/>
<static name="lang" value="en_US" type="locale"/>
</url>
<url pathinfo="/articles/francais/:page" module="cms" action="page:view">
<param name="page"/>
<static name="lang" value="fr_FR" type="locale" />
</url>
If you call simply jUrl::get('cms~page:view', array('page'=>'foo'))
, then jUrl
will generate /articles/english/foo
if the current language is "en_US", or
/articles/francais/foo
if it is "fr_FR". You don't have to indicate the language code
as before: jUrl::get('cms~page:view', array('page'=>'foo', 'lang'=>jApp::config()->locale))
.
However, you can still give it if you want to force the language code (one code different from the default one).
During the call of the page /articles/english/foo
or /articles/francais/foo
,
Jelix will configure automatically the locale. So when the user call the page
/articles/english/foo
, the current language will be "en_US".
You can also use type="lang"
. In this case, you just have to indicate the lang code ('en', 'fr'...),
either in the attribute value
, or to jUrl::get()
.
<static name="lang" value="fr" type="lang" />
With dynamic parameters ¶
If there are more than 2 or 3 language, the use of static parameters for language could be tedious, since you have to define an url for each language.
Happily, you can have parameters with the type "locale" or "lang".
<param name="lg" type="lang"/>
<!-- or -->
<param name="lg" type="locale"/>
It allows you to have a language code into the "pathinfo" of the URL, without indicating
it to jUrl::get()
, It also allows to configure automatically the current language during the
execution of the action.
Then, the previous example:
<url pathinfo="/articles/en/:page" module="cms" action="page:view">
<param name="page"/>
<static name="lang" value="en_US" />
</url>
<url pathinfo="/articles/fr/:page" module="cms" action="page:view">
<param name="page"/>
<static name="lang" value="fr_FR" />
</url>
becomes:
<url pathinfo="/articles/:lang/:page" module="cms" action="page:view">
<param name="page"/>
<param name="lang" type="lang" />
</url>
If you just call jUrl::get('cms~page:view', array('page'=>'foo'))
,
then jUrl will generate /articles/en/foo
if the locale is "en_US",
or /articles/fr/foo
if the locale is "fr_FR".
And if a browser calls /articles/en/foo
, the current locale will be
automatically "en_US".
Same principle with type="locale"
, except that jUrl will generate /articles/en_US/foo
.
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 complex parsing. For example, parts of a pathinfo can be some data 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".
To create an handler, you create a specific class:
class myHandlerUrlsHandler implements jIUrlSignificantHandler {
function parse($url) {
if (preg_match("/^\/(.*)$/",$url->pathInfo,$match)) {
// the pathinfo is the expected one, we can process it
$urlact = new jUrlAction($url->params);
$urlact->setParam('page',jUrl::unescape($match[1]));
return $urlact;
}
else {
// the pathinfo does not correspond to what we expect
return false;
}
}
function create($urlact, $url){
$p=jUrl::escape($url->getParam('page'));
$url->pathInfo = "/$p";
$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:
<entrypoint name="wiki">
<url handler="myHandler" module="unittest" action="url4" />
</entrypoint>
Of course, the handler can be stored in any module:
<entrypoint name="wiki">
<url handler="othermodule~myHandler" module="unittest" action="url4" />
</entrypoint>
The same URL for several possible actions ¶
Let's imagine that we have a url of the following pattern, /article/54-title
, 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-title?action=edit
/article/54-title?action=delete
Notice: we could also do /article/54-title/edit
or
/article/54-title/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 some secured urls (https) for specific actions ¶
For some actions, you could want to access them through 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.
Including urls files of modules ¶
You can define URLs in separate files, in each module, and then
declare those files into the main urls.xml
file. It avoid to have a big main
urls.xml
file, and more important, to avoid to declare or rewrite all url
of a module in this file, when you install a module made by someone.
To do it, you should create a file, urls.xml
(or with an other name), in
the directory of the module. This file should have a suburls
element as
root element, instead of urls
, and have all needed url
element to
declare all urls mapped to each action of the module. You should not use
entrypoint
elements of course. Here is the urls.xml file of the jauth
module:
<?xml version="1.0" encoding="utf-8"?>
<suburls xmlns="http://jelix.org/ns/suburls/1.0">
<url pathinfo="/dologin" action="login:in" />
<url pathinfo="/dologout" action="login:out" />
<url pathinfo="/login" action="login:form"/>
</suburls>
And in the main urls.xml file, in one of your entrypoint
element, you indicate:
<entrypoint name="index">
...
<url pathinfo="/auth" module="jauth" include="urls.xml" />
</entrypoint>
It means: urls declared in the urls.xml
file of the module jauth should be
included, and should be prefixed by the given pathinfo "/auth/". So the url of
the "jauth~login:in" action will be "/auth/dologin".
You notice that URLS defined in a module file are not "full" URL. It allows the developer to choose the first part of URLs, and it avoid to have conflict with other URLS declared in other modules.
In module files, you can declare URL with a static pathinfo, or with a pathinfo
with parameters, or with an handler, or with static values. However you have to
declare an url for all actions. And you cannot of course use the module
attribute.
You have also to create a url file for each type of entry point, if needed.
Removing the entry point name from urls ¶
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 configure correctly your web server.
For example, you want to have:
http://monsite.com/news/2017-02-08-il-neige-a-lille.html
instead of:
http://monsite.com/index.php/news/2017-02-08-il-neige-a-lille.html
First, in the urls.xml
file, put the attribute noentrypoint="true"
on the <url>
element or on the <entrypoint>
element.
Second you must configure your web server.
For Nginx, you can create a configuration like this:
server {
location / {
try_files $uri $uri/ @mysite;
}
location @mysite {
fastcgi_split_path_info ^()(/.*)$;
set $path_info $fastcgi_path_info;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME "$document_root/index.php";
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED "$document_root/index.php";
fastcgi_param SCRIPT_NAME "/index.php";
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
}
}
For Apache, you can use the rewrite module, with a simple configuration: the path
will be added after the index.php. You should create a .htaccess
file in the
www/
directory, or a virtualhost section in the Apache configuration, and
both solution 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).
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