andrey-helldar/laravel-ide-facades-helper
Laravel IDE Facades Helper generates IDE helper files for Laravel facades, adding PHPDoc annotations so editors and IDEs can autocomplete facade methods and static calls more accurately.
Laravel facades are static-looking calls routed through __callStatic, so without help an IDE sees Illuminate\Support\Facades\Cache as a class with almost no methods — no completions, no parameter hints, no return types, and PHPStan/Larastan complaining about valid calls. This package closes that specific gap: it walks each facade's getFacadeAccessor() to the underlying class and writes a single stub file of @method annotations your editor reads as ordinary PHP.
Minimal adoption:
composer require --dev andrey-helldar/laravel-ide-facades-helper
php artisan ide-facades-helper:generate
That produces _ide_helper_facades.php in the project root. Nothing is registered on the request path, no runtime behaviour changes, and uninstalling is composer remove --dev plus deleting the file.
Where to look first, in this order:
_ide_helper_facades.php itself. Open it and skim the facades and methods it contains. It is the ground truth for "why doesn't Http::withToken() autocomplete?" — if the method isn't in there, the generator never resolved it, and the fix is config, not your IDE.php artisan vendor:publish and pick the package's provider/tag, or read the defaults straight out of vendor/.../config/. This is where the facade list and any exclusions live.php artisan ide-facades-helper:generate --help. Cheapest way to see current options before reading source, which matters for an archived package where docs may lag.First real use case: you add a Seo:: facade wrapping a SeoManager service, register it in config/app.php aliases, and it autocompletes nowhere. Run the generate command, reopen the stub, and the facade is now present with the accessor's public methods and docblocks. That fifteen-second loop — add facade, regenerate, confirm — is the whole day-to-day workflow.
Before you adopt, verify the package's declared PHP/Laravel ranges against your matrix. This is archived (last release Jan 2022), so it does not track modern Laravel. It is fine on the versions it declares; on a current Laravel it may resolve a partial or stale facade list. Treat it as a known-good-on-older-stacks tool, not a forward-compatible one, and pin the version you validate.
Make regeneration automatic, not remembered. The stub is a build artifact and goes stale the moment you upgrade the framework or repoint a facade accessor. Hook it into Composer so it refreshes whenever the autoloader is rebuilt:
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi",
"@php artisan ide-facades-helper:generate --quiet"
]
}
post-autoload-dump fires on install, update, and dump-autoload, which covers nearly every event that can change the facade surface. Guard it against production (see Gotchas) or move it to a composer ide script developers invoke explicitly — with an archived dependency, the explicit script is the lower-surprise choice.
Extend the facade list in config, never in the artifact. The generated file is overwritten wholesale on every run, so any hand-written annotation in it is lost. Project-specific facades belong in the config list. Keep the config in version control alongside the rest of your app config.
Commit vs. gitignore is a real team decision.
Committing is usually the better default for analyser consistency. Reduce the noise with .gitattributes:
_ide_helper_facades.php linguist-generated=true merge=ours
Pair it with barryvdh/laravel-ide-helper, don't replace it. That package covers models, container bindings, and _ide_helper.php; this one covers facade signatures only. They coexist by design. If you enable ide-helper's own facade generation too, you may get duplicated or conflicting annotations on the same facade — pick one source for facades and disable the other.
Wire it into static analysis. If you run Larastan/PHPStan, generate the stub before analysis and make it visible to the analyser (bootstrap or scanFiles). Without that, the analyser never sees the annotations and keeps reporting "call to an undefined static method" on perfectly correct facade usage — which is the exact problem you installed this to solve.
Use exclusions as a scalpel, not a hammer. When a single method on a facade produces a misleading signature, exclude that method rather than removing the facade from the list entirely. You keep the other 95% of the completions.
Add a separate hand-written stub for macros. Runtime macros registered in service providers are invisible to the generator. Keep a small _ide_helper_macros.php with plain @method blocks for the macros your team actually uses; it sits alongside the generated file without conflict, and survives regeneration because it is a different file.
Never let the generator run in production. post-autoload-dump fires regardless of APP_ENV. If you use the hook form, wrap it so prod short-circuits, or use a named script that only developers and CI call. The package is dev-only, so production installs (--no-dev) won't have the command at all — a bare hook will then fail the deploy with "command not found."
PhpStorm won't notice a newly created file. After the first generation, use File → Synchronize or Invalidate Caches / Restart once. Also confirm the path isn't excluded under Settings → Directories and isn't caught by a "skip indexing" pattern — a _ide_helper*.php exclusion rule from another tool is a common culprit.
A facade that resolves to a string alias or runtime-bound interface comes back thin or empty. The generator follows getFacadeAccessor() to a class to read its methods. If the accessor returns an alias bound only at runtime, resolution fails silently. Fix by binding the concrete class in a provider that boots during the command, or map the facade manually in config.
Real-time facades are out of scope. use App\Services\Foo; followed by Foo::bar() has no static facade to introspect. Those need manual @method blocks or a different mechanism — don't expect this package to help.
"The file looks right but autocomplete still fails" has three usual causes, in order: the file isn't indexed (excluded/skipped in the IDE); the method is excluded by your config; or the method genuinely lives on a sub-object reached through __call (Cache::store()->…, Http::withHeader()->…) and is therefore never on the facade's own class.
Archived-package risk is real but bounded. Two failure modes: composer constraint conflicts blocking a Laravel/PHP upgrade, and the facade map drifting behind a newer framework so the stub silently omits or misdescribes facades. Both are cheap to detect — regenerate in CI and fail on git diff --exit-code against the committed file, which surfaces staleness as a build failure instead of a developer confusion. If the package ever lags your framework, dropping it costs one command and one deleted file; nothing in production depends on it.
Extension points are limited to config. You can adjust the facade list and exclusions, and that's essentially it. If you need behaviour it doesn't offer, the pragmatic answer is a second hand-written stub file merged into the same indexing path — not patching vendor/, which is silently destroyed on the next composer update.
How can I help you explore Laravel packages today?