Project

General

Profile

Specification #179

Routes dans chill

Added by Julien Fastré about 5 years ago. Updated over 4 years ago.

Status:
Closed
Priority:
Low
Assignee:
-
Category:
-
Target version:
-
Start date:
10/14/2014
Due date:
% Done:

0%


Description

Les fonctionnalités attendues sont :

  • permettre aux développeurs et aux designers d'ajouter des liens de menus facilement dans l'application, aux endroits les plus adéquats, dans l'ordre qu'ils attendent ;
  • éviter aux installateurs d'avoir à manipuler les liens de menu ou les fichiers de configuration ;
  • permettre aux développeurs et aux designers de n'avoir pas à se soucier des différentes configurations d'installation: les menus doivent fonctionner, quels que soient les modules installés

situation actuelle (dans le prototype)

définition des liens de menu

Dans les fichiers routing.yml du bundle (ici, @ChillPersonBundle/Resources/config/routing.yml), les routes à inclure dans un menu ont des paramètres spécifiques sous la clé "options" :

chill_person_view:
    pattern: /view/{id}
    defaults: { _controller: CLChillPersonBundle:Person:view }
    options:
        menu: person #inclut la route dans le menu personne...
        order: 50 #avec le numéro d'ordre "50" 
        label: menu.person.general_view #et le label ci-joint (qui sera traduit)

Dans le fichier routing.yml, on retrouve une ligne qui inclut le fichier ci-dessus :

cl_chill_person:
    resource: "@CLChillPersonBundle/Resources/config/routing.yml" 
    prefix:   /person/

Notons que l'ordre des menus n'est pas incrémenté par pas de 1, mais par des multiples plus grand, ce qui permettra d'intercaler les menus qui viendraient s'ajouter.

utilisation dans les templates

Dans les templates, un appel à un contrôleur specifique permet d'afficher le rendu demander :

{{ render(controller("CLChillMainBundle:Menu:writeMenu", {
             'menu' : 'person', 
             'layout': 'CLChillPersonBundle::menu.html.twig',
             'args' : {'id': person.id },
             'activeRouteKey': activeRouteKey
        })) }}

