Skip to content

Les résolveurs de contexte ​

Un résolveur répond à une question de contexte : « quel est le panier courant ? la devise ? la zone fiscale ? le taux de taxe applicable ? ». Chacun est un contrat que vous pouvez remplacer pour changer la stratégie, sans toucher au code qui le consomme.

Le problème ​

Le calcul d'un prix a besoin de savoir dans quelle devise et quelle zone fiscale se place le client. Un site B2C lit ça d'un cookie et de l'adresse du panier ; un site B2B le déduira du compte entreprise. Le pricing ne doit dépendre d'aucune de ces stratégies : il se contente de poser la question.

Le principe ​

Le cœur demande « le X courant » à un contrat. Une implémentation par défaut (B2C) répond ; vous la remplacez pour changer la logique. C'est une application directe du conteneur & des contrats, spécialisée pour le contexte de la requête.

Les résolveurs de Slab ​

ContratRépond àDéfaut (B2C)
CurrentCartResolverle panier courant (et sa transition à la connexion)panier du compte, sinon panier invité (cookie) ; vide et en mémoire tant qu'il n'a aucun produit
CurrentCurrencyResolverla devise d'affichagecookie, sinon devise du shop
CurrentAreaResolverla zone fiscalezone de l'adresse de facturation, sinon zone par défaut
TaxResolverle taux de taxe pour une règle + une zonetaux par zone, sinon taux par défaut de la règle

Remplacer un résolveur ​

php
use Slab\Framework\Core\Currency\Contracts\CurrentCurrencyResolver;

$this->app->scoped(CurrentCurrencyResolver::class, DeviseParPaysResolver::class);

Votre classe implémente le contrat :

php
use Slab\Framework\Core\Currency\Contracts\CurrentCurrencyResolver;
use Slab\Framework\Models\Currency;

final class DeviseParPaysResolver implements CurrentCurrencyResolver
{
    public function resolve(): Currency
    {
        // votre logique (géo-IP, préférence compte, sous-domaine…)
    }
}

Tout le cœur (prix, totaux, affichage) bascule aussitôt sur votre devise.

Le résolveur de panier ​

CurrentCartResolver demande plus qu'un resolve(), car le panier courant naît et change de main en cours de navigation. Votre implémentation porte trois méthodes :

php
use Slab\Framework\Core\Cart\Contracts\CurrentCartResolver;
use Slab\Framework\Models\Cart;

final class PanierParEntrepriseResolver implements CurrentCartResolver
{
    public function resolve(): Cart
    {
        // le panier courant ; s'il n'existe pas encore, un `Cart` vide en mémoire
    }

    public function remember(Cart $cart): void
    {
        // un panier vient d'être enregistré : s'il est le panier courant, le retenir
    }

    public function setOnLogin(Cart $guestCart): Cart
    {
        // basculer vers le panier du compte, y verser le panier invité au besoin
    }
}
  • resolve() : un panier ne s'enregistre qu'avec son premier produit. Tant que le client n'a rien ajouté (visiteur de passage, robot d'indexation), vous recevez un panier vide en mémoire : on peut le lire (quantité, adresse, zone), mais il n'existe pas en base. Chaque page lit le panier (pour la quantité affichée dans l'en-tête, pour la zone fiscale des prix). Le créer dès la lecture enregistrerait un panier par visiteur.
  • remember() : le cœur l'appelle dès qu'un Cart est enregistré (écouteur RememberNewCart sur eloquent.created), quelle que soit l'action qui a créé le panier : un premier produit, un premier bon de réduction… S'il s'agit du panier courant, il le reste pour les pages suivantes. Le défaut pose le cookie pour un invité ; un panier de compte se retrouve par le compte.
  • setOnLogin() : à la connexion, le panier courant devient celui du compte. Le panier invité y est fusionné si le panier du compte est vide.

TIP

Les opérations sur un panier (ajout, mise à jour, suppression, fusion, commande) passent par CartService, qui travaille sur un panier explicite et ne sait rien du « panier courant ». Le résolveur répond seulement à la question « lequel ? ».

Bon à savoir ​

  • Les résolveurs de contexte sont liés à la requête (scoped) : une instance par requête, jamais de statique partagé entre process. Enregistrez les vôtres de la même façon. Avec un bind, chaque résolution crée une instance neuve : un résolveur de panier qui mémorise le panier courant sur son instance ne le reconnaîtrait plus dans remember().
  • Le défaut est résolument B2C (cookies, fusion panier invité→compte). Une couche B2B (apisell) fournit ses propres résolveurs en les enregistrant dans le conteneur, exactement par ce mécanisme.
  • Les noms des cookies B2C ne sont pas en dur : shop.cookies.cart (cart_id par défaut) et shop.cookies.currency (currency_iso par défaut). Renommez-les en config, ou via les variables d'environnement CART_COOKIE / CURRENCY_COOKIE, sans remplacer le résolveur.

Voir aussi ​