dottedai/laravel-model-annotator
Automatically generates PHPDoc annotations for Laravel Eloquent models, adding @property, @method and relationship hints so your IDE and static analysers understand attributes, scopes and relations without guesswork.
The package is a lightweight codegen utility: an artisan command that inspects your database schema and Eloquent relationship definitions, then writes PHPDoc blocks onto your model classes (property annotations for columns, relationship return types, and @property casts). It is the kind of thing you install once per project and then fold into your working loop.
Minimal steps:
composer require --dev dottedai/laravel-model-annotator
vendor/dottedai/laravel-model-annotator/ for the service provider's publishes() calls and the command's $signature — with a package this small, reading the command class takes two minutes and is faster than guessing at flags.php artisan model:annotate App\\Models\\User
(Confirm the exact command name/arguments from php artisan list | grep annotate.)@property lines for every column, correct @property-read for belongsTo/hasMany, and @property Carbon $created_at-style cast awareness.First use case: a model that your IDE and static analyser currently treat as a black hole. Pick the model you touch most in a given week, run the annotation, and confirm $user->email_address now resolves in your editor without "undefined property" noise. That one model is your proof of value; anything beyond that is rollout.
Where to look first: the command class itself (source of truth for flags like --all, --force, --no-relations), any config file, and the package's own tests — a zero-star package's tests tell you more about intended behaviour than its README.
Single-model, on-demand runs. The safest daily pattern. Annotate the model you're actively working on after a migration adds or renames columns:
php artisan model:annotate App\\Models\\Order --force
Keep this as a muscle-memory step after php artisan migrate on a branch that changes schema.
Batch baseline, then incremental. Do one full pass to bring the whole App\Models namespace up to date, commit the resulting PHPDoc diff as a pure "no logic changed" commit, then rely on single-model runs from there. A single giant annotation commit is reviewable; interleaved annotation noise inside feature PRs is not.
CI drift check. If the command is idempotent (annotations deterministic for a given schema + model), add a CI job that runs it and fails on a dirty working tree:
php artisan model:annotate --all
git diff --exit-code app/Models
This keeps annotations from going stale silently. Verify idempotency locally first — run twice and confirm the second run produces an empty diff. If it isn't deterministic, drop this pattern.
Pair with static analysis. The real payoff is feeding cleaner types to PHPStan/Larastan or Psalm. Generated @property blocks reduce the need for manual @property maintenance and catch relationship nullability mistakes at analysis time. Order matters: run the annotator before static analysis in your pipeline.
Use annotations as discovery documentation. On an unfamiliar codebase, running the annotator over all models gives you a fast, accurate map of schema columns, casts, and relationship directions directly in the model files — often more reliable than reading migrations, because it reflects the live schema.
Respect hand-written docblocks. If the tool appends rather than replaces, adopt a convention: keep your prose docblock at the top and let the tool own the @property/@method block below a separator, so regeneration doesn't nuke your notes. If the tool fully replaces the block, keep explanatory prose in comments above the class declaration, not in the PHPDoc.
migrate on a fresh clone produces empty or wrong annotations. Run migrations, then annotate.--force/overwrite semantics or prompts. Commit before the first run so you can git diff and git checkout cleanly if a whole namespace gets mangled.@property vs @property-read. Getters for relationships and accessors should be -read; if the tool guesses wrong you'll get spurious "read-only property modified" static-analysis errors. Spot-check one belongsTo and one accessor-backed attribute.$appends accessors don't exist in the schema, so they may not appear. Add those manually and expect to re-add them if the tool fully replaces the docblock.morphTo) often degrade to generic annotations. Review those by hand.barryvdh/laravel-ide-helper. If you already run ide-helper:models, don't run both — they fight over the same docblocks. Pick one owner for @property annotations. This package is narrower (schema + relations + casts) but the conflict is real; audit existing model docblocks before adopting.--connection flag exists; if not, that's a hard limitation for sharded or tenant-per-database setups.composer.json, and be prepared to fork it. It's small enough that a fork is cheaper than waiting on maintainer response if the tool breaks on a new Laravel/PHP version. There's no ecosystem safety net here.How can I help you explore Laravel packages today?