$npx -y skills add tranhieutt/software_development_department --skill laravel-patternsProvides Laravel PHP patterns for Eloquent ORM, Artisan commands, queues, middleware, and API resources. Use when working with PHP Laravel files (*.php) or when the user mentions Laravel, Eloquent, or PHP framework.
| 1 | # Laravel Development Patterns |
| 2 | |
| 3 | Production-grade Laravel architecture patterns for scalable, maintainable applications. |
| 4 | |
| 5 | ## When to Use |
| 6 | |
| 7 | - Building Laravel web applications or APIs |
| 8 | - Structuring controllers, services, and domain logic |
| 9 | - Working with Eloquent models and relationships |
| 10 | - Designing APIs with resources and pagination |
| 11 | - Adding queues, events, caching, and background jobs |
| 12 | |
| 13 | ## How It Works |
| 14 | |
| 15 | - Structure the app around clear boundaries (controllers -> services/actions -> models). |
| 16 | - Use explicit bindings and scoped bindings to keep routing predictable; still enforce authorization for access control. |
| 17 | - Favor typed models, casts, and scopes to keep domain logic consistent. |
| 18 | - Keep IO-heavy work in queues and cache expensive reads. |
| 19 | - Centralize config in `config/*` and keep environments explicit. |
| 20 | |
| 21 | ## Examples |
| 22 | |
| 23 | ### Project Structure |
| 24 | |
| 25 | Use a conventional Laravel layout with clear layer boundaries (HTTP, services/actions, models). |
| 26 | |
| 27 | ### Recommended Layout |
| 28 | |
| 29 | ``` |
| 30 | app/ |
| 31 | ├── Actions/ # Single-purpose use cases |
| 32 | ├── Console/ |
| 33 | ├── Events/ |
| 34 | ├── Exceptions/ |
| 35 | ├── Http/ |
| 36 | │ ├── Controllers/ |
| 37 | │ ├── Middleware/ |
| 38 | │ ├── Requests/ # Form request validation |
| 39 | │ └── Resources/ # API resources |
| 40 | ├── Jobs/ |
| 41 | ├── Models/ |
| 42 | ├── Policies/ |
| 43 | ├── Providers/ |
| 44 | ├── Services/ # Coordinating domain services |
| 45 | └── Support/ |
| 46 | config/ |
| 47 | database/ |
| 48 | ├── factories/ |
| 49 | ├── migrations/ |
| 50 | └── seeders/ |
| 51 | resources/ |
| 52 | ├── views/ |
| 53 | └── lang/ |
| 54 | routes/ |
| 55 | ├── api.php |
| 56 | ├── web.php |
| 57 | └── console.php |
| 58 | ``` |
| 59 | |
| 60 | ### Controllers -> Services -> Actions |
| 61 | |
| 62 | Keep controllers thin. Put orchestration in services and single-purpose logic in actions. |
| 63 | |
| 64 | ```php |
| 65 | final class CreateOrderAction |
| 66 | { |
| 67 | public function __construct(private OrderRepository $orders) {} |
| 68 | |
| 69 | public function handle(CreateOrderData $data): Order |
| 70 | { |
| 71 | return $this->orders->create($data); |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | final class OrdersController extends Controller |
| 76 | { |
| 77 | public function __construct(private CreateOrderAction $createOrder) {} |
| 78 | |
| 79 | public function store(StoreOrderRequest $request): JsonResponse |
| 80 | { |
| 81 | $order = $this->createOrder->handle($request->toDto()); |
| 82 | |
| 83 | return response()->json([ |
| 84 | 'success' => true, |
| 85 | 'data' => OrderResource::make($order), |
| 86 | 'error' => null, |
| 87 | 'meta' => null, |
| 88 | ], 201); |
| 89 | } |
| 90 | } |
| 91 | ``` |
| 92 | |
| 93 | ### Routing and Controllers |
| 94 | |
| 95 | Prefer route-model binding and resource controllers for clarity. |
| 96 | |
| 97 | ```php |
| 98 | use Illuminate\Support\Facades\Route; |
| 99 | |
| 100 | Route::middleware('auth:sanctum')->group(function () { |
| 101 | Route::apiResource('projects', ProjectController::class); |
| 102 | }); |
| 103 | ``` |
| 104 | |
| 105 | ### Route Model Binding (Scoped) |
| 106 | |
| 107 | Use scoped bindings to prevent cross-tenant access. |
| 108 | |
| 109 | ```php |
| 110 | Route::scopeBindings()->group(function () { |
| 111 | Route::get('/accounts/{account}/projects/{project}', [ProjectController::class, 'show']); |
| 112 | }); |
| 113 | ``` |
| 114 | |
| 115 | ### Nested Routes and Binding Names |
| 116 | |
| 117 | - Keep prefixes and paths consistent to avoid double nesting (e.g., `conversation` vs `conversations`). |
| 118 | - Use a single parameter name that matches the bound model (e.g., `{conversation}` for `Conversation`). |
| 119 | - Prefer scoped bindings when nesting to enforce parent-child relationships. |
| 120 | |
| 121 | ```php |
| 122 | use App\Http\Controllers\Api\ConversationController; |
| 123 | use App\Http\Controllers\Api\MessageController; |
| 124 | use Illuminate\Support\Facades\Route; |
| 125 | |
| 126 | Route::middleware('auth:sanctum')->prefix('conversations')->group(function () { |
| 127 | Route::post('/', [ConversationController::class, 'store'])->name('conversations.store'); |
| 128 | |
| 129 | Route::scopeBindings()->group(function () { |
| 130 | Route::get('/{conversation}', [ConversationController::class, 'show']) |
| 131 | ->name('conversations.show'); |
| 132 | |
| 133 | Route::post('/{conversation}/messages', [MessageController::class, 'store']) |
| 134 | ->name('conversation-messages.store'); |
| 135 | |
| 136 | Route::get('/{conversation}/messages/{message}', [MessageController::class, 'show']) |
| 137 | ->name('conversation-messages.show'); |
| 138 | }); |
| 139 | }); |
| 140 | ``` |
| 141 | |
| 142 | If you want a parameter to resolve to a different model class, define explicit binding. For custom binding logic, use `Route::bind()` or implement `resolveRouteBinding()` on the model. |
| 143 | |
| 144 | ```php |
| 145 | use App\Models\AiConversation; |
| 146 | use Illuminate\Support\Facades\Route; |
| 147 | |
| 148 | Route::model('conversation', AiConversation::class); |
| 149 | ``` |
| 150 | |
| 151 | ### Service Container Bindings |
| 152 | |
| 153 | Bind interfaces to implementations in a service provider for clear dependency wiring. |
| 154 | |
| 155 | ```php |
| 156 | use App\Repositories\EloquentOrderRepository; |
| 157 | use App\Repositories\OrderRepository; |