›
byrcsc/laravel-cartographer · 1.x
Cartographer scans configured directories and keeps the classes that qualify as Eloquent models.
Before building a diagram, Cartographer needs to find your models. It scans the
directories listed in cartographer.paths and checks the PHP classes inside
them.
// config/cartographer.php
'paths' => [
app_path('Models'),
],Each entry is expanded as a glob against directories. Every matched
directory is scanned recursively for .php files.
A class qualifies when all four statements are true:
.php file.Illuminate\Database\Eloquent\Model.Cartographer skips traits, interfaces, enums, plain classes, anonymous classes, and files without a class. A file can contribute two models when it declares two classes and both qualify.
Cartographer reads class declarations from PHP tokens instead of relying on
filenames. A HasSlug.php file containing a trait contributes nothing. A
Catalog.php file declaring Product and Variant contributes both models.
Discovery is where exclude_models is applied:
'exclude_models' => [
App\Models\Telemetry::class,
App\Models\PasswordReset::class,
],An excluded model produces no entity and no edges. Relations that other models declare towards it are dropped too, because the edge has nowhere to land.
Globs are the reason paths is a list of patterns rather than a list of
directories:
'paths' => [
app_path('Models'),
base_path('src/Domain/*/Models'),
base_path('modules/*/src/Models'),
],src/Domain/*/Models matches src/Domain/Billing/Models,
src/Domain/Catalog/Models, and any domain added later. Nothing needs updating
when a new module appears.
Only *-style directory matching is available. Cartographer passes the pattern
to PHP's glob() function and keeps directory matches. It does not filter by
class name, namespace, or filename. Use exclude_models to remove individual
classes from a matched directory.
Files are keyed by their resolved real path, so a file reached through two
patterns is read once. Listing app_path('Models') twice, or listing both a
parent and a child directory, changes nothing about the result.
The final list is sorted by fully qualified class name. Directory order,
filesystem order, and the order of the paths array have no effect on the
output. This is one half of why the diagram is stable between runs.
A pattern matching no directory produces a warning and is skipped:
WARN Model discovery path matched no directories: /srv/app/src/Domain/*/ModelsThe run continues. This is deliberate: a glob for modules that do not exist yet in a given deployment should not break the command.
Warnings are suppressed under --stdout, so piped output stays clean. If you
are debugging paths, run without --stdout.
When discovery finds nothing at all, the command fails instead:
ERROR No Eloquent models were discovered. Check the paths configured in [cartographer.paths].Discovery produces candidates, not entities. A discovered model is dropped from the graph at assembly time when either is true:
It cannot be instantiated. new Model is called to read the table name; if
the constructor throws, the model is skipped with a warning naming the
exception.
Its table does not exist on the target connection:
WARN Skipping model [App\Models\Ghost]: table [missing_ghosts] does not exist.The second is the common one, and it usually means the database is behind the code. Run your migrations and generate again.
paths and exclude_models are validated when the command runs, and a bad
value fails it:
| Problem | Message |
|---|---|
paths is not an array | [cartographer.paths] must be an array of strings. |
paths contains a non-string or an empty string | [cartographer.paths] must contain only non-empty strings. |
exclude_models contains a class that is not a model | [cartographer.exclude_models] must contain only Eloquent model class names. |
exclude_models entries are checked with is_a(..., Model::class, true), so
the class must be loadable. A typo in the class name fails the command rather
than silently excluding nothing.