このページは英語でのみご覧いただけます。
Laravel
Pathruleルール3件 • メモリ2件 • スキル1件
A bundle for teams on Laravel 12 and 13 that keeps agents on the framework's own idioms instead of generic PHP. It covers the four places Laravel apps rot: Eloquent relations that lazy-load inside a Blade loop, controllers that read straight from the request, jobs that are not idempotent and duplicate work on retry, and a production deploy that never caches config or routes. Written so each piece lands on the directory it governs rather than in one README nobody scopes.
推奨されるパスの配置
Pathruleは各要素を対応するパスに配置するため、アシスタントはそれが属する場所でだけ参照します。これはインポート時に適用されるスコープで、ワークスペースで調整できます。
ルール
3Eager-load every relation a view or resource reads/app高強制Declare `with()` on the query that feeds a view, resource, or export, and fail loudly on lazy loading in local and CI.
| 1 | Eloquent will happily run one query per row, and Blade makes it invisible: the loop reads `$order->customer->name` and the page fires 200 queries. |
| 2 | |
| 3 | - Load relations on the query, not in the template: `Order::with(['customer', 'items.product'])`. If a Blade view, API resource, or export touches a relation, the query that feeds it declares it. |
| 4 | - Turn lazy loading into an error outside production with `Model::preventLazyLoading(! app()->isProduction())` in a service provider. This is the single highest-value line in a Laravel app. |
| 5 | - Use `withCount` for counts, `chunk`/`lazy`/`cursor` for large sets, and `select` the columns you need. Loading full models to count them is wasted memory. |
| 6 | - Never call a query inside an accessor or a `map` over a collection. Load what you need in one query and key it by id. |
| 7 | - Watch the inverse too: `whereHas` on a deep relation can be slower than a join with an index. Read the query log before optimising by feel. |
Make queued jobs idempotent and bounded/app/Jobs高強制Queues deliver at least once: give every job a retry budget, a unique lock where it must not overlap, and a side effect that is safe to repeat.
| 1 | A queued job will run twice eventually: a worker is killed mid-run, a deploy restarts the pool, a transient failure triggers a retry. Design for the second run. |
| 2 | |
| 3 | - Set `$tries` and `$backoff` (or `retryUntil`) on every job. A job with unlimited retries and a permanent failure is an infinite loop that burns the queue. |
| 4 | - Make the side effect idempotent: check state before acting, or key it on something stable so a repeat is a no-op. Charging a card, sending an email, or incrementing a counter twice must be impossible. |
| 5 | - Use `ShouldBeUnique` (or an explicit cache lock) for jobs that must not overlap for the same subject, and `ShouldBeUniqueUntilProcessing` where only the queued window matters. |
| 6 | - Dispatch after the transaction commits (`dispatch()->afterCommit()` or `after_commit` on the connection). A job that reads a row the transaction has not committed yet fails intermittently and is a nightmare to reproduce. |
| 7 | - Pass ids, not serialized models, and handle the row being gone. Implement `failed()` so a dead job leaves a trace instead of silence. |
| 8 | |
| 9 | See the background-jobs-queues pattern for the queue-agnostic version of these constraints. |
メモリ
2Where code goes in a Laravel app, and what stays out of the container/appActions and services hold workflows, models hold scopes and casts, and anything expensive is resolved lazily rather than in a provider boot.
| 1 | Laravel's structure is loose enough that two developers produce two architectures. Pick the conventional one and stay in it. |
| 2 | |
| 3 | - Controllers stay thin: resolve, delegate, respond. Multi-step workflows go in a single-purpose action or service class under `App\Actions` or `App\Services`, which is testable without HTTP and reusable from a command or job. |
| 4 | - Models own their query vocabulary: local scopes for reusable filters, casts for value conversion, accessors for derived display values. Business decisions that span models do not belong there. |
| 5 | - Avoid heavy work in a service provider's `boot()`. It runs on every request, including artisan commands and health checks. Bind lazily and let the container resolve on demand. |
| 6 | - Prefer explicit event listeners over model events for anything a reader needs to know about, and never rely on model events in bulk paths: `Model::query()->update()` bypasses them entirely, exactly like Eloquent's docs say. |
| 7 | - Keep Blade for presentation. A view that queries, formats money, or decides permissions is a view that cannot be tested. |
| 8 | |
| 9 | See /app/Http for the request rules and /app/Jobs for the queue rules. |
Migrations, seeders, and the production deploy sequence/databaseMigrations are forward-only in production, seeders stay idempotent, and every deploy caches config, routes, views, and events.
| 1 | Most Laravel production surprises come from the deploy, not the code. |
| 2 | |
| 3 | - Cache everything the framework can precompute on deploy: `config:cache`, `route:cache`, `view:cache`, `event:cache`. Without config caching, every request re-reads your config tree, and `env()` calls outside config files return null once caching is on. Read config, never `env()`, at runtime. |
| 4 | - Run `migrate --force` as part of the release, and treat migrations as forward-only in production. Rolling back a shipped migration is a data decision, not a command. |
| 5 | - Keep destructive schema changes multi-step: add nullable, deploy writers, backfill, then constrain or drop. On MySQL, an added index or a changed column type can lock a large table. |
| 6 | - Seeders are for reference data and must be idempotent (`upsert`/`firstOrCreate`), so re-running one does not duplicate rows. Test data belongs in factories. |
| 7 | - Restart the queue workers after every deploy (`queue:restart`); long-lived workers keep the old code in memory until they cycle. |
| 8 | |
| 9 | See /app/Jobs for the job design that makes a worker restart safe. |
スキル
1laravel-pre-merge-review/rootChecklist for any Laravel change that adds a controller, model query, job, or migration.
| 1 | --- |
| 2 | name: laravel-pre-merge-review |
| 3 | description: Laravel review checklist covering Eloquent query efficiency, request validation and authorization, queued job safety, and deploy-time caching. Run before merging. |
| 4 | --- |
| 5 | |
| 6 | # Laravel review |
| 7 | |
| 8 | ## Eloquent |
| 9 | - [ ] Every relation the view, resource, or export reads is eager-loaded on the query. |
| 10 | - [ ] No query inside a loop, accessor, or collection callback. |
| 11 | - [ ] `preventLazyLoading` is on outside production and the change does not trip it. |
| 12 | - [ ] Large reads use `chunk`, `lazy`, or `cursor`; counts use `withCount`. |
| 13 | |
| 14 | ## Request handling |
| 15 | - [ ] Writes take a `FormRequest`; the controller never reads `$request->all()`. |
| 16 | - [ ] A policy or gate authorizes the action on the specific record. |
| 17 | - [ ] Responses go through an API resource; `$fillable` is accurate. |
| 18 | |
| 19 | ## Jobs and events |
| 20 | - [ ] `$tries` and `$backoff` are set; the side effect is safe to repeat. |
| 21 | - [ ] Overlap-sensitive jobs use `ShouldBeUnique` or an explicit lock. |
| 22 | - [ ] Dispatch happens after commit; the job takes ids, not models, and handles a missing row. |
| 23 | |
| 24 | ## Migrations and deploy |
| 25 | - [ ] Schema change is additive, or split into add, backfill, constrain. |
| 26 | - [ ] No runtime `env()` call outside a config file. |
| 27 | - [ ] Seeder changes are idempotent. |
このパターンを使う理由
AI agents write Laravel code that lazy-loads relations inside Blade loops, validates inline in controllers, authorizes nowhere, and queues jobs that duplicate work when they retry.
対象:PHP teams shipping Laravel 12 or 13 applications
アシスタントが次のことをしないようにします。
- Lazy-loading a relation inside a Blade or collection loop and firing N queries
- Reading request input directly in a controller with no validation or authorization
- Queueing a job that repeats its side effect every time the queue retries it
- Deploying without caching config, routes, views, and events
- ライセンス
- Apache-2.0
- バージョン
- 1.0.0
- 更新日
- 2026-08-24