Le Routing est une fonctionnalité qui fait correspondre les URLs aux actions du
controller. En définissant des routes, vous pouvez séparer la façon dont votre
application est intégrée de la façon dont ses URLs sont structurées.
Le Routing dans CakePHP englobe aussi l’idée de routing inversé, où un tableau
de paramètres peut être transformé en une URL. En utilisant le routing inversé,
vous pouvez reconstruire la structure d’URL de votre application sans mettre à
jour tous vos codes.
Tour Rapide
Cette section va vous apprendre les utilisations les plus habituelles du Router
de CakePHP. Typiquement si vous voulez afficher quelque chose en page d’accueil,
vous ajoutez ceci au fichier routes.php:
use Cake\Routing\Router;
// EN utilisant le route builder scopé.
Router::scope('/', function ($routes) {
$routes->connect('/', ['controller' => 'Articles', 'action' => 'index']);
});
// En utilisant la méthode statique.
Router::connect('/', ['controller' => 'Articles', 'action' => 'index']);
Router
fournit deux interfaces pour connecter les routes. La méthode
statique est une interface retro-compatible, alors que le builder scopé (lié la
portée) offre une syntaxe plus laconique pour construire des routes multiples,
et de meilleures performances.
Ceci va exécuter la méthode index
dans ArticlesController
quand la page
d’accueil de votre site est visitée. Parfois vous avez besoin de routes
dynamiques qui vont accepter plusieurs paramètres, ce sera par exemple le cas
d’une route pour voir le contenu d’un article:
$routes->connect('/articles/*', ['controller' => 'Articles', 'action' => 'view']);
La route ci-dessus accepte toute URL qui ressemble à /articles/15
et appelle
la méthode view(15)
dans ArticlesController
. En revanche, ceci ne va pas
empêcher les visiteurs d’accéder à une URLs ressemblant à
/articles/foobar
. Si vous le souhaitez, vous pouvez restreindre certains
paramètres grâce à une expression régulière:
$routes->connect(
'/articles/:id',
['controller' => 'Articles', 'action' => 'view'],
)
->setPatterns(['id' => '\d+'])
->setPass(['id']);
// Avant 3.5, utilisez les tableaux d'options
$routes->connect(
'/articles/:id',
['controller' => 'Articles', 'action' => 'view'],
['id' => '\d+', 'pass' => ['id']]
)
Dans l’exemple précédent, le caractère jocker *
est remplacé par un
placeholder :id
. Utiliser les placeholders nous permet de valider les
parties de l’URL, dans ce cas, nous utilisons l’expression régulière \d+
pour que seuls les chiffres fonctionnent. Finalement, nous disons au Router de
traiter le placeholder id
comme un argument de fonction pour la fonction
view()
en spécifiant l’option pass
. Vous pourrez en voir plus sur leur
utilisation plus tard.
Le Router de CakePHP peut aussi faire correspondre les routes en reverse. Cela
signifie qu’à partir d’un tableau contenant des paramètres similaires, il est
capable de générer une chaîne URL:
use Cake\Routing\Router;
echo Router::url(['controller' => 'Articles', 'action' => 'view', 'id' => 15]);
// Va afficher
/articles/15
Les routes peuvent aussi être labellisées avec un nom unique, cela vous permet
de rapidement leur faire référence lors de la construction des liens plutôt
que de spécifier chacun des paramètres de routing:
// Dans le fichier routes.php
$routes->connect(
'/login',
['controller' => 'Users', 'action' => 'login'],
['_name' => 'login']
);
use Cake\Routing\Router;
echo Router::url(['_name' => 'login']);
// Va afficher
/login
Pour aider à garder votre code de router « DRY », le router apporte le concept
de “scopes”. Un scope (étendue) défini un segment de chemin commun, et
optionnellement des routes par défaut. Toute route connectée à l’intérieur d’un
scope héritera du chemin et des routes par défaut du scope qui la contient:
Router::scope('/blog', ['plugin' => 'Blog'], function ($routes) {
$routes->connect('/', ['controller' => 'Articles']);
});
Le route ci-dessus matchera /blog/
et renverra
Blog\Controller\ArticlesController::index()
.
Le squelette d’application contient quelques routes pour vous aider à commencer.
Une fois que vous avez ajouté vos propres routes, vous pouvez retirer les routes
par défaut si vous n’en avez pas besoin.
Connecter les Routes
-
Cake\Routing\Router::
connect
($route, $defaults = [], $options = [])
Pour garder votre code DRY, vous pouvez utiliser les “routing scopes”.
Les scopes de Routing permettent non seulement de garder votre code DRY mais
aident aussi le Router à optimiser son opération. Comme vous l’avez vu
précédemment. Cette méthode va par défaut vers le scope /
. Pour créer un
scope et connecter certaines routes, nous allons utiliser la méthode
scope()
:
// Dans config/routes.php
use Cake\Routing\Route\DashedRoute;
Router::scope('/', function ($routes) {
// Connecte la route de 'fallback' générique
$routes->fallbacks(DashedRoute::class);
});
La méthode connect()
prend trois paramètres: l’URL que vous souhaitez faire
correspondre, les valeurs par défaut pour les éléments de votre route, et les
règles d’expression régulière pour aider le router à faire correspondre les
éléments dans l’URL.
Le format basique pour une définition de route est:
$routes->connect(
'/url/template',
['default' => 'defaultValue'],
['option' => 'matchingRegex']
);
Le premier paramètre est utilisé pour dire au router quelle sorte d’URL vous
essayez de contrôler. L’URL est une chaîne normale délimitée par des slashes,
mais peut aussi contenir une wildcard (*) ou Les Eléments de Route. Utiliser
une wildcard dit au router que vous êtes prêt à accepter tout argument
supplémentaire fourni. Les Routes sans un * ne matchent que le pattern template
exact fourni.
Une fois que vous spécifiez une URL, vous utilisez les deux derniers paramètres
de connect()
pour dire à CakePHP quoi faire avec une requête une fois
qu’elle a été matchée. Le deuxième paramètre est un tableau associatif. Les clés
du tableau devraient être appelées après les éléments de route dans l’URL, ou
les éléments par défaut: :controller
, :action
, et :plugin
. Les
valeurs dans le tableau sont les valeurs par défaut pour ces clés. Regardons
quelques exemples simples avant que nous commencions à voir l’utilisation du
troisième paramètre de connect()
:
$routes->connect(
'/pages/*',
['controller' => 'Pages', 'action' => 'display']
);
Cette route est trouvée dans le fichier routes.php distribué avec CakePHP. Cette
route matche toute URL commençant par /pages/
et il tend vers l’action
display()
de PagesController
La requête /pages/products
serait mappé
vers PagesController->display('products')
.
En plus de l’étoile greedy /*
il y aussi la syntaxe de l’étoile trailing
/**
. Utiliser une étoile double trailing, va capturer le reste de l’URL en
tant qu’argument unique passé. Ceci est utile quand vous voulez utilisez un
argument qui incluait un /
dedans:
$routes->connect(
'/pages/**',
['controller' => 'Pages', 'action' => 'show']
);
L’URL entrante de /pages/the-example-/-and-proof
résulterait en un argument
unique passé de the-example-/-and-proof
.
Vous pouvez utiliser le deuxième paramètre de connect()
pour fournir tout
paramètre de routing qui est composé des valeurs par défaut de la route:
$routes->connect(
'/government',
['controller' => 'Pages', 'action' => 'display', 5]
);
Cet exemple montre comment vous pouvez utiliser le deuxième paramètre de
connect()
pour définir les paramètres par défaut. Si vous construisez un
site qui propose des produits pour différentes catégories de clients, vous
pourriez considérer la création d’une route. Cela vous permet de vous lier à
/government
plutôt qu’à /pages/display/5
.
Une utilisation classique du routing peut impliquer la création de segments
d’URL qui ne correspondent pas aux noms de vos controllers ou de vos models.
Imaginons qu’au lieu de vouloir accéder à une URL /users/some_action/5
,
vous souhaitiez y accéder via /cooks/une_action/5
. Pour ce faire,
vous devriez configurer la route suivante:
$routes->connect(
'/cooks/:action/*', ['controller' => 'Users']
);
Cela dit au Router que toute URL commençant par /cooks/
devrait être envoyée
au UsersController
. L’action appelée dépendra de la valeur du paramètre
:action
. En utilisant Les Eléments de Route, vous pouvez créer des routes
variables, qui acceptent les entrées utilisateur ou les variables. La route
ci-dessus utilise aussi l’étoile greedy. L’étoile greedy indique au
Router
que cette route devrait accepter tout argument de position
supplémentaire donné. Ces arguments seront rendus disponibles dans le tableau
Arguments Passés.
Quand on génère les URLs, les routes sont aussi utilisées. Utiliser
['controller' => 'Users', 'action' => 'some_action', 5]
en URL va sortir
/cooks/some_action/5
si la route ci-dessus est la première correspondante
trouvée.
Les routes connectées jusque là fonctionneront avec n’importe quel verbe HTTP.
Si vous souhaitez construire une API REST, vous aurez probablement besoin de faire
correspondre des actions HTTP à des méthodes de controller différentes.
Le RouteBuilder
met à disposition des méthodes qui rendent plus facile la
définition de routes pour des verbes HTTP spécifiques:
// Crée une route qui ne répondra qu'aux requêtes GET.
$routes->get(
'/cooks/:id',
['controller' => 'Users', 'action' => 'view'],
'users:view'
);
// Crée une route qui ne répondra qu'aux requêtes PUT
$routes->put(
'/cooks/:id',
['controller' => 'Users', 'action' => 'update'],
'users:update'
);
Les méthodes ci-dessus mappent la même URL à des actions différentes en fonction
du verbe HTTP utilisé. Les requêtes GET pointeront sur l’action “view” tandis que les
requêtes PUT pointeront sur l’action “update”. Ces méthodes sont disponibles pour les
verbes :
GET
POST
PUT
PATCH
DELETE
OPTIONS
HEAD
Toutes ces méthodes retournent une instance de Route ce qui vous permet d’utiliser les
setters fluides pour configurer plus précisément vos
routes.
Nouveau dans la version 3.5.0: Les méthodes pour les verbes HTTP ont été ajoutées dans 3.5.0
Les Eléments de Route
Vous pouvez spécifier vos propres éléments de route et ce faisant
cela vous donne le pouvoir de définir des places dans l’URL où les
paramètres pour les actions du controller doivent se trouver. Quand
une requête est faite, les valeurs pour ces éléments de route se
trouvent dans $this->request->getParam()
dans le controller. Quand vous
définissez un élément de route personnalisé, vous pouvez spécifier en option
une expression régulière - ceci dit à CakePHP comment savoir si l’URL est
correctement formée ou non. Si vous choisissez de ne pas fournir une expression
régulière, toute expression non /
sera traitée comme une partie du
paramètre:
$routes->connect(
'/:controller/:id',
['action' => 'view']
)->setPatterns(['id' => '[0-9]+']);
// Avant 3.5, utilisez les options de tableau
$routes->connect(
'/:controller/:id',
['action' => 'view'],
['id' => '[0-9]+']
);
Cet exemple simple montre comment créer une manière rapide de voir les models
à partir de tout controller en élaborant une URL qui ressemble à
/controllername/:id
. L’URL fournie à connect() spécifie deux éléments de
route: :controller
et :id
. L’élément :controller
est l’élément de
route par défaut de CakePHP, donc le router sait comment matcher et identifier
les noms de controller dans les URLs. L’élément :id
est un élément de route
personnalisé, et doit être clarifié plus loin en spécifiant une expression
régulière correspondante dans le troisième paramètre de connect()
.
CakePHP ne produit pas automatiquement d’urls en minuscule avec des tirets quand
vous utilisez le paramètre :controller
. Si vous avez besoin de ceci,
l’exemple ci-dessus peut être réécrit en:
use Cake\Routing\Route\DashedRoute;
// Crée un builder avec une classe de Route différente.
$routes->scope('/', function ($routes) {
$routes->setRouteClass(DashedRoute::class);
$routes->connect('/:controller/:id', ['action' => 'view'])
->setPatterns(['id' => '[0-9]+']);
// Avant 3.5, utilisez le tableau d'options
$routes->connect(
'/:controller/:id',
['action' => 'view'],
['id' => '[0-9]+']
);
});
La classe spéciale DashedRoute
va s’assurer que les paramètres
:controller
et :plugin
sont correctement mis en minuscule et avec des
tirets. Si vous avez besoin d’URLs en minuscule avec des underscores en migrant
d’une application CakePHP 2.x, vous pouvez utiliser à la place la classe
InflectedRoute
.
Note
Les Patrons utilisés pour les éléments de route ne doivent pas contenir
de groupes capturés. S’ils le font, le Router ne va pas fonctionner
correctement.
Une fois que cette route a été définie, la requête /apples/5
est la même
que celle requêtant /apples/view/5
. Les deux appelleraient la méthode view()
de ApplesController. A l’intérieur de la méthode view()
, vous aurez besoin
d’accéder à l’ID passé à $this->request->getParam('id')
.
Si vous avez un unique controller dans votre application et que vous ne
voulez pas que le nom du controller apparaisse dans l’URL, vous pouvez mapper
toutes les URLs aux actions dans votre controller. Par exemple, pour mapper
toutes les URLs aux actions du controller home
, par ex avoir des URLs
comme /demo
à la place de /home/demo
, vous pouvez faire ce qui suit:
$routes->connect('/:action', ['controller' => 'Home']);
Si vous souhaitez fournir une URL non sensible à la casse, vous pouvez utiliser
les modificateurs en ligne d’expression régulière:
// Avant 3.5, utilisez le tableau d'options à la place de setPatterns()
$routes->connect(
'/:userShortcut',
['controller' => 'Teachers', 'action' => 'profile', 1],
)->setPatterns(['userShortcut' => '(?i:principal)']);
Un exemple de plus, et vous serez un pro du routing:
// Avant 3.5, utilisez le tableau d'options à la place de setPatterns()
$routes->connect(
'/:controller/:year/:month/:day',
['action' => 'index']
)->setPatterns([
'year' => '[12][0-9]{3}',
'month' => '0[1-9]|1[012]',
'day' => '0[1-9]|[12][0-9]|3[01]'
]);
C’est assez complexe, mais montre comme les routes peuvent vraiment
devenir puissantes. L’URL fournie a quatre éléments de route. Le premier
nous est familier: c’est une route par défaut qui dit à CakePHP d’attendre
un nom de controller.
Ensuite, nous spécifions quelques valeurs par défaut. Quel que soit le
controller, nous voulons que l’action index()
soit appelée.
Finalement, nous spécifions quelques expressions régulières qui vont
matcher les années, mois et jours sous forme numérique. Notez que les
parenthèses (le groupement) ne sont pas supportées dans les expressions
régulières. Vous pouvez toujours spécifier des alternatives, comme
dessus, mais ne pas grouper avec les parenthèses.
Une fois définie, cette route va matcher /articles/2007/02/01
,
/posts/2004/11/16
, gérant les requêtes
pour les actions index()
de ses controllers respectifs, avec les paramètres de
date dans $this->request->getParam()
.
Il y a plusieurs éléments de route qui ont une signification spéciale dans
CakePHP, et ne devraient pas être utilisés à moins que vous ne souhaitiez
spécifiquement utiliser leur signification.
controller
Utilisé pour nommer le controller pour une route.
action
Utilisé pour nommer l’action de controller pour une route.
plugin
Utilisé pour nommer le plugin dans lequel un controller est
localisé.
prefix
Utilisé pour Prefix de Routage.
_ext
Utilisé pour Routing des Extensions de Fichier.
_base
Défini à false
pour retirer le chemin de base de l’URL générée.
Si votre application n’est pas dans le répertoire racine, cette option peut
être utilisée pour générer les URLs qui sont “liées à cake”.
_scheme
Défini pour créer les liens sur les schémas différents comme
webcal ou ftp. Par défaut, au schéma courant.
_host
Définit l’hôte à utiliser pour le lien. Par défaut à l’hôte courant.
_port
Définit le port si vous avez besoin de créer les liens sur des ports
non-standards.
_full
Si à true
, la constante FULL_BASE_URL va être ajoutée devant
les URLS générées.
#
Vous permet de définir les fragments de hash d’URL.
_ssl
Défini à true
pour convertir l’URL générée à https, ou false
pour forcer http.
_method
Defini la méthode HTTP à utiliser. utile si vous travaillez avec
Créer des Routes RESTful.
_name
Nom de route. Si vous avez configuré les routes nommées, vous
pouvez utiliser cette clé pour les spécifier.
Passer des Paramètres à l’Action
Quand vous connectez les routes en utilisant
Les Eléments de Route vous voudrez peut-être que des éléments routés
soient passés aux arguments à la place. L’option pass
défini une liste
des éléments de route doit également être rendu disponible en tant qu’arguments
passé aux fonctions du controller:
// src/Controller/BlogsController.php
public function view($articleId = null, $slug = null)
{
// du code ici...
}
// routes.php
Router::scope('/', function ($routes) {
$routes->connect(
'/blog/:id-:slug', // E.g. /blog/3-CakePHP_Rocks
['controller' => 'Blogs', 'action' => 'view']
)
// Défini les éléments de route dans le template de route
// à passer en tant qu'arguments à la fonction. L'ordre est
// important car cela fera simplement correspondre ":id" avec
// articleId dans votre action.
->setPass(['id', 'slug'])
// Defini un pattern que `id` doit avoir.
->setPatterns([
'id' => '[0-9]+',
]);
});
Maintenant, grâce aux possibilités de routing inversé, vous pouvez passer
dans le tableau d’URL comme ci-dessous et CakePHP sait comment former l’URL
comme définie dans les routes:
// view.ctp
// ceci va retourner un lien vers /blog/3-CakePHP_Rocks
echo $this->Html->link('CakePHP Rocks', [
'controller' => 'Blog',
'action' => 'view',
'id' => 3,
'slug' => 'CakePHP_Rocks'
]);
// Vous pouvez aussi utiliser des paramètres indexés numériquement.
echo $this->Html->link('CakePHP Rocks', [
'controller' => 'Blog',
'action' => 'view',
3,
'CakePHP_Rocks'
]);
Utiliser les Routes Nommées
Parfois vous trouvez que taper tous les paramètres de l’URL pour une route est
trop verbeux, ou bien vous souhaitez tirer avantage des améliorations de la
performance que les routes nommées permettent. Lorsque vous connectez les
routes, vous pouvez spécifier une option _name
, cette option peut être
utilisée pour le routing inversé pour identifier la route que vous souhaitez
utiliser:
// Connecter une route avec un nom.
$routes->connect(
'/login',
['controller' => 'Users', 'action' => 'login'],
['_name' => 'login']
);
// Nommage d'une route liée à un verbe spécifique (3.5.0+)
$routes->post(
'/logout',
['controller' => 'Users', 'action' => 'logout'],
'logout'
);
// Génère une URL en utilisant une route nommée.
$url = Router::url(['_name' => 'logout']);
// Génère une URL en utilisant une route nommée,
// avec certains args query string
$url = Router::url(['_name' => 'login', 'username' => 'jimmy']);
Si votre template de route contient des éléments de route comme :controller
,
vous aurez besoin de fournir ceux-ci comme options de Router::url()
.
Note
Les noms de Route doivent être uniques pour l’ensemble de votre application.
Le même _name
ne peut être utilisé deux fois, même si les noms
apparaissent dans un scope de routing différent.
Quand vous construisez vos noms de routes, vous voudrez probablement coller
à certaines conventions pour les noms de route. CakePHP facilite la construction
des noms de route en vous permtttant de définir des préfixes de nom dans chaque
scope:
Router::scope('/api', ['_namePrefix' => 'api:'], function ($routes) {
// le nom de cette route sera `api:ping`
$routes->get('/ping', ['controller' => 'Pings'], 'ping');
});
Router::plugin('Contacts', ['_namePrefix' => 'contacts:'], function ($routes) {
// Connecte les routes.
});
Router::prefix('Admin', ['_namePrefix' => 'admin:'], function ($routes) {
// Connecte les routes.
});
Vous pouvez aussi utiliser l’option _namePrefix
dans les scopes imbriqués et
elle fonctionne comme vous pouvez vous y attendre:
Router::plugin('Contacts', ['_namePrefix' => 'contacts:'], function ($routes) {
$routes->scope('/api', ['_namePrefix' => 'api:'], function ($routes) {
// Le nom de cette route sera `contacts:api:ping`
$routes->get('/ping', ['controller' => 'Pings'], 'ping');
});
});
Les routes connectées dans les scopes nommés auront seulement des noms ajoutés
si la route est aussi nommée. Les routes sans nom ne se verront pas appliquées
_namePrefix
.
Nouveau dans la version 3.1: L’option _namePrefix
a été ajoutée dans 3.1
Prefix de Routage
-
static
Cake\Routing\Router::
prefix
($name, $callback)
De nombreuses applications nécessitent une section d’administration dans
laquelle les utilisateurs privilégiés peuvent faire des modifications.
Ceci est souvent réalisé grâce à une URL spéciale telle que
/admin/users/edit/5
. Dans CakePHP, les préfixes de routage peuvent être
activés depuis le fichier de configuration du cœur en configurant les
préfixes avec Routing.prefixes. Les préfixes peuvent être soit activés en
utilisant la valeur de configuration Routing.prefixes
, soit en définissant
la clé prefix
avec un appel de Router::connect()
:
use Cake\Routing\Route\DashedRoute;
Router::prefix('admin', function ($routes) {
// Toutes les routes ici seront préfixées avec `/admin` et auront
// l'élément de route prefix => admin ajouté.
$routes->fallbacks(DashedRoute::class);
});
Les préfixes sont mappés aux sous-espaces de noms dans l’espace de nom
Controller
de votre application. En ayant des préfixes en tant que
controller séparés, vous pouvez créer de plus petits et/ou de plus simples
controllers. Les comportements communs aux controllers préfixés et non-préfixés
peuvent être encapsulés via l’héritage, les Components (Composants), ou
les traits. En utilisant notre exemple des utilisateurs, accéder à l’url
/admin/users/edit/5
devrait appeler la méthode edit()
de notre
App\Controller\Admin\UsersController
en passant 5 comme premier paramètre.
Le fichier de vue utilisé serait src/Template/Admin/Users/edit.ctp.
Vous pouvez faire correspondre l’URL /admin à votre action index()
du controller Pages en utilisant la route suivante:
Router::prefix('admin', function ($routes) {
// Parce que vous êtes dans le scope admin, vous n'avez pas besoin
// d'inclure le prefix /admin ou l'élément de route admin.
$routes->connect('/', ['controller' => 'Pages', 'action' => 'index']);
});
Quand vous créez des routes préfixées, vous pouvez définir des paramètres de
route supplémentaires en utilisant l’argument $options
:
Router::prefix('admin', ['param' => 'value'], function ($routes) {
// Routes connectées ici sont préfixées par '/admin' et
// ont la clé 'param' de routing définie.
$routes->connect('/:controller');
});
Vous pouvez aussi définir les préfixes dans les scopes de plugin:
Router::plugin('DebugKit', function ($routes) {
$routes->prefix('admin', function ($routes) {
$routes->connect('/:controller');
});
});
Ce qui est au-dessus va créer un template de route de type
/debug_kit/admin/:controller
. La route connectée aura les éléments de
route plugin
et prefix
définis.
Quand vous définissez des préfixes, vous pouvez imbriquer plusieurs préfixes
si besoin:
Router::prefix('manager', function ($routes) {
$routes->prefix('admin', function ($routes) {
$routes->connect('/:controller');
});
});
Ce qui est au-dessus va créer un template de route de type
/manager/admin/:controller
. La route connectée aura l’élément de
route prefix
défini à manager/admin
.
Le préfixe actuel sera disponible à partir des méthodes du controller avec
$this->request->getParam('prefix')
Quand vous utilisez les routes préfixées, il est important de définir l’option
prefix. Voici comment construire ce lien en utilisant le helper HTML:
// Aller vers une route préfixée.
echo $this->Html->link(
'Manage articles',
['prefix' => 'manager', 'controller' => 'Articles', 'action' => 'add']
);
// Enlever un prefix
echo $this->Html->link(
'View Post',
['prefix' => false, 'controller' => 'Articles', 'action' => 'view', 5]
);
Note
Vous devez connecter les routes préfixées avant de connecter les routes
fallback.
Routing des Plugins
-
static
Cake\Routing\Router::
plugin
($name, $options = [], $callback)
Les routes des Plugins sont plus faciles à créer en utilisant la méthode
plugin()
. Cette méthode crée un nouveau scope pour les routes de plugin:
Router::plugin('DebugKit', function ($routes) {
// Les routes connectées ici sont préfixées par '/debug_kit' et ont
// l'élément de route plugin défini à 'DebugKit'.
$routes->connect('/:controller');
});
Lors de la création des scopes de plugin, vous pouvez personnaliser le chemin de
l’élément avec l’option path
:
Router::plugin('DebugKit', ['path' => '/debugger'], function ($routes) {
// Les routes connectées ici sont préfixées par '/debugger' et ont
// l'élément de route plugin défini à 'DebugKit'.
$routes->connect('/:controller');
});
Lors de l’utilisation des scopes, vous pouvez imbriquer un scope de plugin dans
un scope de prefix:
Router::prefix('admin', function ($routes) {
$routes->plugin('DebugKit', function ($routes) {
$routes->connect('/:controller');
});
});
Le code ci-dessus devrait créer une route similaire à
/admin/debug_kit/:controller
. Elle devrait avoir les éléments de route
prefix
et plugin
définis. Référez-vous à la section Routes de Plugins
pour avoir plus d’informations sur comment construire des routes de plugin.
Créer des Liens vers des Routes de Plugins
Vous pouvez créer des liens qui pointent vers un plugin, en ajoutant la clé
plugin
au tableau de l’URL:
echo $this->Html->link(
'New todo',
['plugin' => 'Todo', 'controller' => 'TodoItems', 'action' => 'create']
);
Inversement, si la requête active est une requête de plugin et que vous
souhaitez créer un lien qui n’a pas de plugin, vous pouvez faire ceci:
echo $this->Html->link(
'New todo',
['plugin' => null, 'controller' => 'Users', 'action' => 'profile']
);
En définissant 'plugin' => null
, vous dites au Router que vous souhaitez
créer un lien qui n’appartient pas à un plugin.
Routing Favorisant le SEO
Certains développeurs préfèrent utiliser des tirets dans les URLs, car cela
semble donner un meilleur classement dans les moteurs de recherche.
La classe DashedRoute
fournit à votre application la possibilité de créer
des URLs avec des tirets pour vos plugins, controllers, et les noms d’action en
camelCase
.
Par exemple, si nous avons un plugin ToDo
avec un controller TodoItems
et une action showItems()
, la route générée sera
/to-do/todo-items/show-items
avec le code qui suit:
use Cake\Routing\Route\DashedRoute;
Router::plugin('ToDo', ['path' => 'to-do'], function ($routes) {
$routes->fallbacks(DashedRoute::class);
});
Matching des Méthodes HTTP Spécifiques
Les routes peuvent « matcher » des méthodes HTTP spécifiques en utilisant
les méthodes spécifiques:
Router::scope('/', function($routes) {
// Cette route matchera seulement les requêtes POST.
$routes->post(
'/reviews/start',
['controller' => 'Reviews', 'action' => 'start']
);
// Matcher plusieurs verbes
// Avant 3.5, utilisez $options['_method'] pour définir les méthodes
$routes->connect(
'/reviews/start',
[
'controller' => 'Reviews',
'action' => 'start',
]
)->setMethods(['POST', 'PUT']);
});
Vous pouvez « matcher » plusieurs méthodes HTTP en fournissant un tableau.
Puisque que l’option _method
est une clé de routage, elle est utilisée à la
fois dans le parsing des URL et la génération des URL. Pour générer des URL pour
des routes spécifiques, vous devez utiliser la clé _method
lors de la génération:
$url = Router::url([
'controller' => 'Reviews',
'action' => 'start',
'_method' => 'POST',
]);
Matching de Noms de Domaine Spécifiques
Les routes peuvent utiliser l’option _host
pour « matcher » des noms de
domaines spécifiques. Vous pouvez utiliser la wildcard *.
pour « matcher »
n’importe quelle sous-domaine:
Router::scope('/', function($routes) {
// Cette route ne va "matcher" que sur le domaine http://images.example.com
// Avant 3.5, utilisez l'option _host
$routes->connect(
'/images/default-logo.png',
['controller' => 'Images', 'action' => 'default']
)->setHost('images.example.com');
// Cette route matchera sur tous les sous-domaines http://*.example.com
$routes->connect(
'/images/old-log.png',
['controller' => 'Images', 'action' => 'oldLogo']
)->setHost('*.example.com');
});
L’option _host
n’affecte que le parsing des URL depuis les requêtes et
n’intervient jamais dans la génération d’URL.
Nouveau dans la version 3.4.0: L’option _host
a été ajoutée dans la version 3.4.0
Routing des Extensions de Fichier
-
static
Cake\Routing\Router::
extensions
(string|array|null $extensions, $merge = true)
Pour manipuler différentes extensions de fichier avec vos routes, vous pouvez
définir vos extensions de manière globale ou dans un scope. Définir des
extensions globales peut se faire via la méthode static Router::extensions()
Router::extensions([“json”, “xml”]);
// …
Ceci affectera toutes les routes qui seront connectées après cet appel,
quelque soit leur scope.
Pour restreindre les extensions à un scope spécifique, vous pouvez les définir
en utilisant la méthode Cake\Routing\RouteBuilder::extensions()
:
Router::scope('/', function ($routes) {
// Avant 3.5.0 utilisez `extensions()`
$routes->setExtensions(['json', 'xml']);
// ...
});
Cela activera les extensions pour toutes les routes qui seront définies dans ce
scope après l’appel à extensions()
, tout en incluant les routes inclus
dans les scopes imbriqués. De la même manière que la méthode Router::extensions()
,
toutes les routes connectées avant cet appel n’hériteront pas de ces extensions.
Note
Le réglage des extensions devrait être la première chose que vous devriez
faire dans un scope, car les extensions seront appliquées uniquement aux
routes qui sont définies après la déclaration des extensions.
Lorsque vous définissez des routes dans le même scope mais dans deux appels
différents, les extensions ne seront pas héritées d’un appel à l’autre.
En utilisant des extensions, vous dites au router de supprimer toutes les
extensions de fichiers correspondant, puis d’analyser le reste. Si vous
souhaitez créer une URL comme /page/title-of-page.html
vous devriez créer
un scope comme ceci:
Router::scope('/page', function ($routes) {
$routes->setExtensions(['json', 'xml', 'html']);
$routes->connect(
'/:title',
['controller' => 'Pages', 'action' => 'view']
)->setPass(['title']);
});
Ensuite, pour créer des liens, utilisez simplement:
$this->Html->link(
'Link title',
['controller' => 'Pages', 'action' => 'view', 'title' => 'super-article', '_ext' => 'html']
);
Les extensions de fichier sont utilisées par le
Request Handling (Gestion des requêtes) qui fait la commutation des
vues automatiquement en se basant sur les types de contenu.
Connecter des Middlewares à un scope
Bien que les middlewares puissent être appliqués à toute votre application, appliquer
les middlewares à des “scopes” de routing offre plus de flexibilité puisque vous
pouvez appliquer des middlewares seulement où ils sont nécessaires permettant à vos
middlewares de ne pas nécessiter de logique spécifique sur le comment / où il doit
s’appliquer.
Avant qu’un middleware ne puisse être appliqué à un scope, il a besoin d’être
enregistré dans la collection de routes:
// in config/routes.php
use Cake\Http\Middleware\CsrfProtectionMiddleware;
use Cake\Http\Middleware\EncryptedCookieMiddleware;
Router::scope('/', function ($routes) {
$routes->registerMiddleware('csrf', new CsrfProtectionMiddleware());
$routes->registerMiddleware('cookies', new EncryptedCookieMiddleware());
});
Une fois enregistré dans le builder de routes, le middleware peut être appliqué
à des scopes spécifiques:
$routes->scope('/cms', function ($routes) {
// Active les middlewares enregistrés pour ce scope.
$routes->applyMiddleware('csrf', 'cookies');
$routes->get('/articles/:action/*', ['controller' => 'Articles'])
});
Dans le cas où vous auriez des “scopes” imbriqués, les « sous » scopes hériteront
des middlewares apppliqués dans le scope contenant:
$routes->scope('/api', function ($routes) {
$routes->applyMiddleware('ratelimit', 'auth.api');
$routes->scope('/v1', function ($routes) {
$routes->applyMiddleware('v1compat');
// Définissez vos routes
});
});
Dans l’exemple ci-dessus, les routes définies dans /v1
auront les middlewares
“ratelimit”, “auth.api”, and “v1compat” appliqués. Si vous ré-ouvrez un scope, les
middlewares appliqués aux routes dans chaque scopes seront isolés:
$routes->scope('/blog', function ($routes) {
$routes->applyMiddleware('auth');
// Connecter les actions qui nécessitent l'authentification aux 'blog' ici
});
$routes->scope('/blog', function ($routes) {
// Connecter les actions publiques pour le 'blog' ici
});
Dans l’exemple ci-dessus, les 2 utilisations du scope /blog
ne partagent
pas les middlewares. Par contre, les 2 scopes hériteront des middlewares définis
dans le scope qui les contient.
Grouper les Middlewares
Pour vous aider à garder votre code DRY, les
middlewares peuvent être combinés en groupes. Une fois créés, les groupes peuvent
être appliqués comme des middlewares:
$routes->registerMiddleware('cookie', new EncryptedCookieMiddleware());
$routes->registerMiddleware('auth', new AuthenticationMiddleware());
$routes->registerMiddleware('csrf', new CsrfProtectionMiddleware());
$routes->middlewareGroup('web', ['cookie', 'auth', 'csrf']);
// Application du groupe
$routes->applyMiddleware('web');
Nouveau dans la version 3.5.0: Le support des middlewares par scope et des groupes de middlewares
a été ajouté dans 3.5.0
Créer des Routes RESTful
Le router rend facile la génération des routes RESTful pour vos controllers.
Les routes RESTful sont utiles lorsque vous créez des points de terminaison
d’API pour vos applications. Si nous voulions permettre l’accès à une base
de données REST, nous ferions quelque chose comme ceci:
//Dans config/routes.php
Router::scope('/', function ($routes) {
$routes->setExtensions(['json']);
$routes->resources('Recipes');
});
La première ligne définit un certain nombre de routes par défaut pour l’accès
REST où la méthode spécifie le format du résultat souhaité (par exemple, xml,
json, rss). Ces routes sont sensibles aux méthodes de requêtes HTTP.
HTTP format |
URL.format |
Controller action invoked |
GET |
/recipes.format |
RecipesController::index() |
GET |
/recipes/123.format |
RecipesController::view(123) |
POST |
/recipes.format |
RecipesController::add() |
PUT |
/recipes/123.format |
RecipesController::edit(123) |
PATCH |
/recipes/123.format |
RecipesController::edit(123) |
DELETE |
/recipes/123.format |
RecipesController::delete(123) |
La classe Router de CakePHP utilise un nombre différent d’indicateurs pour
détecter la méthode HTTP utilisée. Voici la liste dans l’ordre de préférence:
La variable POST _method
Le X_HTTP_METHOD_OVERRIDE
Le header REQUEST_METHOD
La variable POST _method est utile dans l’utilisation d’un navigateur comme un
client REST (ou tout ce qui peut faire du POST). Il suffit de configurer la
valeur de _method avec le nom de la méthode de requête HTTP que vous souhaitez
émuler.
Créer des Routes de Ressources Imbriquées
Une fois que vous avez connecté une ressource dans un scope, vous pouvez aussi
connecter des routes pour des sous-ressources. Les routes de sous-ressources
seront préfixées par le nom de la ressource originale et par son paramètre id.
Par exemple:
Router::scope('/api', function ($routes) {
$routes->resources('Articles', function ($routes) {
$routes->resources('Comments');
});
});
Le code ci-dessus va générer une ressource de routes pour articles
et
comments
. Les routes des comments
vont ressembler à ceci:
/api/articles/:article_id/comments
/api/articles/:article_id/comments/:id
Vous pouvez récupérer le champs article_id
de CommentsController
de cette façon:
$this->request->getParam('article_id');
By default resource routes map to the same prefix as the containing scope. If
you have both nested and non-nested resource controllers you can use a different
controller in each context by using prefixes:
Router::scope('/api', function ($routes) {
$routes->resources('Articles', function ($routes) {
$routes->resources('Comments', ['prefix' => 'articles']);
});
});
L’exemple ci-dessus mapperait le champs “Comments” vers
App\Controller\Articles\CommentsController
. Une séparation des controllers
vous permet de simplifier la logique. Les préfixes créés de cette manière sont
compatibles avec Prefix de Routage.
Note
Vous pouvez imbriquer autant de ressources que vous le souhaitez, mais il
n’est pas recommandé d’imbriquer plus de 2 ressources ensembles.
Nouveau dans la version 3.3: L’option prefix
a été ajoutée à resources()
dans la version 3.3.
Limiter la Création des Routes
Par défaut, CakePHP va connecter 6 routes pour chaque ressource. Si vous
souhaitez connecter uniquement des routes spécifiques à une ressource, vous
pouvez utiliser l’option only
:
$routes->resources('Articles', [
'only' => ['index', 'view']
]);
Le code ci-dessus devrait créer uniquement les routes de ressource lecture
.
Les noms de route sont create
, update
, view
, index
et
delete
.
Changer les Actions du Controller
Vous devrez peut-être modifier le nom des actions du controller qui sont
utilisés lors de la connexion des routes. Par exemple, si votre action
edit()
est nommée put()
, vous pouvez utiliser la clé actions
pour
renommer vos actions:
$routes->resources('Articles', [
'actions' => ['update' => 'put', 'create' => 'add']
]);
Le code ci-dessus va utiliser la méthode put()
pour l’action edit()
, et
add()
au lieu de create()
.
Mapper des Routes de Ressource Supplémentaires
Vous pouvez mapper des méthodes de ressource supplémentaires en utilisant
l’option map
:
$routes->resources('Articles', [
'map' => [
'deleteAll' => [
'action' => 'deleteAll',
'method' => 'DELETE'
]
]
]);
// Ceci connecterait /articles/deleteAll
En plus des routes par défaut, ceci connecterait aussi une route pour
/articles/delete_all. Par défaut le segment de chemin va matcher le nom
de la clé. Vous pouvez utiliser la clé “path” à l’intérieur de la définition
de la ressource pour personnaliser le nom de chemin:
$routes->resources('Articles', [
'map' => [
'updateAll' => [
'action' => 'updateAll',
'method' => 'DELETE',
'path' => '/update_many'
],
]
]);
// Ceci connecterait /articles/update_many
Si vous définissez “only” et “map”, assurez-vous que vos méthodes mappées sont
aussi dans la liste “only”.
Classes de Route Personnalisée pour les Ressources
Vous pouvez spécifier la clé connectOptions
dans le tableau $options
de
la fonction resources()
pour fournir une configuration personnalisée
utilisée par connect()
:
Router::scope('/', function ($routes) {
$routes->resources('books', [
'connectOptions' => [
'routeClass' => 'ApiRoute',
]
];
});
Inflection de l’URL pour les Routes Ressource
Par défaut le fragment d’URL pour les controllers à plusieurs mots est la forme
en underscore du nom du controller. Par exemple, le fragment d’URL pour
BlogPosts
serait /blog_posts.
Vous pouvez spécifier un type d’inflection alternatif en utilisant l’option
inflect
:
Router::scope('/', function ($routes) {
$routes->resources('BlogPosts', [
'inflect' => 'dasherize' // Utilisera ``Inflector::dasherize()``
]);
})
Ce qui est au-dessus va générer des URLs de style /blog-posts*.
Note
Depuis CakePHP 3.1, le squelette de l’app officiel utilise DashedRoute
comme classe de route par défaut. Donc il est recommandé d’utiliser l’option
'inflect' => 'dasherize'
pour connecter les routes resssource afin de
garder la cohérence de l’URL.
Changer le chemin d’un élément
Par défaut, les ressources de routes utilisent le nom de ressource ayant subi
une inflexion en guise de segment d’URL. Vous pouvez définir un segment d’URL
personnalisé à l’aide de l’option path
:
Router::scope('/', function ($routes) {
$routes->resources('BlogPosts', ['path' => 'posts']);
});
Nouveau dans la version 3.5.0: L’option path
a été ajoutée dans 3.5.0.