Service Providers

Les providers sont le lieu où votre application décide comment configurer et exposer les services. Ils ont deux rôles distincts : enregistrer des services dans le container, et exécuter du code au démarrage.

Pourquoi un provider ?

River peut créer automatiquement la plupart des services via l'autowiring (voir Container IoC). Alors pourquoi un provider ?

Cas 1 — Exposer un service dans tous les templates. River sait créer un objet Csrf, mais il ne sait pas que vous voulez l'appeler $csrf dans vos vues. C'est votre application qui décide comment exposer les services aux templates via $view->share().

// Sans provider : vous devriez passer $csrf dans chaque render() manuellement
// Avec un provider : $csrf est disponible dans tous les templates automatiquement

class Csrf_provider extends Service_provider {
    public function register(): void {}

    public function boot(): void {
        $view = $this->container->get(View::class);
        $csrf = $this->container->get(Csrf::class);
        $view->share('csrf', $csrf);
    }
}
River aurait pu auto-partager $csrf dans toutes les apps, mais ça serait opinionated — toutes les apps n'ont pas besoin du CSRF dans les vues, ou pourraient vouloir un autre nom. Le provider laisse le contrôle à l'application.

Cas 2 — Configurer un service qui nécessite des paramètres. L'autowiring ne peut pas deviner une clé API ou une URL externe. Un provider est l'endroit pour construire ces services.

class Mailer_provider extends Service_provider {
    public function register(): void {
        $this->container->singleton(Mailer::class, function($c) {
            return new Mailer(
                host: $_ENV['SMTP_HOST'],
                port: (int) $_ENV['SMTP_PORT'],
            );
        });
    }
}

register() vs boot()

Un provider a deux méthodes avec des rôles bien distincts :

Méthode Quand Usage
register() Avant que tous les providers soient chargés Lier des services dans le container (bind, singleton)
boot() Après que tous les providers sont chargés Utiliser des services déjà enregistrés (ex: $view->share())
Ne jamais appeler $this->container->get() dans register(). Les autres providers ne sont pas encore chargés à ce stade. Réservez get() pour boot().

Créer un Provider

Les providers étendent River\Providers\Service_provider et se placent dans app/Providers/.

namespace App\Providers;

use River\Providers\Service_provider;
use River\Session;
use River\View;

class Flash_provider extends Service_provider {

    public function register(): void {
        // Rien ici — Session et View sont déjà autowired par River
    }

    public function boot(): void {
        $session = $this->container->get(Session::class);
        $data = $session->get('flash_toast');
        if ($data) {
            $session->remove('flash_toast');
            $this->container->get(View::class)->share('flash_toast', $data);
        }
    }
}

Enregistrement

Ajoutez votre provider dans bootstrap/providers.php :

use River\Providers\Vite_provider;
use App\Providers\Csrf_provider;
use App\Providers\Flash_provider;

return [
    Vite_provider::class,
    Csrf_provider::class,
    Flash_provider::class,
];