NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Tags for Laravel

Artisan commands

tags:types

php artisan tags:types          # Name, Label, Hierarchy, Max, Creation, Slugs, Scopes, Models, API, Source, Overrides
php artisan tags:types --json

Every type, its rules, where it was defined and what adjusted it (see Tag types).

tags:doctor

Read-only checks of everything the data or the setup can disagree on that a write would not catch. Each finding has a severity (error or warning), a section and a plain-language message; the command exits 1 when any finding is an error:

php artisan tags:doctor              # every check; exits 1 when any finding is an error
php artisan tags:doctor --counts     # also compare every usage count with its taggings
php artisan tags:doctor --json       # [{"severity": "error", "section": "locales", "message": "…"}]
SectionLevelChecks
typeserrorTags of a type nobody defines; an extend() or override of a name nobody defines; a type that does not resolve.
limitserrorModels carrying more tags of a type than its max.
treeserror / warningParents on a flat type, tags deeper than their type’s max depth (a cap lowered after data exists rewrites nothing), a path or depth that does not match the parents, parent cycles (fix parent_id by hand); live tags under a deleted parent (warning).
scopeserror / warningA scope key that does not match its scope; models whose tagScope() is not a saved model keyed by tags.key_type; taggings outside their model’s current tagScope() — the next sync of that type drops them (warning).
indexeserrorA supported locale without its unique slug index.
localeserror / warningThe app locale outside translatable.locales — tagging by name fails until you add it; the fallback locale outside it (warning).
keys, connectionserror / warningA taggable or scope model keyed otherwise than tags.key_type; a model on another database connection than the tags tables (warning).
countswarningWith --counts: usage counts that do not match their taggings.
orphans, trashedwarning / errorTaggings whose model is gone (warning); taggings on deleted tags and taggable types that are no model class (errors).
routeswarningThe JSON API on without an auth middleware.

Run it after big imports or settings changes, and in CI after migrating. It pages through taggings in chunks, so it is safe on a large live database.

tags:repair

Puts derived data back in line with the facts — all four repairs unless options pick some:

php artisan tags:repair                            # paths, scope keys, orphans and counts
php artisan tags:repair --counts --type=label       # only usage counts of one type
php artisan tags:repair --orphans --dry-run         # report what would be fixed, write nothing
php artisan tags:repair --paths --scope-keys
OptionMeaning
--pathsRecompute paths and depths from the parent chain, one tree at a time under its tree lock; cycles are counted, never placed.
--scope-keysRecompute scope keys from the scope morph.
--orphansDelete taggings whose model is gone (a mass delete), recounting those tags’ usage counts so --orphans alone leaves them exact, and taggings left on deleted tags (a plain $tag->delete()), zeroing those tags’ counts.
--countsRecount usage counts from the taggings, a chunk at a time under row locks — exact while writers keep tagging.
--type=Only tags of this type.
--dry-runReport what would be fixed; write and lock nothing.

It prints what it fixed (or would fix): paths, cycles (left alone), scope keys, orphan taggings, taggings on deleted tags and usage counts, and warns about taggings of a taggable type that is no model class — those are left alone. The same repair from PHP:

use RoundlyConsulting\Tags\DataTransferObjects\RepairOptions;

$report = Tags::repair(new RepairOptions(paths: false, scopeKeys: false, type: 'label', dryRun: true));

$report->counts;               // tags whose usage count was (or would be) off
$report->orphans;              // taggings whose model is gone
$report->trashedTaggings;      // taggings left on deleted tags
$report->unresolvableTypes;    // taggable types that are no model class
$report->isClean();

Nothing is put on the scheduler for you; the package needs no scheduled task.

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

By donating, you agree to our donation terms.

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.