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 Formulaires + Actions et du Simplecache - Cache simple.
Contenu
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>
Maps to the entity profile page, e.g.
view:user:userorview:object:blog. The path must contain aguid, orusernamefor users- edit:<entity_type>:<entity_subtype>
Maps to the form to edit the entity, e.g.
edit:user:useroredit:object:blog. The path must contain aguid, orusernamefor users. If you need to add subresources, use suffixes, e.g.edit:object:blog:images, keeping at least one subresource as a default without suffix.- add:<entity_type>:<entity_subtype>
Maps to the form to add a new entity of a given type, e.g.
add:object:blog. The path, as a rule, containscontainer_guidparameter- 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
];
Note
Vous pouvez avoir les paramètres de route username et/ou guid remplis avec les valeurs de l’utilisateur connecté par défaut si vous ajoutez l’indicateur use_logged_in et le définissez sur true.
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.
GroupToolGatekeeper
This gatekeeper extends the GroupPageOwnerGatekeeper and will additionally validate that the configured group tool
is enabled.
To provide the GroupToolGatekeeper with the group tool to check add it to the route options.
// in elgg-plugin.php
'routes' => [
'collection:object:news:group' => [
'path' => '/news/group/{guid}',
'controller' => \Elgg\Controllers\GenericContentListing::class,
'options' => [
'group_tool' => 'news',
],
],
],
Note
When the group tool is configured in the route options the GroupToolGatekeeper is automaticly added as middleware.
If a group tool is provided there is no need to add the GroupPageOwnerGatekeeper middleware.
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'],
]);
Listing controller
Elgg offers a default listing controller. This controller will render a full page with:
A title
A breadcrumb
The default filter tabs
An add new content button (if available)
The list of content items
All of this is done based of the recommended route names.
collection:<entity_type>:<entity_subtype>:<collection_type> default:<entity_type>:<entity_subtype>
The title of the page will be the language key collection:<entity_type>:<entity_subtype>:<collection_type>
for the default:<entity_type>:<entity_subtype> route this will be collection:<entity_type>:<entity_subtype>:all.
// elgg-plugin.php
return [
'routes' => [
'collection:object:my_content:all' => [
'path' => '/my_path/all',
'controller' => \Elgg\Controllers\GenericContentListing::class,
],
'collection:object:my_content:friends' => [
'path' => '/my_path/friends/{username}',
'controller' => \Elgg\Controllers\GenericContentListing::class,
'middleware' => [
\Elgg\Router\Middleware\UserPageOwnerGatekeeper::class,
],
],
'collection:object:my_content:group' => [
'path' => '/my_path/group/{guid}',
'controller' => \Elgg\Controllers\GenericContentListing::class,
'middleware' => [
\Elgg\Router\Middleware\GroupPageOwnerGatekeeper::class, // no needed if a group tool is provided
],
'options' => [
'group_tool' => 'my_group_tool', // optional, if provided the group will need to have this tool enabled
],
],
'collection:object:my_content:owner' => [
'path' => '/my_path/owner/{username}',
'controller' => \Elgg\Controllers\GenericContentListing::class,
'middleware' => [
\Elgg\Router\Middleware\UserPageOwnerGatekeeper::class,
],
'options' => [
'sidebar_view' => 'my_content/sidebar', // optional
],
],
'default:object:my_content' => [
'path' => '/my_path',
'controller' => \Elgg\Controllers\GenericContentListing::class,
],
],
];
If you have an additional collection listing you can extend the \Elgg\Controllers\GenericContentListing class
and add a function listCollectionType where CollectionType is taken from the route name and made into a camel case
for example collection:object:my_content:my_listing will call the function listMyListing().
There are helper function in the controller you can extend if you just need to change some parameters.
Note
If you provide your route definition with an option sidebar_view that view will be called during the rendering of
the page.
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
newset 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ù$varscontient le nom d’utilisateur.La vue
resources/blog/ownerobtient 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.