Les paramètres de la fonction sont les suivants :

  • 'menu' : est le nom du menu. Le contrôleur utilisera toute les routes qui ont la clé "options.menu" = "person" dans l'exemple ci-dessus ;
  • layout: est le layout utilisé pour le rendu ;
  • les arguments : les arguments nécessaire pour re-créer les routes. Ici, l'id de la personne est demandé.
  • activeRouteKey : la clé de menu actif (dans l'exemple plus haut, `chill_person_view`). Grâce à cette information, le service pourra connaitre le lien de menu actif et le mettre en forme de manière différente.

Le paramètre "activeRouteKey" est défini dans la vue (ici dans '@PersonChillBundle/Resources/views/person/view.html.twig':

{% set activeRouteKey = 'chill_person_view' %}

Problèmes

avoir une même route dans plusieurs menus

Pour l'instant, il n'est pas possible d'avoir un même route dans plusieurs menus.

solution proposée

L'idée est de modifier la définition des routes dans le fichier routing.yml du bundle pour que les menus soient dans un tableau plutôt que comme variable scalaire :

Le schéma proposé est le suivant :

chill_person_view:
    pattern: /view/{id}
    defaults: { _controller: CLChillPersonBundle:Person:view }
    options:
        menus:
           - person:
              order: 50
              label: menu.person.general_view
           - future_menu:
              order: 150
              label: future_label

conflits entre bundle

Avec la multiplication des bundle, il est possible qu'il y ait des conflits dans l'ordre des routes: que deux bundles différents créent une route avec un 'order' identique.

solution proposée

  • Détecter les numéros d'ordre de routes qui seraient double et les modifier à la volée au moment du rendu (par exemple, changer le numéro "50" en numéro "51" si celui-ci existe déjà.

problème de paramètres

Des paramètres sont nécessaires aux routes rendues dans le menu (ici, l'id de la person). Tant que les paramètres sont identiques, tout se passe bien. Si, par contre, il est nécessaire d'avoir des paramètres supplémentaires, il faut que le template qui "commande" le rendu de menu les ait fourni explicitement. Cela pourra être un problème pour les bundle qui seront créés par la suite.

solution

Pas vraiment de solution pour le moment, sauf celle de baser par des standards et des codes.

  • définir les paramètres qui peuvent être requis par menu (par exemple, pour le menu 'person', les routes ne peuvent que requérir le paramètre 'person.id'). Et tant pis pour ceux qui voudraient plus...

la configuration actuelle impose à l'installeur de modifier le fichier app/config/routing.yml

solution

Utiliser le tout nouveau routing loader (depuis symfony 2.5 ?) : http://symfony.com/doc/current/cookbook/routing/custom_route_loader.html

Le fichier app/config/routing.yml ne devra être modifié qu'une fois (dans l'installation de base), comme décrit ici : http://symfony.com/doc/current/cookbook/routing/custom_route_loader.html#using-the-custom-loader.


Subtasks

ChillMain - Feature #237: Implémenter la clé "condition" dans le routingNew

ChillMain - Feature #238: Implement "access" key in routingNew


Related issues

Related to Chill - Feature #217: Update the routing feature & test Closed 09/24/2014 10/03/2014

Associated revisions

Revision c91a667c
Added by Julien Fastré almost 5 years ago

add chill_menu to render easily menu, refs #179

Revision 68df4008
Added by Julien Fastré almost 5 years ago

add chill_menu to render easily menu, refs #179

History

#1 Updated by Julien Fastré about 5 years ago

L'ajout du custom loader dans app/config/routing.yml devra être fait manuellement s'il n'y a pas d'extension de la hiérarchie de base de symfony.

On pourrait, pour faciliter la tâche à l'installer, créer un post-install script qui ajoutera ces lignes.

#2 Updated by Julien Fastré almost 5 years ago

Je me rends compte qu'il manque un cas d'utilisation à ce qui est exposé ci-dessus: dans certains menus, il est parfois nécessaire d'en savoir un peu plus sur le contexte pour pouvoir adapter son comportement.

Par exemple: une personne a certaines caractéristiques qui doit laisser l'utilisateur avoir accès à certains écrans. Par exemple: une personne est mineur d'âge, il faut pouvoir introduire les coordonnées de ses tuteurs. Une personne est "MENA" (Mineur Non Accompagné): il faut remplir certaines caractéristiques supplémentaire. Une autre est résidente d'une commune avec une convention particulière, il faut pouvoir y avoir accès. Etc.

Je propose de remplacer les "args" (arguments) par un "context" et que le template communique au service de rendu des menu ce contexte.

Concrètement, plutôt que


{{ render(controller("CLChillMainBundle:Menu:writeMenu", {
             'menu' : 'person', 
             'layout': 'CLChillPersonBundle::menu.html.twig',
             'args' : {'id': person.id },
             'activeRouteKey': activeRouteKey
        })) }}

On aurait :


{{ render(controller("CLChillMainBundle:Menu:writeMenu", {
             'menu' : 'person', 
             'layout': 'CLChillPersonBundle::menu.html.twig', 
             'context' : {'person': person }, #cette ligne a changé
             'activeRouteKey': activeRouteKey
        })) }}

Le service pourrait alors faire des opérations plus complexes. Par exemple:


if ($person->getAge() < 18) {
  #ajoute routes specifiques aux mineurs d'âges
}

#3 Updated by Julien Fastré almost 5 years ago

  • Related to Feature #217: Update the routing feature & test added

#4 Updated by Julien Fastré almost 5 years ago

Je me rends compte de deux manques dans ce qu'on a défini :

options supplémentaires

Dans la version précédente de Chill, en projet en décembre dernier, on avait ajouté un champ "helper" à la définition des routes. C'était utilisé pour afficher un message d'aide supplémentaire dans l'admin. Ca donnait quelque chose comme :

chill_person_view:
    pattern: /view/{id}
    defaults: { _controller: CLChillPersonBundle:Person:view }
    options:
        menu: person #inclut la route dans le menu personne...
        order: 50 #avec le numéro d'ordre "50" 
        label: menu.person.general_view #et le label ci-joint (qui sera traduit)

Je propose donc que l'on définisse plutôt :

* des options obligatoire qui ont été définies plus haut : les attributs key (le nom du menu), order, label

Ca donnerait donc ceci (déjà évoqué plus haut) :

chill_person_view:
    pattern: /view/{id}
    defaults: { _controller: CLChillPersonBundle:Person:view }
    options:
        menus: 
           - person: #the key of the menu. Keeping this as a key ease the performance (we do not need to iterate all menus options in service MenuComposer)
              order: 50
              label: menu.person.general_view
           - future_menu:
              order: 150
              label: future_label

* des options 'protégées', utilisées optionnellement

* un attribut "helper" avec un texte d'aide

Sera utilisé comme texte d'aide dans certains menus.

* un attribut "condition" qui sera évalué avec Expression Language

Evaluera les conditions en fonction du contexte. Par exemple, si un menu n'est accessible que pour les personnes de moins de 18 ans, on pourra avoir qqch comme :

menus:
  - person:
    order: 100
    label: school
    condition: 'person.age < 18' #attention qu'il faudra crée une fonction "getAge" dans la class person

Cette fonction serait reportée à une version 2

une option "access" qui considérera les droits de l'agent

Cela permettra de n'afficher que des menus pour les personnes qui ont les droits requis. On pourra également le baser sur Expression Language, et on utilisera "agent" comme représentation de l'utilisateur, plus le contexte du menu (cf plus haut #179!note-2) Exemple :

menus:
  - person:
    order: 200
    label: psychological diagnostic
    access: 'agent.isGranted(ROLE_SEE_DIAGNOSTIC, person)' #person étant fournie dans le contexte du menu

Cette fonction serait reportée à une version 2

* conserver toute autre option qui pourrait survenir par la suite

Si un menu futur devait "inventer" une option (par exemple, une icône, etc.) les attributs seraient conservés. S'ils se répètent, on pourrait les faire passer dans les attributs "protégés" plus haut.

C'est important parce que, dans MenuComposer.php, la classe doit prévoir de les conserver pour les renvoyer au twig qui les traitera.

#5 Updated by Marc Ducobu almost 5 years ago

condition: 'person.age < 18' #attention qu'il faudra crée une fonction "getAge" dans la class person

Marche si age est en public, sinon doit être person.getAge()

Sinon on peut aussi évaluer avec : http://php.net/manual/fr/function.eval.php

#6 Updated by Julien Fastré almost 5 years ago

Expression Language est plus sûr, eval peut introduire des problèmes de sécurité :

Expressions can be seen as a very restricted PHP sandbox and are immune to external injections as you must explicitly declare which variables are available in an expression.

Voir ici : http://symfony.com/doc/current/components/expression_language/introduction.html#how-can-the-expression-engine-help-me

Cela permettrait d'éviter qu'un bundle avec du code source infecté soit introduit sur une installation par un admin peu regardant...

#7 Updated by Julien Fastré almost 5 years ago

La doc est publiée sur http://chill.readthedocs.org

Par rapport à ce qui a été défini plus haut :

{{ render(controller("CLChillMainBundle:Menu:writeMenu", {
             'menu' : 'person', 
             'layout': 'CLChillPersonBundle::menu.html.twig', 
             'context' : {'person': person }, 
             'activeRouteKey': activeRouteKey
        })) }}

  • j'ai créé une fonction twig, chill_menu, ce qui me semble plus pratique que d'appeler un contrôleur.
  • j'ai dû réintroduire l'argument 'args' pour définir les arguments du pattern de la route. Pourquoi ? Parce que sinon, il fallait ajouter une définition quelque part pour faire passer les éléments contenus dans le contexte (les objets person) vers une variable (par exemple, l'id, et donc faire $person->getId() ), ce qui demandait... une définition supplémentaire, quelque part... Ca devenait compliqué... Donc retour à la simplicité !

#8 Updated by Julien Fastré almost 5 years ago

Je ferme cette issue et la #217, je crée une version "future" dans la configuration du projet, et je reporte l'implémentation des clés "conditions" et "access" à ce futur.

#9 Updated by Julien Fastré almost 5 years ago

  • Status changed from New to Closed

Also available in: Atom PDF