›
byrcsc/laravel-cartographer · 1.x
Limit a diagram to the models and relationships needed for one part of your application.
A full application diagram can contain too many tables to read at once. Scoping creates a smaller diagram for one subsystem and its nearby models.
Cartographer applies five controls in this order:
--except removes models from the run before anything is read.--only narrows the finished diagram to a set, stubbing what it cuts.Order matters. Excluding a relation type can disconnect a model. The model can then fall outside the depth limit and disappear from the diagram.
The two ends of that list are the ones people confuse. --except and --only
both narrow the model set, and they do it in opposite directions and leave
different traces. The scoping a set versus removing
models section below is the short
version if that is what you came for.
For a scope you intend to commit, declare a group instead of remembering flags. Everything on this page describes a single run.
--models names one or more starting models by short class name or fully
qualified name:
php artisan cartographer:erd --models=Post
php artisan cartographer:erd --models=Post,Invoice
php artisan cartographer:erd --models='App\Models\Post'Quote the fully qualified form; the backslashes need protecting from the shell.
With no seeds, every discovered model with a table is included and the diagram is the whole application.
Seeds resolve against discovered models. Three failures are possible, and each ends the command:
ERROR Seed model [Postt] was not found. Did you mean: Post, User, Comment?Up to three near matches are offered, ranked by edit distance.
ERROR Seed model [Order] is ambiguous. Use one of: App\Models\Order, App\Domain\Sales\Models\Order.Two discovered models share a short name. Pass the fully qualified one.
ERROR Seed model [Ghost] has no available database table.The class was discovered, but its table does not exist on the connection, so it never became an entity. This is a different message from "not found" on purpose: the problem is the database, not the spelling.
There is no config key for seeds. Seeding is a per-run decision, so it lives on the command line.
--depth sets the number of relationship steps to follow from the seeds. Edge
direction does not affect the count, so Cartographer can follow an edge from
either end.
php artisan cartographer:erd --models=Post --depth=0
php artisan cartographer:erd --models=Post --depth=1
php artisan cartographer:erd --models=Post # unlimitedFor the blog application in the quick start:
| Command | Entities | What is included |
|---|---|---|
--models=Post --depth=0 | 1 | posts alone, with no edges |
--models=Post --depth=1 | 7 | Direct neighbours: users, categories, comments, tags, attachments, plus the post_tag pivot |
--models=Post --depth=2 | 8 | Adds profiles, reached through users |
--models=Post | 8 | Everything connected to posts; audit_logs has no relations, so it stays out |
| (no seeds) | 9 | Every model, connected or not |
--depth on its own, with no --models, does nothing. There is no seed to
measure hops from, so the full graph is produced. If a depth-limited diagram
comes back complete, the missing flag is --models.
Selection picks entities; edges are then filtered to those with both ends
selected. So a --depth=1 diagram includes edges between two neighbours of the
seed, not only edges touching the seed itself.
Seeding on User at depth 1 keeps comments }o--|| posts : "post", because
both comments and posts are neighbours of users. This is what makes a
shallow diagram readable: the neighbourhood is drawn as it is, not as a star.
A column keeps its FK marker even when the table it references is out of
scope:
posts {
bigint author_id FK
bigint category_id FK
bigint id PK
}Here categories was not selected, and category_id FK is still correct: the
constraint exists in the database. Treat a marker with no matching edge as a
sign that the diagram is scoped, not that something is broken.
--exclude-relations takes a comma-separated list of type names:
php artisan cartographer:erd --exclude-relations=through
php artisan cartographer:erd --exclude-relations=morph,belongs_to_many// config/cartographer.php
'relations' => [
'exclude' => ['through'],
],Values match against the type names in relationship detection, plus two group aliases:
| Value | Removes |
|---|---|
through | has_one_through and has_many_through |
morph | morph_to, morph_one, morph_many, morph_to_many, morphed_by_many |
| An exact type name | Only that type, such as belongs_to_many, morph_many, or has_one |
Matching is forgiving about formatting: values are trimmed, lowercased, and
hyphens and spaces become underscores, so Belongs-To-Many and
belongs_to_many are the same thing.
through relations are the usual first exclusion. They are shortcuts across an
intermediate model, so they add an edge the diagram already implies through two
others.
One asymmetry to know about: excluding morph_many on its own removes those
edges but leaves the morph_to edges pointing back, because the inverse
relations are read before exclusions are applied. Exclude morph when you want
the family gone.
Passing --exclude-relations ignores relations.exclude entirely, rather than
merging with it. Passing --exclude-relations= with an empty value clears the
configured exclusions for that run.
--only and --except both take a comma-separated list of models, in short or
fully qualified form, and they are not opposites.
php artisan cartographer:erd --only=Order,Invoice
php artisan cartographer:erd --except=Telemetry,AuditLog--only | --except | |
|---|---|---|
| Names | What to keep | What to drop |
| A relation leaving the set | Keeps its edge, far entity stubbed | Gone with the model |
Relationship to exclude_models | Independent | Composes with it |
| Equivalent to | A group, unnamed | A one-run exclude_models |
--only scopes the diagram the way a group does. A model outside the set that
something inside points at is drawn as a stub: a bare entity name, no columns,
no edges of its own.
erDiagram
invoices }o--|| users : "user"
invoices {
bigint id PK
bigint user_id FK
}
usersThat is the point of --only. The diagram stays honest about its boundaries
without dragging in everything on the other side of them.
--except removes the models outright. Their entities and every edge touching
them are gone, and nothing is stubbed, because the model was never part of the
run to begin with. It composes with exclude_models rather than replacing it,
so a model named in either place is out.
Removing everything fails rather than writing an empty diagram:
ERROR Every discovered model was excluded. Check [--except] and [cartographer.exclude_models].Use --except for noise: token tables, job tables, audit logs, telemetry.
Things that are real schema and never what anyone opened the diagram to look
at.
Use --only for a subsystem, when the boundary itself is information. Then
promote it to a group once you want the file committed, because a group
regenerates on every run and a remembered flag does not.
Passing --only or --except, like passing --models, --depth, --output,
or --stdout, produces that one diagram and leaves the configured group files
untouched. An experiment cannot rewrite your committed set.
--group is the exception, and it refuses to be narrowed further:
ERROR A group is already a scope, so [--group] cannot be combined with
[--only], [--except], [--models] or [--depth].A many-to-many relation draws its edge directly between the two models:
posts }o--o{ tags : "tags"The pivot table is still added as an entity, with its columns, whenever the edge is in scope and the table exists:
post_tag {
bigint id PK
bigint post_id FK, UK
bigint tag_id FK, UK
}It has no edges of its own. A pivot can still contain important columns such as
sort_order, added_by, or timestamps. Showing the pivot keeps those columns
and the table count visible. A pivot is removed when its relationship falls
outside the scope.
Pivot entities never carry a model class, so columns.exclude cannot hide
columns on them.
The three controls combine:
php artisan cartographer:erd \
--models=Post,Category \
--depth=1 \
--exclude-relations=through,morph \
--except=AuditLog \
--columns=keys \
--output=docs/erd-publishing.mdRead it as: drop AuditLog from the run, ignore through and polymorphic
relations entirely, start at Post and Category, follow one hop, show key
columns only, write it beside the full diagram.
--only is the one that does not compose usefully with the rest. It names the
final set outright, so combining it with seeds and depth means two answers to
the same question. Reach for one or the other.