Skip to content

Choose container bindings

Use a regular binding for the default fake, a contextual binding for the Admin coordination UseCase, and a scoped binding for tenant context. Binding selection does not authorize an actor or enforce tenant filtering.

Before you begin

Run composer run reference:test:integration and read Contracts and Adapters.

Register each lifetime explicitly

examples/reference-app/app/Providers/PulsarServiceProvider.php — Regular, contextual, and scoped application bindings.

php
<?php

namespace App\Providers;

use App\Pulsar\Domain\Billing\Contracts\PaymentGateway;
use App\Pulsar\Domain\Orders\Contracts\TenantContext;
use App\Pulsar\Domain\Orders\Models\Order;
use App\Pulsar\Infrastructure\Payments\AdminPaymentGateway;
use App\Pulsar\Infrastructure\Payments\FakePaymentGateway;
use App\Pulsar\Infrastructure\Tenancy\ScopedTenantContext;
use App\Pulsar\Services\Client\Modules\Orders\UseCases\FinalizeOrderPayment;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider;

class PulsarServiceProvider extends ServiceProvider
{
    // #region pulsar-bindings
    public function register(): void
    {
        $this->app->bind(PaymentGateway::class, FakePaymentGateway::class);
        $this->app->scoped(TenantContext::class, ScopedTenantContext::class);
        $this->app->when(FinalizeOrderPayment::class)->needs(PaymentGateway::class)->give(AdminPaymentGateway::class);
    }
    // #endregion

    public function boot(): void
    {
        Gate::guessPolicyNamesUsing(static function (string $modelClass): string {
            return str_replace('\\Models\\', '\\Policies\\', $modelClass).'Policy';
        });

        /** @var class-string<Model> $model */
        $model = Order::class;
        $model::preventLazyLoading();
    }
}
A default PaymentGateway binding resolves the fake adapter, FinalizeOrderPayment receives its contextual Admin adapter, and TenantContext is newly resolved after the scoped lifecycle is reset.
Resolve regular, contextual, and scoped bindings. Choose a binding from ownership and lifetime; authorization and tenant checks remain separate workflow work.

Interpretation. Contextual resolution changes an implementation choice, while scope limits only the lifetime of context state.

Verify and troubleshoot

The focused test proves default and contextual resolution. Prefer method arguments for runtime values; use scoped state only when the framework lifecycle can reset it.