PHP code example of evolvex / laravel-invariant-sentinel

1. Go to this page and download the library: Download evolvex/laravel-invariant-sentinel library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

evolvex / laravel-invariant-sentinel example snippets


'invariants' => [
    App\\Invariants\\CompletedWithdrawalInvariant::class,
],

use Evolvex\\InvariantSentinel\\Facades\\Sentinel;

Sentinel::register(App\\Invariants\\CompletedWithdrawalInvariant::class);

final class CompletedWithdrawalInvariant extends ModelInvariant implements SweepableInvariant
{
    public static function key(): string
    {
        return 'payments.withdrawal.completed-integrity';
    }

    public function modelClass(): string
    {
        return Withdrawal::class;
    }

    public function severity(): Severity
    {
        return Severity::Critical;
    }

    public function appliesTo(mixed $withdrawal): bool
    {
        return $withdrawal->status === 'completed';
    }

    public function consistency(): ConsistencyPolicy
    {
        return ConsistencyPolicy::eventuallyWithin(seconds: 30, retryAfterSeconds: 5);
    }

    public function incidentPolicy(): IncidentPolicy
    {
        return IncidentPolicy::make(openAfterFailures: 1, resolveAfterPasses: 2);
    }

    public function checks(): array
    {
        return [
            new ProviderSucceeded,
            new ExactlyOneProviderExecution,
            new ExactlyOneWalletDebit,
        ];
    }

    public function triggers(): array
    {
        return [
            ModelTrigger::make(
                Withdrawal::class,
                ['updated'],
                fn (Withdrawal $w) => $w->wasChanged('status'),
            ),
        ];
    }

    public function candidates(): iterable
    {
        foreach (Withdrawal::query()->where('status', 'completed')->lazyById(500) as $w) {
            yield SubjectRef::fromModel($w);
        }
    }
}

final class ExactlyOneWalletDebit implements InvariantCheck
{
    public function key(): string
    {
        return 'wallet-debited-exactly-once';
    }

    public function evaluate(mixed $withdrawal, EvaluationContext $context): CheckResult
    {
        $count = $withdrawal->walletTransactions()
            ->where('type', 'withdrawal')
            ->count();

        return $count === 1
            ? CheckResult::pass($this->key())
            : CheckResult::fail(
                ruleKey: $this->key(),
                code: 'wallet.debit_count_mismatch',
                expected: 1,
                actual: $count,
                evidence: [Evidence::database('wallet_transactions', 1, $count)],
            );
    }
}

Schedule::command('sentinel:sweep')
    ->everyMinute()
    ->onOneServer()
    ->withoutOverlapping();

Schedule::command('sentinel:drain')
    ->everyMinute()
    ->onOneServer()
    ->withoutOverlapping();

Schedule::command('sentinel:prune')
    ->daily()
    ->onOneServer();

Sentinel::facts()->record(
    type: 'provider.withdrawal.executed',
    subject: Sentinel::subject($withdrawal),
    idempotencyKey: $providerReference,
    payload: ['provider' => 'example'],
);

$this->app->bind(TenantResolver::class, AppTenantResolver::class);

Sentinel::fake();

// execute application code...

Sentinel::fake()->assertTriggered(
    'payments.withdrawal.completed-integrity',
    $withdrawal->id,
);

InvariantTest::for(CompletedWithdrawalInvariant::class)
    ->subject($withdrawal)
    ->assertPasses();

$result = Sentinel::check(
    'payments.withdrawal.completed-integrity',
    $withdrawal,
);

expect($result->status)->toBe(EvaluationStatus::Pass);
bash
composer vendor:publish --tag=sentinel-config
php artisan migrate
bash
php artisan queue:work --queue=sentinel
bash
php artisan sentinel:sweep
php artisan sentinel:sweep payments.withdrawal.completed-integrity
bash
php artisan make:invariant CompletedWithdrawalInvariant
php artisan sentinel:list
php artisan sentinel:show payments.withdrawal.completed-integrity
php artisan sentinel:check payments.withdrawal.completed-integrity 98122 --type='App\\Models\\Withdrawal'
php artisan sentinel:sweep
php artisan sentinel:drain
php artisan sentinel:incidents
php artisan sentinel:incident <id> ack [email protected]
php artisan sentinel:incident <id> resolve --reason=manually_reconciled
php artisan sentinel:recheck <id>
php artisan sentinel:repair <id>              # dry-run
php artisan sentinel:repair <id> --execute    # 
bash
php artisan sentinel:doctor