---
title: "DI and actions — Sentinel for Laravel | Roundly"
description: "Skip the facade: inject SentinelManager or call one of the 30 host-facing actions — request objects, plain-argument actions and the method → action map."
url: https://roundly-consulting.com/open-source/docs/sentinel-for-laravel/without-facade
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Sentinel for Laravel](https://roundly-consulting.com/open-source/docs/sentinel-for-laravel.md)

# DI and actions

The facade is the recommended default, not the only way in. Three entry points run the same code: the Sentinel facade (shortest); the manager RoundlyConsulting\\Sentinel\\SentinelManager — the facade’s root, a container singleton with every facade method under the same signature — injected through the constructor; and the actions in RoundlyConsulting\\Sentinel\\Actions\\…, final readonly classes with one execute() each.

## Inject the manager

```php
use RoundlyConsulting\Sentinel\SentinelManager;

final class FixInvoice
{
    public function __construct(private SentinelManager $sentinel) {}

    public function __invoke(Invoice $invoice, User $admin): void
    {
        $this->sentinel->for($invoice)->by($admin)->because('Ticket #412: corrected VAT via SQL')->acknowledge();
    }
}
```

## Call an action

Twenty-one of the 30 host-facing actions take one public request or option object — build them with named arguments. Nine take plain arguments: CheckInstallationAction (none), RetireKeyAction($ring, $keyId), VerifyMacAction($ring, $keyId, $message, $mac), ComputeMacAction($ring, $message), ForgetIdempotencyKeyAction($key, $scope), ReadLedgerHistoryAction($model, $seal, $limit), SignRequestAction($request, $keyId, SigningOptions $options), VerifyRequestSignatureAction($request, ?$profile) and VerifyResponseSignatureAction($response, ?$profile). Where the manager fills in the model’s default seal, AcknowledgeRequest, UnsealRequest and ReadLedgerHistoryAction want the seal name explicitly.

```php
use RoundlyConsulting\Sentinel\Actions\Keys\ImportKeyAction;
use RoundlyConsulting\Sentinel\Actions\Keys\RetireKeyAction;
use RoundlyConsulting\Sentinel\Actions\Seals\AcknowledgeTamperingAction;
use RoundlyConsulting\Sentinel\Actions\Seals\ReadLedgerHistoryAction;
use RoundlyConsulting\Sentinel\Actions\Seals\SealModelAction;
use RoundlyConsulting\Sentinel\DataTransferObjects\AcknowledgeRequest;
use RoundlyConsulting\Sentinel\DataTransferObjects\ImportKeyRequest;
use RoundlyConsulting\Sentinel\DataTransferObjects\SealRequest;
use RoundlyConsulting\Sentinel\Enums\Algorithm;

// The raw actions — a request object…
app(ImportKeyAction::class)->execute(new ImportKeyRequest('http', 'acme-2026-10', Algorithm::Ed25519, $pem, owner: $partner));
app(SealModelAction::class)->execute(new SealRequest($invoice, reason: 'INC-1'));   // null seal = the default one
app(AcknowledgeTamperingAction::class)->execute(new AcknowledgeRequest(
    model: $invoice, seal: 'financial', reason: 'Ticket #412: corrected VAT via SQL', actor: $admin,
));

// …or plain arguments
app(ReadLedgerHistoryAction::class)->execute($invoice, 'financial', 20);   // list<LedgerRecord>, limit 1–1000
app(RetireKeyAction::class)->execute('http', 'acme-2025-10');
```

## Facade method → action

| Facade method | Action (input) |
| --- | --- |
| `check()` | `CheckInstallationAction (no input)` |
| `seal()` | `Seals\SealModelAction (SealRequest)` |
| `verify()` | `Seals\VerifyModelAction (VerifyRequest)` |
| `verifyOrFail()` | `Seals\VerifyModelAction (VerifyRequest)` |
| `verifyAll()` | `Seals\VerifyModelsAction (VerifyManyRequest)` |
| `verifyMany()` | `Seals\VerifyModelsAction (VerifyManyRequest)` |
| `isIntact()` | `Seals\VerifyModelsAction (VerifyManyRequest)` |
| `acknowledge()` | `Seals\AcknowledgeTamperingAction (AcknowledgeRequest)` |
| `unseal()` | `Seals\UnsealModelAction (UnsealRequest)` |
| `ledgerHistory()` | `Seals\ReadLedgerHistoryAction ($model, $seal, $limit)` |
| `scan()` | `Seals\ScanSealsAction (ScanOptions)` |
| `reseal()` | `Seals\ResealModelsAction (ResealOptions)` |
| `resealWhere()` | `Seals\ResealWhereAction (ResealWhereRequest)` |
| `updateAndReseal()` | `Seals\UpdateAndResealAction (UpdateAndResealRequest)` |
| `sealMissing()` | `Seals\SealMissingAction (BaselineOptions)` |
| `generateKey()` | `Keys\GenerateKeyAction (GenerateKeyRequest)` |
| `importKey()` | `Keys\ImportKeyAction (ImportKeyRequest)` |
| `rotateKey()` | `Keys\RotateKeyAction (RotateKeyRequest)` |
| `revokeKey()` | `Keys\RevokeKeyAction (RevokeKeyRequest)` |
| `retireKey()` | `Keys\RetireKeyAction ($ring, $keyId)` |
| `verifyMac()` | `Keys\VerifyMacAction ($ring, $keyId, $message, $mac)` |
| `mac()` | `Keys\ComputeMacAction ($ring, $message)` |
| `checkpoint()` | `Ledger\CreateCheckpointAction (CheckpointOptions)` |
| `verifyLedger()` | `Ledger\VerifyLedgerAction (LedgerVerifyOptions)` |
| `runIdempotent()` | `Idempotency\RunIdempotentAction (IdempotentCall)` |
| `forgetIdempotencyKey()` | `Idempotency\ForgetIdempotencyKeyAction ($key, $scope)` |
| `issueNonce()` | `Nonces\IssueNonceAction (IssueNonceRequest)` |
| `consumeNonce()` | `Nonces\ConsumeNonceAction (ConsumeNonceRequest)` |
| `signedRoute()` | `Nonces\IssueSingleUseUrlAction (SignedRouteRequest)` |
| `prune()` | `PruneAction (PruneOptions)` |
| `signRequest()` | `Signatures\SignRequestAction ($request, $keyId, SigningOptions)` |
| `verifyRequestSignature()` | `Signatures\VerifyRequestSignatureAction ($request, $profile)` |
| `verifyResponseSignature()` | `Signatures\VerifyResponseSignatureAction ($response, $profile)` |

- Each manager method that seals, verifies or changes state resolves its action from the container on every call, so a container binding of an action class replaces it everywhere — facade, handles, model trait and commands. Actions are final; a replacement must offer the same execute() signature, for example a wrapper that logs and delegates to the original.
- The handles, sub-accessors, model trait, middleware, rule, macros and job middleware all call the manager — never an action — which is why the fake sees every call.
- Sentinel::fake() (facade only) swaps the manager in the facade and in the container, so an injected SentinelManager is faked too. Calling an action directly bypasses the fake.
- Data objects carrying secrets (ImportKeyRequest, ConsumeNonceRequest, IssuedNonce, GeneratedKey, RotationResult) print \[redacted\] in var\_dump(), json\_encode() and log contexts, and all except ConsumeNonceRequest refuse serialize(). Since 1.2 a flat facade call also hides the arguments the manager marks #\[\\SensitiveParameter\] (verifyMac()’s $mac) in the facade’s own frame, so a stack trace shows them no more than a call through the manager does.
- Manager methods such as verifyIn(), persist(), retrieved(), beginIdempotentRequest() and rememberNonce() are public only for the package’s own wiring and marked @internal — don’t call them. ResealKeyEnvelopesAction (behind sentinel:key:reseal) is @internal too: it upgrades Sentinel’s own key storage once, and the command — whose point is the operator reading the labels it prints — is the interface.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/sentinel-for-laravel.md)
