veilletech.fr
8 sept. Feed du jour
#06 LARAVEL Article

Des règles métier qui changent avec la date

Git garde l'histoire du code, pas celle de vos décisions.

Laravel Rulebook, de Mathias Onea, modélise les règles métier qui changent dans le temps : chaque règle est une classe PHP qui déclare sa fenêtre de validité (always, from, until, between), et la résolution rend un gagnant unique désigné par priorité, accompagné de la raison de chaque règle — gagnante, perdante ou hors fenêtre. Un snapshot fige la décision en JSON, ce qui permet de justifier après coup un calcul fait sous une politique révolue.

3 min de lectureintermédiairevidéo 1:13
Partager
Sommaire4 sections
  1. Ce qui se passe
  2. Le mécanisme
  3. Ce qui fait la valeur
  4. À retenir

Ce qui se passe

Un client demande pourquoi son remboursement de mars vaut ce qu'il vaut. Depuis, la politique a été réécrite — en place, dans le même fichier. La seule trace de ce que le code faisait à l'époque est dans l'historique Git, et on ne colle pas un diff dans une réponse au support.

Laravel Rulebook, de Mathias Onea, s'attaque à ce problème précis : les décisions qu'il faut pouvoir expliquer après coup.

Terminal
composer require mathiasonea/laravel-rulebook

Il demande PHP 8.3 et Laravel 12 ou 13. Pas de façade, pas de registre, pas de fichier de configuration, pas de migration : les règles sortent du conteneur de services, et un rulebook est générique sur son sujet, son contexte et son résultat.

Le mécanisme

Chaque règle est une classe PHP ordinaire qui déclare la fenêtre pendant laquelle elle a fait foi, avec always(), from(), until() ou between(). Les fenêtres sont semi-ouvertes, si bien que deux années consécutives ne se chevauchent jamais.

PHP
final class FlexibleFareRefund2025 extends FlexibleFareRefund
{
    public function validity(): ValidityPeriod
    {
        return ValidityPeriod::between(
            from: new DateTimeImmutable('2025-01-01T00:00:00-05:00'),
            until: new DateTimeImmutable('2026-01-01T00:00:00-05:00'),
        );
    }

    protected function noticeInDays(): int { return 7; }
    protected function handlingFeeInCents(): int { return 0; }
}

La règle de 2026 ouvre au même instant que celle de 2025 se ferme, avec ses propres chiffres : préavis porté à 14 jours et frais de dossier de 3,50 $. La logique d'éligibilité commune reste dans la classe parente ; chaque année ne fournit que ses valeurs.

La résolution rend un gagnant et un seul, désigné par priority() — jamais par la position dans le tableau des règles. On interroge à une date :

PHP
$decision = $rulebook->resolveAt(
    subject: new Ticket(reference: 'TCK-4193', priceInCents: 89_00),
    at: new DateTimeImmutable('2025-11-02T09:00:00-05:00'),
    context: new Cancellation(fare: 'flexible', daysBeforeEvent: 10),
);

$decision->outcome()->formatted();          // $89.00
$decision->winningResult()->reason();       // Refunded under the 2025 policy.

Le même appel daté de 2026 rend 0,00 $ : dix jours de préavis ne suffisent plus aux quatorze exigés par la politique en vigueur.

Ce qui fait la valeur

Ce n'est pas la fenêtre de dates, qu'on peut bricoler avec deux if. C'est la traçabilité de la décision :

À retenir

Le domaine visé est étroit mais fréquent : remboursements, barèmes de commission, taux de TVA, seuils tarifaires — tout ce qui est recalculé plus tard, sous des conditions qui n'existent plus. Si vos règles ne changent jamais, ce paquet n'apporte rien. Si vous avez déjà fouillé Git pour reconstituer un calcul, il apporte exactement ce qui manquait.

Source : Laravel News