Routage
Elgg dispose de deux mécanismes pour répondre aux requêtes HTTP qui ne passent pas déjà par les systèmes des Actions et du Simplecache - Cache simple.
Identifiant d’URL et segments
Après avoir retiré l’URL du site, Elgg découpe le chemin de l’URL par /
dans un tableau. Le premier élément, l’identificateur, est mis de côté, et les éléments restants sont appelés les segments. Par exemple, si l’URL du site est http://example.com/elgg/
, l’URL http://example.com/elgg/blog/owner/jane?foo=123
produit :
Identificateur : 'blog'
. Segments : ['owner', 'jane']
. (les paramètres de la chaîne de requête sont disponibles via get_input()
)
L’URL du site (page d’accueil) est un cas spécial qui produit un identificateur de chaîne vide et un tableau de segments vide.
Avertissement
Les identificateurs/segments d’URL doivent être considérés comme des entrées utilisateur potentiellement dangereuses. Elgg utilise dessus htmlspecialchars
pour échapper les entités HTML.
Gestion des pages
Elgg offre des outils pour gérer les pages de votre plugin via des routes personnalisées, permettant des URLs comme http://yoursite/my_plugin/section
. Vous pouvez enregistrer une nouvelle route en utilisant elgg_register_route()
ou via la configuration routes
dans elgg-plugin.php
. Les routes assurent la correspondance avec les vues de ressources, où vous pouvez générer le contenu de la page.
// in your 'init', 'system' handler
elgg_register_route('my_plugin:section' [
'path' => '/my_plugin/section/{guid}/{subsection?}',
'resource' => 'my_plugin/section',
'requirements' => [
'guid' => '\d+',
'subsection' => '\w+',
],
]);
// in my_plugin/views/default/resources/my_plugin/section.php
$guid = elgg_extract('guid', $vars);
$subsection = elgg_extract('subsection', $vars);
// render content
Dans l’exemple ci-dessus, nous avons enregistré une nouvelle route qui est accessible via http://yoursite/my_plugin/section/<guid>/<subsection>
. Chaque fois que cette route est accédée avec le segment requis guid
et un segment facultatif subsection
, le routeur va afficher la vue de la ressource spécifiée my_plugin/section
et transmettre les paramètres extraits de l’URL à votre vue de ressource via $vars
.
Noms des routes
Les noms de routes peuvent ensuite être utilisés pour générer une URL :
$url = elgg_generate_url('my_plugin:section', [
'guid' => $entity->guid,
'subsection' => 'assets',
]);
Les noms d’itinéraires sont uniques pour l’ensemble des plugins et pour le noyau, de sorte qu’un autre plugin peut surcharger une route en enregistrant d’autres paramètres sur le même nom de route.
Les noms des routes respectent un certain formalisme et seront, dans certains cas, utilisés pour résoudre automatiquement les URLs, par exemple pour afficher une entité.
Les conventions suivantes sont utilisées dans le noyau et recommandées pour les plugins :
- view :<entity_type>:<entity_subtype>
Correspond à la page de profil de l’entité, par exemple
view:user:user
ouview:object:blog
. Le chemin d’accès doit contenir unguid
, ou unusername
pour les utilisateurs- edit:<entity_type>:<entity_subtype>
Correspond au formulaire pour modifier l’entité, par exemple
edit:user:user
ouedit:object:blog
. Le chemin d’accès doit contenir unguid
, ou unusername
pour les utilisateurs. Si vous avez besoin d’ajouter des sous-ressources, utilisez des suffixes, par exempleedit:object:blog:images
, en gardant au moins une sous-ressource sans suffixe par défaut.- add:<entity_type>:<entity_subtype>
Correspond au formulaire pour ajouter une nouvelle entité d’un type donné, par exemple
add:object:blog
. Le chemin d’accès, en règle générale, contient le paramètrecontainer_guid
- collection:<entity_type>:<entity_subtype>:<collection_type>
Correspond aux pages de listes. Les noms de routes couramment utilisés dans le noyau sont les suivants :
collection:object:blog:all
: liste tous les articles de blogcollection:object:blog:owner
: liste les articles de blog appartenant à un utilisateur avec un identifiant donnécollection:object:blog:friends
: liste les articles de blog appartenant à des contacts de l’utilisateur connecté (ou d’un utilisateur avec un identifiant donné)collection:object:blog:group
: liste les articles de blog dans un groupe
- default:<entity_type>:<entity_subtype>
Fait correspondre à la page par défaut pour une ressource, par exemple pour le chemin d’accès
/blog
. Elgg utilise la collection « all » pour ces routes.default:object:blog
: gère le chemin générique/blog
.
<entity_subtype>
peut être omis des noms de routes pour enregistrer des routes globales applicables à toutes les entités d’un type donné. Le générateur d’URL va d’abord essayer de générer une URL à l’aide du sous-type, puis se replie sur un nom de route sans sous-type. Par exemple, les profils utilisateur sont acheminés vers la même vue de ressource quel que soit le sous-type utilisateur.
elgg_register_route('view:object:attachments', [
'path' => '/attachments/{guid}',
'resource' => 'attachments',
]);
elgg_register_route('view:object:blog:attachments', [
'path' => '/blog/view/{guid}/attachments',
'resource' => 'blog/attachments',
]);
$blog = get_entity($blog_guid);
$url = elgg_generate_entity_url($blog, 'view', 'attachments'); // /blog/view/$blog_guid/attachments
$other = get_entity($other_guid);
$url = elgg_generate_entity_url($other, 'view', 'attachments'); // /attachments/$other_guid
Configuration du routage
Les segments peuvent être définis à l’aide de jokers, par exemple profile/{username}
, qui correspond à toutes les URL qui contiennent profile/
suivies d’un nom d’utilisateur arbitraire.
Pour rendre un segment facultatif, vous pouvez ajouter un ?
(point d’interrogation) au nom du joker, par exemple profile/{username}/{section?}
. Dans ce cas, l’URL va correspondre même si le segment section
n’est pas fourni.
Vous pouvez contraindre davantage les segments en utilisant les exigences regex :
// elgg-plugin.php
return [
'routes' => [
'profile' => [
'path' => '/profile/{username}/{section?}',
'resource' => 'profile',
'requirements' => [
'username' => '[\p{L}\p{Nd}._-]+', // only allow valid usernames
'section' => '\w+', // can only contain alphanumeric characters
],
'defaults' => [
'section' => 'index',
],
],
]
];
Par défaut, Elgg va définir les exigences suivantes pour les segments d’URL nommés :
$patterns = [
'guid' => '\d+', // only digits
'group_guid' => '\d+', // only digits
'container_guid' => '\d+', // only digits
'owner_guid' => '\d+', // only digits
'username' => '[\p{L}\p{Nd}._-]+', // letters, digits, underscores, dashes
];
Routes dépendant d’un plugin
Si une route a besoin qu’un plugin spécifique soit actif, cela peut être configuré dans la configuration de la route.
// elgg-plugin.php
return [
'routes' => [
'collection:object:blog:friends' => [
'path' => '/blog/friends/{username?}/{lower?}/{upper?}',
'resource' => 'blog/friends',
'required_plugins' => [
'friends', // route only allowed when friends plugin is active
],
],
]
];
Middleware de routage
Les middlewares de gestion du routage peuvent être utilisés pour empêcher l’accès à une certaine route, ou pour exécuter une certaine logique avant que la route ne soit rendue. Un middleware peut être utilisé, par exemple pour implémenter un système d’inscription payante, ou pour définir des métadonnées open graph.
Le noyau de Elgg implémente plusieurs gestionnaires de middleware. Le middleware suivant se trouve dans l’espace de noms \Elgg\Router\Middleware
:
Gatekeeper
Ce gestionnaire d’accès empêchera l’accès des utilisateurs non authentifiés.
AdminGatekeeper
Ce gestionnaire d’accès empêchera l’accès des utilisateurs non-administrateurs.
LoggedOutGatekeeper
Ce gestionnaire d’accès empêchera l’accès à tout utilisateur authentifié.
AjaxGatekeeper
Ce gestionnaire d’accès empêchera l’accès à toute demande non-XHR.
PageOwnerGatekeeper
Ce contrôleur d’accès empêchera l’accès s’il n’y a pas d’entité propriétaire de la page.
GroupPageOwnerGatekeeper
Ce contrôleur d’accès étend PageOwnerGatekeeper
et requiert également que le propriétaire de la page soit une entité ElggGroup
.
UserPageOwnerGatekeeper
Ce contrôleur d’accès étend le PageOwnerGatekeeper
et requiert également que le propriétaire de la page soit une entité ElggUser
.
PageOwnerCanEditGatekeeper
Ce contrôleur d’accès bloquera l’accès si aucun propriétaire de page n’est détecté et que le propriétaire de la page ne peut pas être modifié.
GroupPageOwnerCanEditGatekeeper
Ce gestionnaire d’accès étend PageOwnerCanEditGatekeeper
mais exige également que le propriétaire de la page soit une entité ElggGroup
.
UserPageOwnerCanEditGatekeeper
Ce gestionnaire d’accès étend PageOwnerCanEditGatekeeper
mais exige également que le propriétaire soit une entité ElggUser
.
CsrfFirewall
Ce middleware empêchera l’accès sans les jetons CSRF corrects. Ce middleware sera automatiquement appliqué aux actions.
ActionMiddleware
Ce middleware fournira une logique liée à l’action. Ce middleware sera automatiquement appliqué aux actions.
SignedRequestGatekeeper
Ce gestionnaire d’accès empêchera l’accès si l’URL a été trafiquée. Une URL sécurisée peut être générée à l’aide de la fonction elgg_http_get_signed_url
.
UpgradeGatekeeper
Ce gestionnaire d’accès empêchera l’accès si l’URL de mise à niveau est sécurisée et que l’URL n’est pas valide.
WalledGarden
Ce middleware empêchera l’accès à une route si le site est configuré uniquement pour les utilisateurs authentifiés et qu’aucun utilisateur authentifié n’est connecté. Ce middleware est automatiquement activé pour toutes les routes. Vous pouvez désactiver le gardien du walled garden avec une option de configuration de route.
Middleware personnalisé
Les gestionnaires de middleware peuvent être définis par n’importe quelle fonction appellable qui reçoit une instance de \Elgg\Request
: le gestionnaire devrait lancer une instance de \Elgg\Exceptions\HttpException
pour empêcher l’accès à la route. Le gestionnaire peut renvoyer une instance de \Elgg\Http\ResponseBuilder
pour empêcher la poursuite de la mise en œuvre de la séquence de routage (une réponse de redirection peut être renvoyée pour réacheminer la requête).
class MyMiddleware {
public function __invoke(\Elgg\Request $request) {
$entity = $request->getEntityParam();
if ($entity) {
// do stuff
} else {
throw new EntityNotFoundException();
}
}
}
elgg_register_route('myroute', [
'path' => '/myroute/{guid?}',
'resource' => 'myroute',
'middleware' => [
\Elgg\Router\Middleware\Gatekeeper::class,
MyMiddleware::class,
]
]);
Contrôleurs de routage
Dans certains cas, l’utilisation des vues de ressources n’est pas appropriée. Dans ces cas, vous pouvez utiliser un contrôleur - toute fonction appelable qui reçoit une instance de \Elgg\Request
:
class MyController {
public function handleFoo(\Elgg\Request $request) {
elgg_set_http_header('Content-Type: application/json');
$data = [
'entity' => $request->getEntityParam(),
];
return elgg_ok_response($data);
}
}
elgg_register_route('myroute', [
'path' => '/myroute/{guid?}',
'controller' => [MyController::class, 'handleFoo'],
]);
L’événement route:rewrite
Pour la réécriture d’URL, l’événement route:rewrite
(avec des arguments similaires à route
) est déclenché très tôt, et permet de modifier le chemin de l’URL de la requête (par rapport au site Elgg).
Ici, nous réécrivons les requêtes de news/*
vers blog/*
:
function myplugin_rewrite_handler(\Elgg\Event $event) {
$value = $event->getValue();
$value['identifier'] = 'blog';
return $value;
}
elgg_register_event_handler('route:rewrite', 'news', 'myplugin_rewrite_handler');
Avertissement
L’événement doit être enregistré directement dans la fonction boot
du Bootstrap de votre plugin. La fonction init
arrive trop tard.
Aperçu du routage
Pour les pages standard, le flux de programme de Elgg est quelque chose comme ceci :
Un utilisateur demande
http://example.com/news/owner/jane
.Les plugins sont initialisés.
Elgg analyse l’URL pour l’identificateur
news
et les segments['owner', 'jane']
.Elgg déclenche l’événement
route:rewrite, news
(voir ci-dessus).Elgg trouve une route enregistrée qui correspond au chemin d’accès final de la route, et affiche la vue de ressource qui lui est associée, en appellant
elgg_view_resource('blog/owner', $vars)
, où$vars
contient le nom d’utilisateur.La vue
resources/blog/owner
obtient le nom d’utilisateur via$vars['username']
et utilise de nombreuses autres vues et fonctions de mise en forme telles queelgg_view_layout()
etelgg_view_page()
pour créer la page HTML complète.PHP invoque la séquence d’arrêt de Elgg.
L’utilisateur reçoit une page complète.
Les normes de codage de Elgg suggèrent une disposition d’URL particulière, mais il n’y a pas de syntaxe obligatoire.