---
title: "DI and actions — Tags for Laravel | Roundly"
description: "Skip the facade: inject TagsManager or call a single-purpose action — every action with its execute() signature and facade path."
url: https://roundly-consulting.com/open-source/docs/tags-for-laravel/without-facade
language: en
---

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

[Tags for Laravel](https://roundly-consulting.com/open-source/docs/tags-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 Tags facade (shortest), the manager RoundlyConsulting\\Tags\\TagsManager — the facade’s root, a container singleton — injected through the constructor (same API, explicit dependency, no static calls), and actions (final readonly classes with one execute(), for composing into your own actions, jobs and commands):

```php
use RoundlyConsulting\Tags\Actions\Tagging\AttachTagsAction;
use RoundlyConsulting\Tags\DataTransferObjects\TagSelection;
use RoundlyConsulting\Tags\Facades\Tags;
use RoundlyConsulting\Tags\TagsManager;

Tags::for($concert)->attach(['live'], 'label');                                        // facade
app(TagsManager::class)->for($concert)->attach(['outdoor'], 'label');                  // dependency injection
app(AttachTagsAction::class)->execute($concert, TagSelection::of(['free'], 'label'));  // action
```

## Inject the manager

```php
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use RoundlyConsulting\Tags\TagsManager;

final class ConcertLabelsController
{
    public function __construct(private TagsManager $tags) {}

    public function update(Request $request, Concert $concert): Response
    {
        $this->tags->for($concert)->sync($request->input('labels', []), 'label');

        return response()->noContent();
    }
}
```

The manager holds no container of its own: it resolves actions and read services from the current one on every call, so it is Octane-safe and a binding made inside a request applies.

## Call an action

```php
use RoundlyConsulting\Tags\Actions\Catalog\DeleteTagAction;
use RoundlyConsulting\Tags\Actions\Maintenance\RepairTagsAction;
use RoundlyConsulting\Tags\Actions\Tagging\SyncTagsAction;
use RoundlyConsulting\Tags\DataTransferObjects\RepairOptions;
use RoundlyConsulting\Tags\DataTransferObjects\TagSelection;
use RoundlyConsulting\Tags\Enums\TagChildren;

app(SyncTagsAction::class)->execute($concert, TagSelection::of($jazz, 'genre'));
app(DeleteTagAction::class)->execute($jazz, TagChildren::Reparent);
app(RepairTagsAction::class)->execute(new RepairOptions(counts: true, paths: false, scopeKeys: false, orphans: false));
```

## Facade method → action

Namespaces are relative to RoundlyConsulting\\Tags\\Actions:

| Action | execute(…) | Returns | Facade path |
| --- | --- | --- | --- |
| `Tagging\AttachTagsAction` | `execute($taggable, TagSelection $selection)` | `TagChanges` | Tags::attach(), for()->attach(), attachTags() |
| `Tagging\DetachTagsAction` | `execute($taggable, TagSelection $selection)` | `TagChanges` | Tags::detach(), for()->detach(), detachTags() |
| `Tagging\SyncTagsAction` | `execute($taggable, TagSelection $selection)` | `TagChanges` | Tags::sync(), for()->sync(), syncTags() |
| `Tagging\ClearTagsAction` | `execute($taggable, $type = null)` | `TagChanges` | Tags::clear(), for()->clear(), clearTags() |
| `Catalog\CreateTagAction` | `execute($type, TagData $data, ?Model $scope = null)` | `Tag` | type()->create(), make()->create() |
| `Catalog\FindOrCreateTagAction` | `execute($type, string\|array\|TagData $name, ?Model $scope = null)` | `Tag` | type()->findOrCreate(), make()->findOrCreate() |
| `Catalog\UpdateTagAction` | `execute(Tag $tag, UpdateTagData $data)` | `Tag` | type()->update(), rename(), edit()->save() |
| `Catalog\MoveTagAction` | `execute(Tag $tag, ?Tag $under = null, ?int $position = null)` | `Tag` | type()->move() |
| `Catalog\ReorderTagsAction` | `execute($type, ?Model $scope, ?Tag $parent, array $order)` | `Collection<int, Tag>` | type()->reorder() |
| `Catalog\DeleteTagAction` | `execute(Tag $tag, TagChildren $children = Refuse)` | `Tag` | type()->delete() |
| `Catalog\RestoreTagAction` | `execute(Tag $tag)` | `Tag` | type()->restore() |
| `Maintenance\RepairTagsAction` | `execute(RepairOptions $options)` | `RepairReport` | Tags::repair(), tags:repair |

- Every write — from the facade, an injected manager, a handle, a builder or a model method — funnels through the manager, which resolves the action from the container, so a container binding of an action applies everywhere.
- Tags::fake() swaps the manager in the container too, so an injected TagsManager is faked as well. Calling an action directly is not recorded — only manager calls are.
- The scope checks of a type() handle (a write matches its scope exactly) live in the handle: an action called directly writes whatever tag you hand it.
- The read services BuildTagTree, LoadAncestors, PopularTags and SuggestTags (RoundlyConsulting\\Tags\\Queries) are resolved from the container too, so you may bind your own.
- Actions\\Internal\\\* (AdjustUsageCountsAction, ApplyTagChangesAction, ClearDeletedTaggableAction, ResolveTagsAction, RewriteSubtreePathsAction) are building blocks — don’t call them.

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