Artisan commands
tags:types
php artisan tags:types # Name, Label, Hierarchy, Max, Creation, Slugs, Scopes, Models, API, Source, Overrides
php artisan tags:types --jsonEvery 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": "…"}]| Section | Level | Checks |
|---|---|---|
types | error | Tags of a type nobody defines; an extend() or override of a name nobody defines; a type that does not resolve. |
limits | error | Models carrying more tags of a type than its max. |
trees | error / warning | Parents 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). |
scopes | error / warning | A 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). |
indexes | error | A supported locale without its unique slug index. |
locales | error / warning | The app locale outside translatable.locales — tagging by name fails until you add it; the fallback locale outside it (warning). |
keys, connections | error / warning | A taggable or scope model keyed otherwise than tags.key_type; a model on another database connection than the tags tables (warning). |
counts | warning | With --counts: usage counts that do not match their taggings. |
orphans, trashed | warning / error | Taggings whose model is gone (warning); taggings on deleted tags and taggable types that are no model class (errors). |
routes | warning | The 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| Option | Meaning |
|---|---|
--paths | Recompute paths and depths from the parent chain, one tree at a time under its tree lock; cycles are counted, never placed. |
--scope-keys | Recompute scope keys from the scope morph. |
--orphans | Delete 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. |
--counts | Recount 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-run | Report 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 cryptoBy 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.