---
title: "DI and actions — Options for Laravel | Roundly"
description: "Skip the facade: inject OptionsManager for the same API without static calls, or call the export and import actions directly."
url: https://roundly-consulting.com/open-source/docs/options-for-laravel/without-facade
language: en
---

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

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

# DI and actions

The facade is the recommended default, not a requirement. There are three equivalent entry points:

- The Options facade — shortest; recommended for most code.
- The manager, RoundlyConsulting\\Options\\OptionsManager, injected through the constructor — it’s the facade root, so it has exactly the same API, as an explicit dependency with no static calls.
- Actions — single-purpose classes with one execute() method, for composing into your own actions, jobs and commands. Options ships two: ExportOptionsAction and ImportOptionsAction.

## Inject the manager

```php
use RoundlyConsulting\Options\OptionsManager;

final class CopyTeamSettings
{
    public function __construct(private OptionsManager $options) {}

    public function __invoke(Team $from): string
    {
        return $this->options->exportJson($from);
    }
}

// The same API as the facade, handles included:
$this->options->for($team)->set(ThemeOption::class, 'dark');
```

Options::fake() swaps the container binding, so an OptionsManager resolved after the call is the fake too.

## Call an action

```php
use RoundlyConsulting\Options\Actions\ExportOptionsAction;
use RoundlyConsulting\Options\Actions\ImportOptionsAction;

// The raw actions — one execute() each:
$payloads = app(ExportOptionsAction::class)->execute($team, globalOnly: false); // list<OptionPayload>
$count = app(ImportOptionsAction::class)->execute($payloads);                    // int
```

## Facade method → action

| Facade method | Action | execute() |
| --- | --- | --- |
| `Options::export()` | `ExportOptionsAction` | `execute(?Model $owner = null, bool $globalOnly = false): list<OptionPayload>` |
| `Options::exportJson()` | — (encodes export()) | — |
| `Options::import()` | `ImportOptionsAction` | `execute(list<OptionPayload> $payloads): int` |

Every other manager method — get(), set(), the handles, groups, observers, the config bridge — lives on the manager itself; there is no separate action to call. The manager’s resolveOptionInstance() is @internal (the config bridge’s resolver), so don’t build on it.

## The OptionPayload DTO

Both actions speak RoundlyConsulting\\Options\\DataTransferObjects\\OptionPayload — one stored row. Build payloads yourself, or parse rows and JSON into them:

```php
use RoundlyConsulting\Options\DataTransferObjects\OptionPayload;

$payload = new OptionPayload('theme', 'dark', ownerType: User::class, ownerId: 5);

OptionPayload::fromArray(['key' => 'theme', 'value' => 'dark']); // global row
OptionPayload::list($rows);                                      // rows or payloads → list<OptionPayload>
OptionPayload::listFromJson($json);                              // a JSON export → list<OptionPayload>

$payload->toArray(); // ['key' => 'theme', 'value' => 'dark', 'owner_type' => User::class, 'owner_id' => 5]
```

owner\_id follows options.key\_type — an int for bigint owners, a string for UUID or ULID owners. fromArray() turns digit strings into ints, treats a row with only one of owner\_type / owner\_id as global, and turns the value into its column string — a value that isn’t a string, number, boolean or null throws InvalidOptionPayload.

## 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/options-for-laravel.md)
