Quand l’ordre de vos votants fait la règle

Trois des quatre algorithmes de combinaison sont indépendants de l’ordre : mélangez les votants et la décision reste la même. Le quatrième fait de l’ordre d’enregistrement une partie de la règle, et cela vaut d’être su avant de s’en servir.

first_applicable, que Symfony Security appelle priority, prend la première autorisation ou le premier refus qu’il rencontre et s’arrête là. Les votants qui s’abstiennent sont passés en silence ; le premier qui a quelque chose à dire tranche la question.

L’ordre comme sens

Sous les trois autres algorithmes, enregistrer un votant avant ou après un autre ne change rien sinon l’ordre des votes dans le profileur. Ici, cela change la réponse.

C’est bien l’intérêt : un votant enregistré en premier peut passer outre le reste, sans recevoir de veto sur des questions où il n’a pas d’avis. C’est ainsi qu’une liste de dérogations s’exprime honnêtement, que la dérogation dise oui ou non.

  • Une règle de maintenance qui refuse tout pendant qu’un déploiement tourne, et s’abstient le reste du temps.
  • Une règle d’accès d’urgence qui accorde un compte de secours et s’abstient pour tout le monde.
  • Une règle de cloisonnement qui refuse tout ce qui appartient à un autre locataire avant même qu’on regarde la propriété.

Chacune est un votant qui s’abstient presque toujours, et dont toute la valeur tient à être interrogé en premier.

Dans la bibliothèque, l’ordre est le tableau

Quand on construit le gestionnaire à la main, l’ordre des votants est celui dans lequel vous les avez passés :

$accessControlManager = new AccessControlManager(
    strategies: [new FirstApplicableStrategy()],
    voters: [new MaintenanceVoter(), new PostVoter(), new RoleVoter()],
    defaultStrategy: 'first_applicable',
);

Dans une application Symfony, les votants viennent d’un itérateur étiqueté, donc l’ordre est la priorité de l’étiquette. Donnez à ceux qui doivent parler en premier une priorité explicite, plutôt que de vous fier à l’ordre que le conteneur a produit par hasard :

services:
    App\Security\MaintenanceVoter:
        tags:
            - { name: access_control.voter, priority: 100 }

L’autoconfiguration étiquette tous vos votants ; déclarer le service explicitement n’est nécessaire que pour dire où il se place dans la file.

Ce que ça coûte

Une règle qui dépend de l’ordre est une règle écrite à deux endroits : le votant, et la priorité qui le place là où il est. Rien dans le votant ne dit qu’il s’attend à être interrogé en premier, et rien dans la priorité ne dit pourquoi elle vaut 100.

Employez donc first_applicable là où la préséance est le modèle, et non comme un moyen de faire gagner une discussion à un votant. Quand l’exigence est que chaque règle soit d’accord, deny_overrides le dit en un mot et survit à un remaniement qui change un ordre dont personne ne savait qu’il portait la charge.

Et quel que soit votre choix, le panneau du profileur montre les votes dans l’ordre où ils ont été émis, avec la raison donnée par chaque votant. Quand la préséance est la règle, cette liste est la règle en train de s’appliquer, et c’est le seul cas où la relire vaut le clic.