Repository navigation
Expand file tree
/
Copy pathlaravel-php.mdc
More file actions
197 lines (149 loc) · 10 KB
/
Copy pathlaravel-php.mdc
File metadata and controls
197 lines (149 loc) · 10 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
---
description: Laravel best practices — strict types, Form Requests, API Resources, no dd() in prod.
globs: ""
alwaysApply: true
---
## PHP Declarations and Strict Types
- Every PHP file must start with `<?php` followed immediately by `declare(strict_types=1);` on line 2
- No exceptions for service files, controllers, models, or migrations
- Verify with: first two lines are `<?php` and `declare(strict_types=1);`
## Eloquent Model Requirements
- All database queries must use Eloquent methods, never raw SQL queries
- Forbidden: `DB::raw()`, `DB::select()`, `DB::statement()` in application code
- Use `Model::where()`, `Model::join()`, `Model::with()` instead
- Raw queries only allowed in database seeders and migrations
- Verify: search codebase for `DB::` outside `database/seeders/` and `database/migrations/`
## Model File Naming and Location
- Models live in `app/Models/` directory only
- File name must match class name exactly: `User.php` contains `class User`
- Model class names are singular: `User`, `Post`, `Comment` — never `Users` or `Posts`
- Verify: `ls app/Models/*.php | grep -v "^[A-Z]"` returns nothing
## Strict Type Hints on All Methods
- Every method parameter must have a type hint: `public function store(string $name, int $id): void`
- Return types are mandatory on all methods: `public function getName(): string`
- No `mixed` type hints — use specific types or union types: `string|int`, never `mixed`
- Nullable types must be explicit: `?string $email` not `string|null $email`
- Verify: grep for `function.*(\$` without type hints — should return zero results
## Form Request Validation Classes
- All input validation must live in `app/Http/Requests/` directory
- One Form Request class per controller action: `StoreUserRequest`, `UpdatePostRequest`
- Validation rules defined in `rules()` method, never in controller
- Authorization logic in `authorize()` method, never in controller
- Forbidden: validation logic in controller methods
- Verify: controller methods contain zero `$request->validate()` calls
## Controller Method Signatures
- Controllers live in `app/Http/Controllers/` directory
- Controller class names end with `Controller`: `UserController`, `PostController`
- One action per method: `store()`, `update()`, `destroy()`, `show()`
- Method parameters must type-hint Form Request: `public function store(StoreUserRequest $request): JsonResponse`
- Never accept `Request $request` — always use specific Form Request class
- Verify: grep for `function.*Request \$request` — all matches should be specific Form Request classes
## API Resource Classes
- All API responses must use Resource classes from `app/Http/Resources/`
- Resource class names match model: `UserResource`, `PostResource`
- Collections use `::collection()`: `return UserResource::collection($users)`
- Single resources: `return new UserResource($user)`
- Forbidden: returning raw arrays or models in API responses
- Verify: no `return $model;` or `return $models->toArray();` in controller methods
## Service Layer Organization
- Business logic lives in `app/Services/` directory
- Service class names end with `Service`: `UserService`, `PaymentService`
- Services are injected into controllers via constructor: `public function __construct(UserService $service)`
- Never instantiate services with `new`: use dependency injection
- Verify: grep for `new.*Service` in controllers — should return zero results
## Repository Pattern (if used)
- Repository interfaces in `app/Repositories/Contracts/`
- Repository implementations in `app/Repositories/`
- Bind in `AppServiceProvider`: `$this->app->bind(UserRepositoryContract::class, UserRepository::class)`
- Never use repositories and Eloquent models interchangeably in same codebase
- Verify: either all queries use repositories OR all use Eloquent — never mixed
## Error Handling and Exceptions
- Custom exceptions in `app/Exceptions/` directory
- All exceptions must extend `Exception` or `RuntimeException`
- HTTP exceptions use Laravel's `HttpException` with status code: `throw new HttpException(404, 'User not found')`
- Catch exceptions with specific types: `catch (ModelNotFoundException $e)` never `catch (Exception $e)`
- Forbidden: `dd()`, `dump()`, `var_dump()` in any non-test file
- Verify: grep for `dd\(|dump\(|var_dump\(` outside `tests/` — should return zero results
## Logging Requirements
- Use `Log::channel('stack')->error()` for errors, never `echo` or `print`
- Log format: `Log::error('User creation failed', ['user_id' => $id, 'error' => $e->getMessage()])`
- Forbidden: logging sensitive data (passwords, tokens, SSNs)
- All exceptions must be logged before throwing to user
- Verify: grep for `echo |print ` in `app/` directory — should return zero results
## Environment Variables and Secrets
- All configuration in `config/` directory, never hardcoded in code
- Access via `config('app.key')` or `env('APP_KEY')` in config files only
- Forbidden: `env()` calls in application code outside `config/`
- `.env` file never committed to version control
- Verify: `.env` in `.gitignore` and no hardcoded API keys in `app/`
## Database Migrations
- Migrations in `database/migrations/` with timestamp prefix: `2024_01_15_120000_create_users_table.php`
- Use `Schema::create()` for new tables, `Schema::table()` for modifications
- All columns must have `nullable()` or `default()` or be required
- Foreign keys use `constrained()`: `$table->foreignId('user_id')->constrained()`
- Forbidden: raw SQL in migrations — use Schema builder only
- Verify: grep for `DB::statement` in migrations — should return zero results
## Model Relationships
- Relationships defined as methods in Model class: `public function posts(): HasMany`
- Return type must match relationship: `HasMany`, `BelongsTo`, `ManyToMany`
- Relationship methods are lowercase, plural for collections: `posts()`, `comments()`
- Relationship methods are lowercase, singular for single model: `user()`, `author()`
- Eager load relationships in queries: `User::with('posts')->get()` never `User::all()` then access `$user->posts`
- Verify: no `$model->relation` access without prior `with()` in query
## Casting and Accessors
- Use `$casts` property for type casting: `protected $casts = ['email_verified_at' => 'datetime'];`
- Forbidden: manual casting in accessors or mutators
- Accessors use `#[Attribute]` decorator: `#[Attribute] public function fullName(): Attribute`
- Never use `getAttribute()` or `setAttribute()` directly
- Verify: grep for `getAttribute|setAttribute` in models — should return zero results
## Testing File Structure
- Unit tests in `tests/Unit/` with matching path to `app/`: `tests/Unit/Services/UserService.php`
- Feature tests in `tests/Feature/` for HTTP endpoints: `tests/Feature/Http/Controllers/UserControllerTest.php`
- Test class names end with `Test`: `UserServiceTest`, `UserControllerTest`
- Test methods start with `test_`: `test_user_can_be_created()`
- Verify: all test files match `tests/{Unit|Feature}/**/*Test.php` pattern
## Test Assertions and Mocking
- Use `$this->assertDatabaseHas()` for database assertions: `$this->assertDatabaseHas('users', ['email' => 'test@example.com'])`
- Mock services in tests: `$this->mock(UserService::class, function ($mock) { $mock->shouldReceive('create')->andReturn($user); })`
- Never test with real database queries in unit tests — use mocks
- Feature tests use `RefreshDatabase` trait: `use RefreshDatabase;`
- Verify: unit tests contain zero `Model::create()` calls
## Naming Conventions for Variables and Functions
- Variable names are camelCase: `$userName`, `$userEmail` — never `$user_name`
- Function names are camelCase: `getUserById()`, `createNewUser()` — never `get_user_by_id()`
- Boolean variables/methods start with `is`, `has`, `can`: `$isActive`, `hasPermission()`, `canDelete()`
- Constants are UPPER_SNAKE_CASE: `const MAX_RETRIES = 3;`
- Verify: grep for `\$[a-z]+_[a-z]` in `app/` — should return zero results
## Array and Collection Handling
- Use Laravel Collections: `collect($array)->map()->filter()->toArray()`
- Forbidden: raw PHP array functions like `array_map()`, `array_filter()` in application code
- Collection methods are chainable: `$users->where('active', true)->pluck('email')->unique()`
- Verify: grep for `array_map|array_filter|array_reduce` in `app/` — should return zero results
## Middleware Organization
- Middleware in `app/Http/Middleware/` directory
- Middleware class names end with `Middleware`: `AuthMiddleware`, `RateLimitMiddleware`
- Register in `app/Http/Kernel.php` in appropriate group: `$routeMiddleware` or `$middleware`
- Forbidden: business logic in middleware — only request/response handling
- Verify: middleware files contain zero service instantiation or database queries
## Route Organization
- Routes in `routes/` directory: `routes/api.php`, `routes/web.php`
- API routes use `Route::apiResource()`: `Route::apiResource('users', UserController::class)`
- Route names use dot notation: `users.store`, `users.update`, `posts.show`
- Forbidden: inline closures in routes — always use controller methods
- Verify: grep for `Route::.*function\(` in routes — should return zero results
## Query Optimization
- Always use `select()` to limit columns: `User::select('id', 'name', 'email')->get()`
- Forbidden: `User::all()` without column selection
- Use `paginate()` for large datasets: `User::paginate(15)` never `User::get()`
- Eager load all relationships: `User::with('posts', 'comments')->get()` never lazy load
- Verify: grep for `Model::all\(\)` in controllers — should return zero results
## Configuration Files
- Configuration in `config/` directory with descriptive names: `config/payment.php`, `config/email.php`
- Return associative arrays from config files
- Access via `config('payment.stripe_key')` not `config('payment')['stripe_key']`
- Forbidden: logic or conditionals in config files
- Verify: config files contain only `return [...]` statements
---
> Source: [Codelibrium](https://codelibrium.com) — the marketplace for AI behaviour files.
> Browse multiple rulesets at [codelibrium.com](https://codelibrium.com) or install via CLI:
> `npx codelibrium-cli install <ruleset-name>`