@famgia/omnify-laravel 0.0.88 → 0.0.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-YVVAJA3T.js → chunk-2QSKZS63.js} +188 -12
- package/dist/chunk-2QSKZS63.js.map +1 -0
- package/dist/index.cjs +190 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -1
- package/dist/index.d.ts +48 -1
- package/dist/index.js +5 -1
- package/dist/plugin.cjs +186 -11
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.js +1 -1
- package/package.json +5 -5
- package/scripts/postinstall.js +29 -36
- package/stubs/ai-guides/README.md.stub +95 -0
- package/stubs/ai-guides/claude-agents/architect.md.stub +150 -0
- package/stubs/ai-guides/claude-agents/developer.md.stub +190 -0
- package/stubs/ai-guides/claude-agents/reviewer.md.stub +134 -0
- package/stubs/ai-guides/claude-agents/tester.md.stub +196 -0
- package/stubs/ai-guides/claude-checklists/backend.md.stub +112 -0
- package/stubs/ai-guides/claude-omnify/antdesign-guide.md.stub +401 -0
- package/stubs/ai-guides/claude-omnify/config-guide.md.stub +253 -0
- package/stubs/ai-guides/claude-omnify/japan-guide.md.stub +186 -0
- package/stubs/ai-guides/claude-omnify/laravel-guide.md.stub +61 -0
- package/stubs/ai-guides/claude-omnify/react-form-guide.md.stub +259 -0
- package/stubs/ai-guides/claude-omnify/schema-guide.md.stub +115 -0
- package/stubs/ai-guides/claude-omnify/typescript-guide.md.stub +310 -0
- package/stubs/ai-guides/claude-rules/naming.md.stub +364 -0
- package/stubs/ai-guides/claude-rules/performance.md.stub +251 -0
- package/stubs/ai-guides/claude-rules/security.md.stub +159 -0
- package/stubs/ai-guides/claude-workflows/bug-fix.md.stub +201 -0
- package/stubs/ai-guides/claude-workflows/code-review.md.stub +164 -0
- package/stubs/ai-guides/claude-workflows/new-feature.md.stub +327 -0
- package/stubs/ai-guides/cursor/laravel-controller.mdc.stub +391 -0
- package/stubs/ai-guides/cursor/laravel-request.mdc.stub +112 -0
- package/stubs/ai-guides/cursor/laravel-resource.mdc.stub +73 -0
- package/stubs/ai-guides/cursor/laravel-review.mdc.stub +69 -0
- package/stubs/ai-guides/cursor/laravel-testing.mdc.stub +138 -0
- package/stubs/ai-guides/cursor/laravel.mdc.stub +82 -0
- package/stubs/ai-guides/cursor/omnify.mdc.stub +58 -0
- package/stubs/ai-guides/laravel/README.md.stub +59 -0
- package/stubs/ai-guides/laravel/architecture.md.stub +424 -0
- package/stubs/ai-guides/laravel/controller.md.stub +484 -0
- package/stubs/ai-guides/laravel/datetime.md.stub +334 -0
- package/stubs/ai-guides/laravel/openapi.md.stub +369 -0
- package/stubs/ai-guides/laravel/request.md.stub +450 -0
- package/stubs/ai-guides/laravel/resource.md.stub +516 -0
- package/stubs/ai-guides/laravel/service.md.stub +503 -0
- package/stubs/ai-guides/laravel/testing.md.stub +1504 -0
- package/ai-guides/laravel-guide.md +0 -461
- package/dist/chunk-YVVAJA3T.js.map +0 -1
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
# Controller Guide
|
|
2
|
+
|
|
3
|
+
> **Related:** [README](./README.md) | [Service Guide](./service-guide.md) | [Request Guide](./request-guide.md)
|
|
4
|
+
|
|
5
|
+
## Golden Rule: Thin Controller
|
|
6
|
+
|
|
7
|
+
Controllers should only:
|
|
8
|
+
1. **Receive** validated input (via FormRequest)
|
|
9
|
+
2. **Delegate** to Model or Service
|
|
10
|
+
3. **Return** formatted response (via Resource)
|
|
11
|
+
|
|
12
|
+
```php
|
|
13
|
+
// ✅ PERFECT: Thin controller
|
|
14
|
+
public function store(UserStoreRequest $request): UserResource
|
|
15
|
+
{
|
|
16
|
+
$user = User::create($request->validated());
|
|
17
|
+
return new UserResource($user);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ❌ BAD: Fat controller
|
|
21
|
+
public function store(Request $request)
|
|
22
|
+
{
|
|
23
|
+
$validated = $request->validate([...]); // Validation here
|
|
24
|
+
$user = new User();
|
|
25
|
+
$user->name = $validated['name']; // Manual assignment
|
|
26
|
+
$user->password = bcrypt($validated['password']); // Logic here
|
|
27
|
+
$user->save();
|
|
28
|
+
Mail::to($user)->send(new WelcomeMail()); // Side effects here
|
|
29
|
+
return response()->json([ // Manual formatting
|
|
30
|
+
'id' => $user->id,
|
|
31
|
+
'name' => $user->name,
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## CRUD Controller Template
|
|
39
|
+
|
|
40
|
+
```php
|
|
41
|
+
<?php
|
|
42
|
+
|
|
43
|
+
namespace App\Http\Controllers;
|
|
44
|
+
|
|
45
|
+
use App\Http\Requests\UserStoreRequest;
|
|
46
|
+
use App\Http\Requests\UserUpdateRequest;
|
|
47
|
+
use App\Http\Resources\UserResource;
|
|
48
|
+
use App\Models\User;
|
|
49
|
+
use Illuminate\Http\JsonResponse;
|
|
50
|
+
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
|
51
|
+
use Spatie\QueryBuilder\AllowedFilter;
|
|
52
|
+
use Spatie\QueryBuilder\QueryBuilder;
|
|
53
|
+
|
|
54
|
+
class UserController extends Controller
|
|
55
|
+
{
|
|
56
|
+
/**
|
|
57
|
+
* Display a listing of the resource.
|
|
58
|
+
* GET /api/users?filter[search]=keyword&sort=-created_at&per_page=10
|
|
59
|
+
*/
|
|
60
|
+
public function index(): AnonymousResourceCollection
|
|
61
|
+
{
|
|
62
|
+
$users = QueryBuilder::for(User::class)
|
|
63
|
+
->allowedFilters([
|
|
64
|
+
AllowedFilter::callback('search', function ($query, $value) {
|
|
65
|
+
$query->where(function ($q) use ($value) {
|
|
66
|
+
$q->where('name', 'like', "%{$value}%")
|
|
67
|
+
->orWhere('email', 'like', "%{$value}%");
|
|
68
|
+
});
|
|
69
|
+
}),
|
|
70
|
+
])
|
|
71
|
+
->allowedSorts(['id', 'name', 'email', 'created_at', 'updated_at'])
|
|
72
|
+
->defaultSort('-id')
|
|
73
|
+
->paginate(request()->input('per_page', 10));
|
|
74
|
+
|
|
75
|
+
return UserResource::collection($users);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Store a newly created resource in storage.
|
|
80
|
+
* POST /api/users
|
|
81
|
+
*/
|
|
82
|
+
public function store(UserStoreRequest $request): JsonResponse
|
|
83
|
+
{
|
|
84
|
+
$user = User::create($request->validated());
|
|
85
|
+
|
|
86
|
+
return (new UserResource($user))
|
|
87
|
+
->response()
|
|
88
|
+
->setStatusCode(201);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Display the specified resource.
|
|
93
|
+
* GET /api/users/{user}
|
|
94
|
+
*/
|
|
95
|
+
public function show(User $user): UserResource
|
|
96
|
+
{
|
|
97
|
+
return new UserResource($user);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Update the specified resource in storage.
|
|
102
|
+
* PUT /api/users/{user}
|
|
103
|
+
*/
|
|
104
|
+
public function update(UserUpdateRequest $request, User $user): UserResource
|
|
105
|
+
{
|
|
106
|
+
$user->update($request->validated());
|
|
107
|
+
|
|
108
|
+
return new UserResource($user);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Remove the specified resource from storage.
|
|
113
|
+
* DELETE /api/users/{user}
|
|
114
|
+
*/
|
|
115
|
+
public function destroy(User $user): JsonResponse
|
|
116
|
+
{
|
|
117
|
+
$user->delete();
|
|
118
|
+
|
|
119
|
+
return response()->json(null, 204);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Controller Rules
|
|
127
|
+
|
|
128
|
+
### 1. Always Type-Hint Return Types
|
|
129
|
+
|
|
130
|
+
```php
|
|
131
|
+
// ✅ DO: Type-hint everything
|
|
132
|
+
public function index(): AnonymousResourceCollection
|
|
133
|
+
public function store(UserStoreRequest $request): UserResource
|
|
134
|
+
public function show(User $user): UserResource
|
|
135
|
+
public function destroy(User $user): JsonResponse
|
|
136
|
+
|
|
137
|
+
// ❌ DON'T: Missing return types
|
|
138
|
+
public function index()
|
|
139
|
+
public function store(Request $request)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 2. Use Route Model Binding
|
|
143
|
+
|
|
144
|
+
```php
|
|
145
|
+
// ✅ DO: Auto-resolve model from route parameter
|
|
146
|
+
public function show(User $user): UserResource
|
|
147
|
+
{
|
|
148
|
+
return new UserResource($user);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ❌ DON'T: Manual find
|
|
152
|
+
public function show(int $id): UserResource
|
|
153
|
+
{
|
|
154
|
+
$user = User::findOrFail($id);
|
|
155
|
+
return new UserResource($user);
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### 3. Always Use FormRequest for Validation
|
|
160
|
+
|
|
161
|
+
```php
|
|
162
|
+
// ✅ DO: Separate FormRequest class
|
|
163
|
+
public function store(UserStoreRequest $request): UserResource
|
|
164
|
+
{
|
|
165
|
+
$user = User::create($request->validated());
|
|
166
|
+
return new UserResource($user);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ❌ DON'T: Validate in controller
|
|
170
|
+
public function store(Request $request): UserResource
|
|
171
|
+
{
|
|
172
|
+
$validated = $request->validate([
|
|
173
|
+
'name' => 'required|string|max:255',
|
|
174
|
+
'email' => 'required|email|unique:users',
|
|
175
|
+
]);
|
|
176
|
+
// ...
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 4. Always Return Resource
|
|
181
|
+
|
|
182
|
+
```php
|
|
183
|
+
// ✅ DO: Use Resource for consistent formatting
|
|
184
|
+
return new UserResource($user);
|
|
185
|
+
return UserResource::collection($users);
|
|
186
|
+
|
|
187
|
+
// ❌ DON'T: Return model or array directly
|
|
188
|
+
return $user;
|
|
189
|
+
return response()->json(['data' => $user]);
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### 5. Use Dependency Injection for Services
|
|
193
|
+
|
|
194
|
+
```php
|
|
195
|
+
// ✅ DO: Constructor injection
|
|
196
|
+
class OrderController extends Controller
|
|
197
|
+
{
|
|
198
|
+
public function __construct(
|
|
199
|
+
private OrderService $orderService
|
|
200
|
+
) {}
|
|
201
|
+
|
|
202
|
+
public function store(OrderRequest $request): OrderResource
|
|
203
|
+
{
|
|
204
|
+
$order = $this->orderService->checkout(...);
|
|
205
|
+
return new OrderResource($order);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ❌ DON'T: Create service in method
|
|
210
|
+
public function store(OrderRequest $request): OrderResource
|
|
211
|
+
{
|
|
212
|
+
$service = new OrderService(); // Hard to test
|
|
213
|
+
// ...
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Query Parameters - List Endpoint
|
|
220
|
+
|
|
221
|
+
### Template
|
|
222
|
+
|
|
223
|
+
```php
|
|
224
|
+
use Spatie\QueryBuilder\AllowedFilter;
|
|
225
|
+
use Spatie\QueryBuilder\QueryBuilder;
|
|
226
|
+
|
|
227
|
+
public function index(): AnonymousResourceCollection
|
|
228
|
+
{
|
|
229
|
+
$users = QueryBuilder::for(User::class)
|
|
230
|
+
->allowedFilters([
|
|
231
|
+
AllowedFilter::callback('search', function ($query, $value) {
|
|
232
|
+
$query->where(function ($q) use ($value) {
|
|
233
|
+
$q->where('name', 'like', "%{$value}%")
|
|
234
|
+
->orWhere('email', 'like', "%{$value}%");
|
|
235
|
+
});
|
|
236
|
+
}),
|
|
237
|
+
])
|
|
238
|
+
->allowedSorts(['id', 'name', 'email', 'created_at'])
|
|
239
|
+
->defaultSort('-id')
|
|
240
|
+
->paginate(request()->input('per_page', 10));
|
|
241
|
+
|
|
242
|
+
return UserResource::collection($users);
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### API Example
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
GET /api/users?filter[search]=田中&sort=-created_at&per_page=20
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### OpenAPI - Use Reusable Parameters
|
|
253
|
+
|
|
254
|
+
```php
|
|
255
|
+
#[OA\Get(
|
|
256
|
+
path: '/api/users',
|
|
257
|
+
summary: 'List users',
|
|
258
|
+
description: 'Allowed sorts: id, name, email, created_at',
|
|
259
|
+
parameters: [
|
|
260
|
+
new OA\Parameter(ref: '#/components/parameters/FilterSearch'),
|
|
261
|
+
new OA\Parameter(ref: '#/components/parameters/QueryPage'),
|
|
262
|
+
new OA\Parameter(ref: '#/components/parameters/QueryPerPage'),
|
|
263
|
+
new OA\Parameter(ref: '#/components/parameters/QuerySort'),
|
|
264
|
+
],
|
|
265
|
+
)]
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Keep It Simple
|
|
269
|
+
|
|
270
|
+
```php
|
|
271
|
+
// ✅ DO: Simple, flat filters
|
|
272
|
+
->allowedFilters([
|
|
273
|
+
AllowedFilter::callback('search', fn($q, $v) => ...),
|
|
274
|
+
AllowedFilter::exact('status'),
|
|
275
|
+
])
|
|
276
|
+
->allowedSorts(['id', 'name', 'created_at'])
|
|
277
|
+
|
|
278
|
+
// ❌ DON'T: Over-engineer
|
|
279
|
+
->allowedFilters([
|
|
280
|
+
AllowedFilter::exact('author.company.country'), // Too nested!
|
|
281
|
+
])
|
|
282
|
+
->allowedIncludes(['a', 'b', 'c', 'd', 'e']) // Too many!
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## OpenAPI Schema Location
|
|
288
|
+
|
|
289
|
+
Define schemas close to the code that uses them:
|
|
290
|
+
|
|
291
|
+
| Type | Location | Example |
|
|
292
|
+
| ------------ | ------------------------- | --------------------------------------- |
|
|
293
|
+
| Request body | `*Request.php` | `UserStoreRequest`, `UserUpdateRequest` |
|
|
294
|
+
| Response | `*Resource.php` | `UserResource` |
|
|
295
|
+
| Pagination | `app/OpenApi/Schemas.php` | `PaginationMeta`, `PaginationLinks` |
|
|
296
|
+
| Parameters | `app/OpenApi/Schemas.php` | `FilterSearch`, `QuerySort` |
|
|
297
|
+
|
|
298
|
+
### Request Schema (on FormRequest class)
|
|
299
|
+
|
|
300
|
+
```php
|
|
301
|
+
// app/Http/Requests/UserStoreRequest.php
|
|
302
|
+
#[OA\Schema(
|
|
303
|
+
schema: 'UserStoreRequest',
|
|
304
|
+
required: ['name', 'email', 'password'],
|
|
305
|
+
properties: [
|
|
306
|
+
new OA\Property(property: 'name', type: 'string', example: '田中'),
|
|
307
|
+
new OA\Property(property: 'email', type: 'string', format: 'email'),
|
|
308
|
+
new OA\Property(property: 'password', type: 'string', minLength: 8),
|
|
309
|
+
]
|
|
310
|
+
)]
|
|
311
|
+
class UserStoreRequest extends FormRequest
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Response Schema (on Resource class)
|
|
315
|
+
|
|
316
|
+
```php
|
|
317
|
+
// app/Http/Resources/UserResource.php
|
|
318
|
+
#[OA\Schema(
|
|
319
|
+
schema: 'User',
|
|
320
|
+
properties: [
|
|
321
|
+
new OA\Property(property: 'id', type: 'integer'),
|
|
322
|
+
new OA\Property(property: 'name', type: 'string'),
|
|
323
|
+
new OA\Property(property: 'email', type: 'string'),
|
|
324
|
+
new OA\Property(property: 'created_at', type: 'string', format: 'date-time'),
|
|
325
|
+
]
|
|
326
|
+
)]
|
|
327
|
+
class UserResource extends JsonResource
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Controller uses refs
|
|
331
|
+
|
|
332
|
+
```php
|
|
333
|
+
#[OA\Post(
|
|
334
|
+
path: '/api/users',
|
|
335
|
+
requestBody: new OA\RequestBody(
|
|
336
|
+
content: new OA\JsonContent(ref: '#/components/schemas/UserStoreRequest')
|
|
337
|
+
),
|
|
338
|
+
responses: [
|
|
339
|
+
new OA\Response(
|
|
340
|
+
response: 201,
|
|
341
|
+
content: new OA\JsonContent(
|
|
342
|
+
properties: [
|
|
343
|
+
new OA\Property(property: 'data', ref: '#/components/schemas/User'),
|
|
344
|
+
]
|
|
345
|
+
)
|
|
346
|
+
),
|
|
347
|
+
]
|
|
348
|
+
)]
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Don't Mix Concepts
|
|
354
|
+
|
|
355
|
+
| Concept | Use For | DON'T Use For |
|
|
356
|
+
| ---------------- | ---------------- | -------------------- |
|
|
357
|
+
| `*StoreRequest` | POST create | GET list, PUT update |
|
|
358
|
+
| `*UpdateRequest` | PUT/PATCH update | POST create |
|
|
359
|
+
| `*Resource` | Response output | Request input |
|
|
360
|
+
| `index()` | List (no body) | Create/Update |
|
|
361
|
+
| `store()` | Create new | Update existing |
|
|
362
|
+
| `update()` | Update existing | Create new |
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Response Status Codes
|
|
367
|
+
|
|
368
|
+
| Action | Success Code | Resource |
|
|
369
|
+
| ------- | -------------- | ---------- |
|
|
370
|
+
| index | 200 OK | Collection |
|
|
371
|
+
| store | 201 Created | Resource |
|
|
372
|
+
| show | 200 OK | Resource |
|
|
373
|
+
| update | 200 OK | Resource |
|
|
374
|
+
| destroy | 204 No Content | null |
|
|
375
|
+
|
|
376
|
+
```php
|
|
377
|
+
// store returns 201 automatically via Resource
|
|
378
|
+
public function store(UserStoreRequest $request): UserResource
|
|
379
|
+
{
|
|
380
|
+
$user = User::create($request->validated());
|
|
381
|
+
|
|
382
|
+
return (new UserResource($user))
|
|
383
|
+
->response()
|
|
384
|
+
->setStatusCode(201); // Explicit 201
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Or simpler (Laravel auto-returns 201 for new resources)
|
|
388
|
+
public function store(UserStoreRequest $request): UserResource
|
|
389
|
+
{
|
|
390
|
+
return new UserResource(User::create($request->validated()));
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// destroy returns 204
|
|
394
|
+
public function destroy(User $user): JsonResponse
|
|
395
|
+
{
|
|
396
|
+
$user->delete();
|
|
397
|
+
return response()->json(null, 204);
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## When to Add Logic to Controller
|
|
404
|
+
|
|
405
|
+
### ✅ OK in Controller
|
|
406
|
+
|
|
407
|
+
```php
|
|
408
|
+
// Simple query building
|
|
409
|
+
$query = User::query();
|
|
410
|
+
if ($request->input('search')) {
|
|
411
|
+
$query->where('name', 'like', '%'.$request->input('search').'%');
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Dispatching events/jobs (one-liners)
|
|
415
|
+
event(new UserRegistered($user));
|
|
416
|
+
SendWelcomeEmail::dispatch($user);
|
|
417
|
+
|
|
418
|
+
// Simple eager loading
|
|
419
|
+
$user->load('orders', 'profile');
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### ❌ Move to Service
|
|
423
|
+
|
|
424
|
+
```php
|
|
425
|
+
// Multi-step business logic
|
|
426
|
+
// - Calculate pricing
|
|
427
|
+
// - Process payment
|
|
428
|
+
// - Create order
|
|
429
|
+
// - Update inventory
|
|
430
|
+
// - Send notifications
|
|
431
|
+
// → Create OrderService
|
|
432
|
+
|
|
433
|
+
// Complex validation beyond FormRequest
|
|
434
|
+
// - Check external API
|
|
435
|
+
// - Validate business rules
|
|
436
|
+
// → Create Service or Action
|
|
437
|
+
|
|
438
|
+
// Reusable across multiple controllers
|
|
439
|
+
// → Create Action class
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Anti-Patterns
|
|
445
|
+
|
|
446
|
+
```php
|
|
447
|
+
// ❌ DON'T: Business logic in controller
|
|
448
|
+
public function store(OrderRequest $request)
|
|
449
|
+
{
|
|
450
|
+
$cart = Cart::find($request->cart_id);
|
|
451
|
+
|
|
452
|
+
// 50 lines of pricing calculation
|
|
453
|
+
// 30 lines of payment processing
|
|
454
|
+
// 20 lines of inventory update
|
|
455
|
+
|
|
456
|
+
return new OrderResource($order);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// ❌ DON'T: Validation in controller
|
|
460
|
+
public function store(Request $request)
|
|
461
|
+
{
|
|
462
|
+
$request->validate([...]); // Use FormRequest instead
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// ❌ DON'T: Manual JSON response
|
|
466
|
+
public function show(User $user)
|
|
467
|
+
{
|
|
468
|
+
return response()->json([
|
|
469
|
+
'id' => $user->id,
|
|
470
|
+
'name' => $user->name,
|
|
471
|
+
]); // Use Resource instead
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// ❌ DON'T: Try-catch for expected exceptions
|
|
475
|
+
public function show(int $id)
|
|
476
|
+
{
|
|
477
|
+
try {
|
|
478
|
+
$user = User::findOrFail($id);
|
|
479
|
+
} catch (ModelNotFoundException $e) {
|
|
480
|
+
return response()->json(['error' => 'Not found'], 404);
|
|
481
|
+
}
|
|
482
|
+
// Laravel handles this automatically with route model binding
|
|
483
|
+
}
|
|
484
|
+
```
|