This chapter is not yet translated. Contributions are 7 | welcomed!
8 | 9 |Un programme doit gérer beaucoup de requêtes, et une tâche
7 | essentielle est de savoir les router,
8 | c'est à dire de savoir où les acheminer. C'est le rôle qui
9 | incombe à la bibliothèque Hoa\Router
.
Un routeur a une tâche assez simple : il reçoit une
18 | requête et il doit trouver où l'acheminer.
19 | Pour cela, il dispose d'une série de règles. Il cherche
20 | quelle règle parmi toutes celles dont il dispose correspond à la requête. Si
21 | une correspondance entre une requête et une règle existe,
22 | alors des données seront extraites de cette requête. Ces
23 | données peuvent être utilisées pour acheminer la requête quelque part. C'est
24 | le rôle de Hoa\Dispatcher
,
25 | qui fonctionne de paire avec Hoa\Router
.
Une règle doit être vue comme une succession de filtres. Si tous les 27 | filtres laissent passer la requête, alors la règle sera retenue pour acheminer 28 | la requête. Une requête est traitée de la façon suivante :
29 | 30 | 47 |Tout d'abord, une règle a une visibilité qui contrôle la
48 | provenance de la requête. Il y a deux visibilités possibles :
49 | publique, qui est validée par les requêtes provenant de
50 | l'intérieur du programme comme de l'extérieur, et privée, qui
51 | n'est validée que par les requêtes provenant du programme lui-même. Par
52 | exemple, si la requête est extérieure au programme (typiquement, un client
53 | envoie une requête sur un serveur) et que la règle a une visibilité privée,
54 | elle ne sera pas retenue. En revanche, si une requête est interne au
55 | programme, une règle publique ou privée pourra être retenue. Ensuite, une
56 | règle définit des méthodes qui vérifient le type de la
57 | requête. Par exemple, dans le cas d'une requête HTTP, nous pouvons avoir la
58 | méthode GET
: toutes les règles ayant au moins la méthode
59 | GET
peuvent être retenues. Enfin, une règle impose un
60 | motif sous la forme d'une expression régulière (basée sur les
61 | PCRE). La requête doit correspondre à ce motif
62 | pour qu'elle soit retenue. Ce motif permet aussi d'extraire des données de la
63 | requête, ce qui pourra aider à son acheminement. Notons par ailleurs que
64 | toutes les règles portent un identifiant unique.
Nous avons vu qu'une règle est composée d'une visibilité, 69 | de méthodes et d'un motif. Mais nous savons 70 | également que lorsqu'une règle a été choisie, son motif sera utilisé pour 71 | extraire des données de la requête, qui seront ensuite placées dans des 72 | variables. Une règle est donc également composée de 73 | variables. Nous avons au total quatre éléments.
74 |Nous trouvons deux méthodes pour ajouter des règles sur un routeur :
75 | Hoa\Router\Router::addRule
pour ajouter une règle publique et
76 | Hoa\Router\Router::addPrivateRule
pour ajouter une règle privée.
77 | Les deux méthodes ont la même en-tête :
Les deux derniers paramètres sont optionnels. Nous verrons par la suite que 87 | le callable est en fait une variable, ce qui réduit notre 88 | liste aux quatre éléments énoncés précédemment.
89 |Prenons un exemple avec le routeur HTTP représenté par la classe
90 | Hoa\Router\Http
:
$router = new Hoa\Router\Http();
92 | $router->addRule('h', ['get'], '/hello')
93 | ->addRule('l', ['get', 'post'], '/login');
94 | Nous avons déclarés deux règles : h
et l
. La
95 | règle h
n'est accessible qu'à travers la méthode HTTP
96 | GET
et seule la requête (l'URI) /hello
correspond.
97 | La règle l
n'est accessible qu'à travers les méthodes HTTP
98 | GET
et POST
et seule la requête /login
99 | correspond. Toutes les deux sont des règles publiques.
Il existe un raccourci pour ajouter plus rapidement et plus facilement des 101 | règles. Nous pouvons ainsi écrire :
102 |$router->get('h', '/hello')
103 | ->get_post('l', '/login');
104 | La liste des méthodes peut être concaténées par le symbole
105 | « _
», puis utilisée comme nom de méthode sur le routeur. L'ordre
106 | des méthodes n'a toujours pas d'importance. Si nous voulons représenter toutes
107 | les méthodes, nous pourrons utiliser any
:
$router->any(…);
109 | Et enfin, pour représenter une règle privée, le nom devra commencer par le
110 | symbole « _
». Ainsi, ces deux déclarations sont strictement
111 | équivalentes :
$router->addPrivateRule('f', ['get', 'post'], '/foobar');
113 | $router->_get_post('f', '/foobar');
114 | Notons que nous pouvons supprimer à tout moment une règle avec la méthode
115 | Hoa\Router\Router::removeRule
à laquelle nous passons
116 | l'identifiant d'une règle. Nous sommes également capable de vérifier qu'une
117 | règle existe avec la méthode Hoa\Router\Router::ruleExists
et un
118 | identifiant de règle.
Maintenant que nous avons des règles, voyons à laquelle
123 | correspond une requête. Pour cela, nous allons utiliser la
124 | méthode Hoa\Router\Router::route
. L'en-tête de cette méthode
125 | dépend du routeur. Nous allons nous concentrer sur le router HTTP pour
126 | illustrer le concept, soit la méthode Hoa\Router\Http::route
. Le
127 | premier argument est l'URI, soit notre requête (ce paramètre est optionnel
128 | mais nous le verrons plus tard). Nous allons chercher la règle associée à
129 | l'URI /hello
. Si aucune exception
130 | Hoa\Router\Exception\NotFound
n'est levée, alors nous pouvons
131 | appeler la méthode Hoa\Router\Router::getTheRule
pour obtenir les
132 | informations sur la règle choisie ; voyons plutôt :
$router->route('/hello');
134 | print_r($router->getTheRule());
135 |
136 | /**
137 | * Will output:
138 | * Array
139 | * (
140 | * [0] => 0
141 | * [1] => h
142 | * [2] => Array
143 | * (
144 | * [0] => get
145 | * )
146 | *
147 | * [3] => /hello
148 | * [4] =>
149 | * [5] =>
150 | * [6] => Array
151 | * (
152 | * [_uri] => hello
153 | * [_method] => get
154 | * [_domain] =>
155 | * [_subdomain] =>
156 | * [_call] =>
157 | * [_able] =>
158 | * [_request] => Array
159 | * (
160 | * )
161 | *
162 | * )
163 | *
164 | * )
165 | */
166 | Les indices du tableau sont donnés par les constantes sur
167 | Hoa\Router\Router
suivantes :
RULE_VISIBILITY
, pour la visibilité de la
170 | règle (VISIBILITY_PUBLIC
ou
171 | VISIBILITY_PRIVATE
) ;RULE_ID
, pour l'identifiant ;RULE_METHODS
, pour les méthodes ;RULE_PATTERN
, pour le motif ;RULE_CALL
et RULE_ABLE
, pour le
176 | callable ;RULE_VARIABLES
, pour les variables.Ainsi, si nous voulons toutes les variables de la règle choisie, nous
180 | écrirons $theRule[$router::RULE_VARIABLES]
.
181 | C'est aussi simple que ça.
L'exception Hoa\Router\Exception\NotFound
signifie que la
183 | requête ne correspond à aucune règle. Par exemple :
try {
185 | $router->route('/foobar');
186 | } catch (Hoa\Router\Exception\NotFound $e) {
187 | echo $e->getMessage();
188 | }
189 |
190 | /**
191 | * Will output:
192 | * Cannot found an appropriated rule to route foobar.
193 | */
194 | Elle peut être levée à différentes étapes de la méthode
195 | Hoa\Router\Router::route
, avec des messages différents.
Jusqu'à maintenant, les motifs utilisés dans nos exemples 200 | sont constants : il n'y a pas de plages de caractères non-définis, 201 | pas de captures etc. Les motifs sont écrits avec des expressions régulières de 202 | type PCRE, ce qui nous permet de définir des règles avec des parties 203 | partiellement définies. Par exemple :
204 |$router->get('h', '/hello_(?<who>\w+)');
205 | Cela signifie que les requêtes correspondantes à la règle h
206 | sont de la forme /hello_word
. La valeur de
207 | word
sera placée dans la variable who
.
208 | Voyons plutôt :
$router->route('/hello_gordon');
210 | $theRule = $router->getTheRule();
211 | print_r($theRule[$router::RULE_VARIABLES]);
212 |
213 | /**
214 | * Will output:
215 | * Array
216 | * (
217 | * [_uri] => hello_gordon
218 | * [_method] => get
219 | * [_domain] =>
220 | * [_subdomain] =>
221 | * [_call] =>
222 | * [_able] =>
223 | * [_request] => Array
224 | * (
225 | * )
226 | *
227 | * [who] => gordon
228 | * )
229 | */
230 | Nous retrouvons notre variable who
qui vaut
231 | gordon
. Nous remarquons que le nom de certaines variables
232 | commence par le symbole « _
», comme _domain
ou
233 | _request
. Cela signifie que ce sont des variables déclarées par
234 | le routeur et non pas par l'utilisateur.
235 | Elles sont dites réservées. Chaque routeur a ses propres
236 | variables réservées. Notons que rien ne nous empêche d'utiliser leur nom dans
237 | une règle. Le routeur leur donne des valeurs « par défaut », c'est tout.
Nous avons extrait des données de la requête choisie. Le 239 | nombre de variables n'est pas limité. Ainsi :
240 |$router->get('h', '/hello_(?<who>\w+)(?<format>\.[a-z]+)');
241 | Avec /hello_gordon.html
, la variable who
sera
242 | égale à gordon
et format
sera égale à
243 | .html
. Avec /hello_gordon.42
, une exception
244 | Hoa\Router\Exception\NotFound
sera levée car .42
245 | n'est pas reconnu par le motif \.[a-z]+
et la requêe ne
246 | correspond à aucune autre règle.
Nous l'aurons compris, le motif est une expression régulière classique et 248 | nous utilisons les sous-masques nommés 249 | pour définir le nom des variables à extraire. Nous nous servons de son pouvoir 250 | d'expression pour filtrer (ou valider) les requêtes finement.
251 |Quand nous précisons des variables lors d'une déclaration de règle avec
252 | Hoa\Router\Router::addRule
(ou sa sœur
253 | Hoa\Router\Router::addPrivateRule
), il est possible de définir
254 | des valeurs par défaut pour les variables. Par exemple, si la
255 | partie format
devient optionnelle, nous voudrions que sa valeur
256 | par défaut soit .txt
:
$router->get(
258 | 'h',
259 | '/hello_(?<who>\w+)(?<format>\.[a-z]+)?',
260 | null,
261 | null,
262 | ['format' => '.txt']
263 | );
264 |
265 | $router->route('/hello_gordon');
266 | $theRule = $router->getTheRule();
267 | var_dump($theRule[$router::RULE_VARIABLES]['format']);
268 |
269 | /**
270 | * Will output:
271 | * string(4) ".txt"
272 | */
273 |
274 | $router->route('/hello_gordon.html');
275 | $theRule = $router->getTheRule();
276 | var_dump($theRule[$router::RULE_VARIABLES]['format']);
277 |
278 | /**
279 | * Will output:
280 | * string(5) ".html"
281 | */
282 | Il est important de savoir que le routeur traite les requêtes et les règles
283 | sans tenir compte de la casse, c'est à dire de la différence
284 | entre majuscule et minuscule. D'ailleurs, les données extraites des variables
285 | sont passées en minuscules selon les routeurs (ce qui est le
286 | cas de Hoa\Router\Http
par exemple). En effet, dans la plupart
287 | des situations, il est souhaitable que le routeur soit insensible à la casse.
288 | En revanche, il existe certains cas rares où la casse est importante. Par
289 | exemple avec un moteur de recherche où les mots-clés de la recherche sont
290 | contenus dans l'URI.
Les PCRE définissent les internal options permettant de
292 | changer les options d'une expression à la volée et à l'intérieur même d'une
293 | expression. Par exemple : les chaînes foo/bar/baz
ou
294 | FOO/bAr/BaZ
correspondent à l'expression
295 | #foo/bar/baz#i
car l'option globale i
rend
296 | l'expression entièrement insensible à la casse. Si nous voulons que seulement
297 | bar
soit sensible à la casse, nous écrirons :
298 | #foo/(?-i)bar(?i)/baz#i
. Alors FOO/bar/BaZ
sera
299 | valide, tout comme foo/bar/baz
mais pas FOO/bAr/BaZ
.
300 | Les options internes supportées par Hoa\Router
sont de la forme
301 | (?options)
pour activer des options et
302 | (?-options)
pour désactiver des options. Dès qu'une
303 | option interne désactive la casse, les données extraites de
304 | toutes les variables ne seront pas passées en minuscule si c'était le cas
305 | avant.
Par exemple, si nous voulons que tout ce qui suit /hello_
soit
307 | sensible à la casse, nous écrirons :
$router->get('h', '/hello_(?-i)(?<who>\w+)');
309 | $router->route('/hello_GorDON');
310 | $theRule = $router->getTheRule();
311 | var_dump($theRule[$router::RULE_VARIABLES]['who']);
312 |
313 | /**
314 | * Will output:
315 | * string(6) "GorDON"
316 | */
317 | Il arrivera rarement que nous ayons besoin des options internes mais il est 318 | important de les comprendre.
319 | 320 |L'opération inverse de
323 | Hoa\Router\Router::route
est
324 | Hoa\Router\Router::unroute
. Au minimum, il est demandé
325 | l'identifiant de la règle et une liste de
326 | variables. Cette méthode va construire une requête à partir
327 | d'une règle. Par exemple, nous aimerions produire la requête correspondante à
328 | la règle h
avec comme valeur alyx
pour
329 | who
et rien pour le format (la valeur par défaut sera utilisée).
330 | Alors, nous écrirons :
var_dump($router->unroute('h', ['who' => 'alyx']));
332 |
333 | /**
334 | * Will output:
335 | * string(15) "/hello_alyx.txt"
336 | */
337 | Cela implique que les requêtes, liens et autres URI de ressources peuvent
338 | être abstraits à partir d'identifiants et de variables. La
339 | syntaxe finale peut changer à tout moment sans casser l'application. Par
340 | exemple, changeons la règle h
pour :
$router->get('h', '/users/(?<who>\w+)/hello(?<format>\.[a-z]+)?');
342 | var_dump($router->unroute('h', ['who' => 'alyx']));
343 |
344 | /**
345 | * Will output:
346 | * string(21) "/users/alyx/hello.txt"
347 | */
348 | La souplesse d'un tel mécanisme permet de réduire considérablement la 349 | maintenance des applications ou d'augmenter leur modularité.
350 | 351 |Parmi les informations que nous retrouverons sur tous les routeurs, nous 355 | avons :
356 |Hoa\Router\Router::getMethod
pour connaître la
358 | méthode détectée par le routeur ;Hoa\Router\Router::isAsynchronous
pour connaître le type de
360 | communication détectée par le routeur (synchrone ou
361 | asynchrone).Certains routeurs exposent d'autres informations, mais celles-ci sont 364 | standards.
365 | 366 |Passons maintenant aux spécificités des routeurs en commençant par le
369 | routeur HTTP, représenté par la classe
370 | Hoa\Router\Http
.
Les méthodes supportées par le routeur sont un
372 | sous-ensemble des méthodes HTTP. Nous comptons : GET
,
373 | POST
, PUT
, PATCH
, DELETE
,
374 | HEAD
et OPTIONS
. Les variables
375 | réservées pour la méthode Hoa\Router\Http::route
sont :
_uri
, l'adresse ;_method
, la méthode HTTP ;_domain
, le domaine (de la forme
380 | domain.tld
) ;_subdomain
, le sous-domaine (que nous
382 | allons détailler) ;_call
et _able
, le
384 | callable ;_request
, la partie requête de l'URI, soit
386 | le contenu de la variable
387 | $_REQUEST
.Quand nous voudrons router une requête avec la méthode
390 | Hoa\Router\Http::route
, nous allons travailler sur deux données :
391 | l'URI et son préfixe. L'URI est à comprendre
392 | au sens HTTP, c'est le chemin vers une ressource. Par
393 | exemple, considérons la requête HTTP suivante :
GET /Foo/Bar.html
395 | Ici, l'URI est /Foo/Bar.html
(et la méthode est
396 | GET
). Le nom de domaine n'est jamais considéré, tout comme le
397 | port. Si l'URI est manquante, la méthode statique
398 | Hoa\Router\Http::getURI
sera appelée.
Le préfixe de l'URI permet de préciser quelle partie au
400 | début de l'URI ne devra pas être considérée durant l'analyse.
401 | Imaginons que votre application soit accessible depuis l'URI
402 | /Forum/
; une URI peut alors être :
403 | /Forum/Help/Newpost.html
. Le routeur n'est intéressé que par la
404 | partie /Help/Newpost.html
. Dans ce cas, le préfixe est
405 | Forum
(les slashes avant et après n'ont pas
406 | d'importance). Ainsi :
$router->route('/Forum/Help/Newpost.html', 'Forum');
408 | Toutefois, nous pouvons définir un préfixe pour toutes les requêtes, avec
409 | la méthode Hoa\Router\Http::setPrefix
:
$router->setPrefix('Forum');
411 | $router->route('/Forum/Help/Newpost.html');
412 | Pour obtenir le préfixe, nous pouvons utiliser la méthode
413 | Hoa\Router\Http::getPrefix
. Notons qu'avec la plupart des
414 | serveurs HTTP, Hoa\Router\Http
sait détecter
415 | automatiquement le préfixe, vous n'aurez donc pas à vous
416 | soucier de cette problématique.
Nous avons également les méthodes Hoa\Router\Http::getPort
418 | pour obtenir le port et Hoa\Router\Http::isSecure
pour savoir si
419 | la connexion est sécurisée ou pas.
La classe Hoa\Router\Http
sait également router les
424 | sous-domaines. Commençons par les méthodes auxquelles nous
425 | avons accès :
Hoa\Router\Http::getDomain
pour avoir le domaine en
428 | entier (c'est à dire avec les sous-domaines) sans le
429 | port ;Hoa\Router\Http::getStrictDomain
pour avoir
431 | uniquement le domaine, sans les sous-domaines ;Hoa\Router\Http::getSubdomain
pour avoir
433 | uniquement les sous-domaines.Si nous accédons à l'hôte (au serveur) à travers une IP, les méthodes
436 | Hoa\Router\Http::getDomain
et
437 | Hoa\Router\Http::getStrictDomain
nous retourneront cette IP (sans
438 | le port, encore une fois). Prenons un exemple avec le domaine
439 | sub2.sub1.domain.tld
:
var_dump(
441 | $router->getDomain(),
442 | $router->getStrictDomain(),
443 | $router->getSubdomain()
444 | );
445 |
446 | /**
447 | * Will output:
448 | * string(20) "sub2.sub1.domain.tld"
449 | * string(10) "domain.tld"
450 | * string(9) "sub2.sub1"
451 | */
452 | À l'instar des préfixes pour les URI, Hoa\Router\Http
453 | ajoute la notion de suffixe sur les sous-domaines,
454 | c'est à dire une partie à ne pas considérer durant l'analyse, mais cette fois,
455 | c'est la fin. Imaginons que votre application soit accessible
456 | depuis le domaine app.domain.tld
et que nous aimerions que le
457 | routeur reconnaisse les sous-domaines
458 | user.app.domain.tld
. Dans ce cas, le suffixe est
459 | app
. Nous utiliserons la méthode
460 | Hoa\Router\Http::setSubdomainSuffix
pour définir ce suffixe. La
461 | méthode Hoa\Router\Http::getSubdomain
retournera par défaut tous
462 | les sous-domaines, suffixe inclu. Nous devons lui donner false
en
463 | seul argument pour ne pas avoir le suffixe. Prenons un exemple avec le domaine
464 | gordon.app.domain.tld
:
$router->setSubdomainSuffix('app');
466 | var_dump(
467 | $router->getSubdomain(),
468 | $router->getSubdomain(false)
469 | );
470 |
471 | /**
472 | * Will output:
473 | * string(10) "gordon.app"
474 | * string(6) "gordon"
475 | */
476 |
477 | Bien. Maintenant voyons comment dire à une règle de
478 | travailler sur les sous-domaines. Une règle est en réalité constituée de
479 | deux expressions régulières, concaténées par
480 | le symbole @
(arobase), c'est à dire
481 | [subdomain@]URI
, avec la première partie qui
482 | est optionnelle. Si nous voulons reconnaître les sous-domaines de la forme
483 | user.domain.tld
et les URI de la forme
484 | /Project/project.html
, nous écrirons la règle
485 | p
suivante (accessible avec la méthode GET
486 | uniquement) :
$router->get('p', '(?<user>.*)@/Project/(?<project>[^\.]+)\.html');
488 | Si nous essayons de router la requête
489 | gordon.domain.tld/Project/Space-biker.html
, nous obtiendrons
490 | ceci :
$router->route();
492 | print_r($router->getTheRule());
493 |
494 | /**
495 | * Will output:
496 | * Array
497 | * (
498 | * [0] => 0
499 | * [1] => p
500 | * [2] => Array
501 | * (
502 | * [0] => get
503 | * )
504 | *
505 | * [3] => (?<user>.*)@/Project/(?<project>[^\.]+)\.html
506 | * [4] =>
507 | * [5] =>
508 | * [6] => Array
509 | * (
510 | * [_uri] => gordon.domain.tld/Project/Space-biker.html
511 | * [_method] => get
512 | * [_domain] => gordon.domain.tld
513 | * [_subdomain] => gordon
514 | * [_call] =>
515 | * [_able] =>
516 | * [_request] => Array
517 | * (
518 | * )
519 | *
520 | * [project] => space-biker
521 | * [user] => gordon
522 | * )
523 | *
524 | * )
525 | */
526 | Nous voyons bien nos deux variables : user
et
527 | project
respectivement définies à gordon
et
528 | space-biker
! Nous retrouvons aussi le sous-domaine dans la
529 | variable réservée _subdomain
, comme nous retrouvons également le
530 | domaine dans la variable réservée _domain
.
Maintenant passons à l'opération inverse : dérouter. Nous
532 | utilisons la règle p
et nous voulons construire la requête
533 | gordon.domain.tld/Project/Space-biker.html
. Il n'y aura aucune
534 | différence avec ce que nous avons vu précédemment :
var_dump(
536 | $router->unroute(
537 | 'p',
538 | [
539 | 'user' => 'gordon',
540 | 'project' => 'Space-biker'
541 | ]
542 | )
543 | );
544 |
545 | /**
546 | * Will output:
547 | * string(49) "http://gordon.domain.tld/Project/Space-biker.html"
548 | */
549 | La méthode Hoa\Router\Http::unroute
a deux
550 | variables réservées. Nous allons nous intéresser à la
551 | première : _subdomain
. Elle permet de définir la valeur du
552 | sous-domaine, elle écrasera complètement le sous-domaine mais
553 | le suffixe sera tout de même ajouté. Ainsi :
var_dump(
555 | $router->unroute(
556 | 'p',
557 | [
558 | 'project' => 'Space-biker',
559 | '_subdomain' => 'my-subdomain'
560 | ]
561 | )
562 | );
563 |
564 | /**
565 | * Will output:
566 | * string(55) "http://my-subdomain.domain.tld/Project/Space-biker.html"
567 | */
568 | Nous voyons que le sous-domaine est bien forcé à une valeur précise. La
569 | variable réservée _subdomain
peut avoir comme valeur trois
570 | mots-clés, chacun étant associé à une opération sur les
571 | sous-domaines :
__self__
représente tous les
574 | sous-domaines, suffixe compris ;__root__
supprime les sous-domaines, la
576 | requête n'aura que le suffixe et le domaine ;__shift__
permet de supprimer un
578 | sous-domaine (à gauche donc). Nous pouvons répéter cette opération
579 | n fois en écrivant __shift__ * n
. Le suffixe
580 | sera toujours ajouté.Prenons des exemples, ce sera plus simple. Nous sommes sur le domaine
583 | sub3.sub2.sub1.domain.tld
:
$router->get('s', '(?<three>[^\.]+)\.(?<two>[^\.]+)\.(?<one>.+)@');
585 | var_dump(
586 | // Normal.
587 | $router->unroute('s', ['three' => 'foo', 'two' => 'bar', 'one' => 'baz']),
588 |
589 | // Force.
590 | $router->unroute('s', ['_subdomain' => 'my-subdomain']),
591 |
592 | // Current subdomain.
593 | $router->unroute('s', ['_subdomain' => '__self__']),
594 |
595 | // No subdomain.
596 | $router->unroute('s', ['_subdomain' => '__root__']),
597 |
598 | // Shift only sub3.
599 | $router->unroute('s', ['_subdomain' => '__shift__']),
600 |
601 | // Shift two sub-domains.
602 | $router->unroute('s', ['_subdomain' => '__shift__ * 2'])
603 | );
604 |
605 | /**
606 | * Will output:
607 | * string(29) "http://foo.bar.baz.domain.tld"
608 | * string(30) "http://my-subdomain.domain.tld"
609 | * string(32) "http://sub3.sub2.sub1.domain.tld"
610 | * string(17) "http://domain.tld"
611 | * string(27) "http://sub2.sub1.domain.tld"
612 | * string(22) "http://sub1.domain.tld"
613 | */
614 | Notons que le symbole @
est présent à la fin de la règle. Ce
615 | serait une erreur de l'oublier, la règle s'appliquerait sur l'URI et non pas
616 | sur les sous-domaines.
Ces trois-mots clés nous permettent de faire face aux situations les plus 618 | courantes avec les sous-domaines. En effet, il arrive 619 | fréquemment de vouloir remonter d'un sous-domaine, ou de 620 | retourner à la racine directement, tout en conservant 621 | l'abstraction offerte par le routeur.
622 | 623 |Nous avons parlé de deux variables réservées pour la méthode
626 | Hoa\Router\Http::unroute
. Nous avons évoqué
627 | _subdomain
et c'est maintenant le tour de _fragment
.
628 | Cette variable réservée permet de définir le fragment d'une
629 | URI, c'est à dire la partie après le symbole #
(dièse). Par
630 | exemple dans /Project/Space-biker.html#Introduction
, le fragment
631 | est Introduction
. Ainsi :
var_dump(
633 | $router->unroute(
634 | 'p',
635 | [
636 | 'user' => 'gordon',
637 | 'project' => 'Space-biker',
638 | '_fragment' => 'Introduction'
639 | ]
640 | )
641 | );
642 |
643 | /**
644 | * Will output:
645 | * string(62) "http://gordon.domain.tld/Project/Space-biker.html#Introduction"
646 | */
647 |
648 |
649 |
650 | Les ports HTTP par défaut sont 80 pour une connexion
653 | non-cryptée et 443 pour une connexion
654 | cryptée (avec TLS). Pour obtenir ces valeurs de ports, nous
655 | pouvons utiliser la méthode Hoa\Router\Http::getDefaultPort
.
656 | Naturellement, nous aurons le port par défaut pour une connexion non-cryptée.
657 | En revanche, si nous donnons Hoa\Router\Http::SECURE
en seul
658 | argument, nous aurons le port par défaut pour une connexion cryptée.
659 | Ainsi :
var_dump($router->getDefaultPort());
661 |
662 | /**
663 | * Will output:
664 | * int(80)
665 | */
666 | La valeur des ports par défaut se met à jour toute seule.
667 | Par exemple, si les requêtes arrivent sur une connexion non-cryptée à travers
668 | le port 8880, Hoa\Router\Http
changera 80 par 8880
669 | automatiquement. Toutefois, pour modifier les ports par défaut manuellement,
670 | nous utiliserons la méthode Hoa\Router\Http::setDefaultPort
, avec
671 | en premier argument la valeur du port et en second argument l'une des deux
672 | constantes : Hoa\Router\Http::SECURE
ou
673 | Hoa\Router\Http::UNSECURE
, indiquant si c'est pour une connexion
674 | cryptée ou pas.
Ces numéros de port par défaut sont importants quand nous appelons la
676 | méthode Hoa\Router\Http::unroute
et qu'un domaine avec un port
677 | doit être reconstitué. C'est le cas, par exemple, si nous forçons à dérouter
678 | vers une connexion cryptée, à l'aide du troisième argument de cette méthode en
679 | lui donnant Hoa\Router\Http::SECURE
:
var_dump(
681 | $router->unroute(
682 | 'p',
683 | ['user' => 'gordon', 'project' => 'Space-biker'],
684 | true
685 | )
686 | );
687 | $router->setDefaultPort(8443, Hoa\Router\Http::SECURE);
688 | var_dump(
689 | $router->unroute(
690 | …
691 | )
692 | );
693 |
694 | /**
695 | * Will output:
696 | * string(50) "https://gordon.domain.tld/Project/Space-biker.html"
697 | * string(55) "https://gordon.domain.tld:8443/Project/Space-biker.html"
698 | */
699 | Nous remarquons que le protocole HTTPS est utilisé. Dans le premier cas, le 700 | port n'est pas affiché car sa valeur par défaut est 443 et c'est un standard. 701 | En revanche, quand nous modifions le port par défaut pour 8443, le port est 702 | bien affiché.
703 | 704 |Le routeur CLI permet de manipuler des requêtes dans un
707 | terminal. Il est représenté par la classe
708 | Hoa\Router\Cli
.
Ce routeur ne supporte qu'une seule méthode :
710 | GET
. Les variables réservées pour la méthode
711 | Hoa\Router\Cli::route
sont :
_call
et _able
, le
714 | callable ;_tail
, contient les options et les
716 | entrées d'une ligne de commande (optionnelle).La méthode Hoa\Router\Cli::route
n'a qu'un seul argument :
719 | l'URI ; par exemple avec :
$ command --option value input
721 | Dans ce contexte, l'URI est la ligne de commande, ou plus précisément, ce
722 | qui suit la commande, sans distinction ; soit --option value
723 | input
. Nous pouvons nous en rendre compte en appelant la méthode
724 | statique Hoa\Router\Cli::getURI
. Il n'y pas de notion de préfixe
725 | comme pour Hoa\Router\Http
.
Prenons un exemple très courant qui consiste à avoir une ligne de commande
727 | la forme command group:subcommand
728 | options
. Nous écrirons la règle g
suivante dans
729 | le fichier Router.php
:
$router = new Hoa\Router\Cli();
731 | $router->get(
732 | 'g',
733 | '(?<group>\w+):(?<subcommand>\w+)(?<_tail>.*?)'
734 | );
735 |
736 | $router->route();
737 | $theRule = $router->getTheRule();
738 | print_r($theRule[$router::RULE_VARIABLES]);
739 | Nous pouvons exécuter le fichier de la façon suivante :
740 |$ php Router.php foo:bar baz
741 | Array
742 | (
743 | [group] => foo
744 | [subcommand] => bar
745 | [_call] =>
746 | [_able] =>
747 | [_tail] => baz
748 | )
749 | La variable _tail
a une signification particulière. Il faut
750 | savoir que nous nous en servons pour capturer les options et les entrées d'une
751 | ligne de commande afin de les analyser avec
752 | Hoa\Console
753 | par la suite.
Nous pouvons avoir envie que group
soit
755 | optionnel (avec default
comme valeur par
756 | défaut), tout comme subcommand
(avec la même valeur par
757 | défaut). Dans ce cas, la règle deviendrait :
$router->get(
759 | 'g',
760 | '(?<group>\w+)?(:(?<subcommand>\w+))?(?<_tail>.*?)',
761 | null,
762 | null,
763 | [
764 | 'group' => 'default',
765 | 'subcommand' => 'default'
766 | ]
767 | );
768 | Ainsi, nous pourrions avoir group
,
769 | group:subcommand
ou :subcommand
.
770 | Testons avec subcommand
absent dans un premier temps,
771 | puis avec group
absent dans un second temps :
$ php Router.php foo baz
773 | Array
774 | (
775 | [group] => foo
776 | [subcommand] => default
777 | [_call] =>
778 | [_able] =>
779 | [_tail] => baz
780 | )
781 | $ php Router.php :baz baz
782 | Array
783 | (
784 | [group] => default
785 | [subcommand] => bar
786 | [_call] =>
787 | [_able] =>
788 | [_tail] => baz
789 | )
790 |
791 | Rien de plus simple avec Hoa\Router\Cli
. Nous pouvons toujours
792 | regarder le script hoa
(dans
793 | hoa://Library/Cli/Bin/Hoa.php
)
794 | pour avoir un exemple concret.
Lorsque le routeur reçoit une requête et qu'il trouve une règle qui la
800 | reconnaît, il pourra en extraire des données. C'est ce que fait
801 | Hoa\Router\Router::route
. Nous obtenons les informations de la
802 | règle avec Hoa\Router\Router::getTheRule
. Nous remarquons que
803 | tous les routeurs ont les variables réservées
804 | _call
et _able
: elles permettent de définir un
805 | callable. Ces variables peuvent être alors
806 | réutilisées pour dispatcher la requête. C'est exactement le
807 | rôle de Hoa\Dispatcher
et
808 | c'est la suite logique de Hoa\Router
.
La bibliothèque Hoa\Router
offre une
813 | interface et un fonctionnement commun à des
814 | routeurs. Un routeur est capable de reconnaître une requête à
815 | partir de plusieurs règles et d'en extraire des
816 | données. Actuellement, deux routeurs sont proposés :
817 | Hoa\Router\Http
et Hoa\Router\Cli
.
2 |
3 |
14 | Hoa is a modular, extensible and
15 | structured set of PHP libraries.
16 | Moreover, Hoa aims at being a bridge between industrial and research worlds.
17 |