laravel-conventions
Skill1 starsChanged 5 months agoMITView on GitHub
Modern Laravel 11+ / PHP 8.3+ coding standards reference. Use when writing or reviewing PHP/Laravel code to ensure convention compliance.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- techmefr/mentistheir own version, first seen Sep 11, 2026
- wakqasahmed/skillstheir own version, first seen Aug 12, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- wakqasahmed/skills★ 2same name
- techmefr/mentis★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository30 other files it gives its agents.
- .codex/AGENTS.mdAGENTS.md
- compound-engineeringSkill
- compound-engineeringSkill
- agent-browserSkill
- agent-native-architectureSkill
- agent-native-auditSkill
- brainstormingSkill
- cavemanSkill
- compound-docsSkill
- compound-engineeringSkill
- compounding-operating-systemSkill
- compound-refreshSkill
- create-agent-skillsSkill
- document-reviewSkill
- file-todosSkill
- finishing-branchSkill
- frontend-designSkill
- gemini-imagegenSkill
- git-worktreeSkill
- grill-meSkill
- ideateSkill
- i-have-adhdSkill
- orchestrating-swarmsSkill
- rcloneSkill
- resolve-pr-parallelSkill
- setupSkill
- skill-creatorSkill
- systematic-debuggingSkill
- ubiquitous-languageSkill
- xml-tag-structureSkill
The file
We split this skill into the rules it gives an agent
10 rules. About 0 are common, 5 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 171
Always include down() method for rollbacks
- Distinctive: line 172
Never modify migrations that have been run in production
- Very specific: line 173
Use foreignId() and constrained() for foreign keys
- Very specific: line 174
Use after() to control column order
- Distinctive: line 282
Use Laravel Sanctum or Passport for API authentication
- Distinctive: line 283
Always validate with FormRequest classes
- Distinctive: line 284
Use Policies for authorization (not Gates in controllers)
- Distinctive: line 285
Never expose internal IDs if security-sensitive -- use UUIDs or hashids
- Very specific: line 286
Use $request->validated() to only access validated data
- Very specific: line 288
Use encrypt()/decrypt() for sensitive data at rest
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Laravel Coding Conventions (Laravel 11+ / PHP 8.3+)
Reference skill for modern Laravel coding standards and PHP 8.3+ best practices.
Architecture Pattern
Controller -> FormRequest -> Action/Service -> Model- Controllers: Thin, single-responsibility. Invoke actions or services, return API resources
- Actions: Single-purpose classes for discrete operations (e.g.,
CreateUser,ProcessPayment) - Services: Coordinate multiple actions or complex business logic
- Models: Eloquent models with relationships, scopes, casts, and accessors/mutators
- DTOs: Readonly data transfer objects for passing structured data between layers
PHP 8.3+ Features to Use
declare(strict_types=1);
// Readonly classes for DTOs
readonly class CreateUserData {
public function __construct(
public string $name,
public string $email,
public ?string $phone = null,
) {}
}
// Enums instead of constants
enum UserStatus: string {
case Active = 'active';
case Suspended = 'suspended';
case Pending = 'pending';
}
// First-class callable syntax
$users->map($this->transformUser(...));
// Named arguments for clarity
Cache::put(key: $cacheKey, value: $data, ttl: 3600);
// Match expressions over switch
$label = match($status) {
UserStatus::Active => 'Active User',
UserStatus::Suspended => 'Account Suspended',
default => 'Unknown',
};Naming Conventions
| Type | Convention | Example |
| Classes | PascalCase | UserService |
| Methods | camelCase | getUserById |
| Properties/Variables | camelCase | $userData |
| Constants | UPPER_SNAKE_CASE | MAX_RETRIES |
| Database tables | plural, snake_case | user_accounts |
| Database columns | snake_case | created_at |
| Routes | kebab-case | /user-profiles |
| Config keys | snake_case | cache.default_ttl |
| Enums | PascalCase | UserStatus::Active |
Code Style
- PSR-12 compliance, enforced via Laravel Pint
declare(strict_types=1)at the top of every PHP file- Single quotes for strings (unless interpolation needed)
- Short array syntax
[]with trailing commas - Type declarations on all parameters, return types, and properties
- No
mixedtype unless absolutely necessary - Constructor property promotion where appropriate
Directory Structure (Laravel 11+)
app/
├── Actions/ # Single-purpose action classes
├── Console/Commands/ # Artisan commands
├── DTOs/ # Readonly data transfer objects
├── Enums/ # PHP 8.1+ backed enums
├── Events/ # Event classes
├── Exceptions/ # Custom exceptions
├── Http/
│ ├── Controllers/ # API/Web controllers
│ ├── Middleware/ # Request middleware
│ ├── Requests/ # FormRequest validation
│ └── Resources/ # API Resources (JSON transformations)
├── Jobs/ # Queued jobs
├── Listeners/ # Event listeners
├── Mail/ # Mailable classes
├── Models/ # Eloquent models
│ └── Concerns/ # Model traits
├── Notifications/ # Notification classes
├── Observers/ # Model observers
├── Policies/ # Authorization policies
├── Providers/ # Service providers
├── Rules/ # Custom validation rules
└── Services/ # Business logic services
database/
├── factories/ # Model factories
├── migrations/ # Database migrations
└── seeders/ # Database seeders
routes/
├── api.php # API routes
├── web.php # Web routes
└── console.php # Console routes (Laravel 11+)
tests/
├── Feature/ # Feature/integration tests
├── Unit/ # Unit tests
└── Pest.php # Pest configurationEloquent Best Practices
// Use $casts property (not method unless dynamic)
protected $casts = [
'email_verified_at' => 'datetime',
'status' => UserStatus::class,
'settings' => 'array',
'is_admin' => 'boolean',
];
// Scope queries for reuse
public function scopeActive(Builder $query): Builder
{
return $query->where('status', UserStatus::Active);
}
// Prevent lazy loading in development
// In AppServiceProvider::boot()
Model::preventLazyLoading(! app()->isProduction());
// Use strict mode
Model::shouldBeStrict(! app()->isProduction());
// Eager load relationships
User::with(['posts', 'profile'])->get();
// Use whenLoaded in API Resources
'posts' => PostResource::collection($this->whenLoaded('posts')),Database Migrations
Naming Convention
YYYY_MM_DD_HHMMSS_description.phpBest Practices
- One concern per migration file
- Always include
down()method for rollbacks - Never modify migrations that have been run in production
- Use
foreignId()andconstrained()for foreign keys - Use
after()to control column order
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('title');
$table->string('slug')->unique();
$table->text('body');
$table->enum('status', ['draft', 'published', 'archived'])->default('draft');
$table->timestamp('published_at')->nullable();
$table->timestamps();
$table->softDeletes();
$table->index(['status', 'published_at']);
});API Resources
// Always use API Resources for JSON responses
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'posts' => PostResource::collection($this->whenLoaded('posts')),
'created_at' => $this->created_at->toISOString(),
];
}
}
// In controller
return UserResource::make($user);
return UserResource::collection($users);Queues and Jobs
// Implement ShouldQueue for async processing
class ProcessPayment implements ShouldQueue
{
use Queueable;
public int $tries = 3;
public int $backoff = 60;
public int $timeout = 120;
public function __construct(
private readonly Order $order,
) {}
public function handle(PaymentGateway $gateway): void
{
$gateway->charge($this->order);
}
public function failed(\Throwable $exception): void
{
// Notify team of failure
}
}Events and Listeners
// Use typed events
class OrderPlaced
{
public function __construct(
public readonly Order $order,
) {}
}
// Auto-discovered listeners (Laravel 11+)
// Just type-hint the event in handle()
class SendOrderConfirmation
{
public function handle(OrderPlaced $event): void
{
$event->order->user->notify(new OrderConfirmationNotification($event->order));
}
}Routes
// Use controller class references
Route::apiResource('users', UserController::class);
// Group related routes
Route::prefix('admin')->middleware('auth:sanctum', 'admin')->group(function () {
Route::apiResource('users', Admin\UserController::class);
});
// Single-action controllers
Route::post('/webhooks/stripe', StripeWebhookController::class);Security
- Use Laravel Sanctum or Passport for API authentication
- Always validate with FormRequest classes
- Use Policies for authorization (not Gates in controllers)
- Never expose internal IDs if security-sensitive -- use UUIDs or hashids
- Use
$request->validated()to only access validated data - Set rate limiting on API routes
- Use
encrypt()/decrypt()for sensitive data at rest
Error Handling
// Custom exceptions with render method
class InsufficientFundsException extends Exception
{
public function render(Request $request): JsonResponse
{
return response()->json([
'message' => 'Insufficient funds for this transaction.',
], 422);
}
}
// Use abort helpers
abort_if(! $user->canAccess($resource), 403);
abort_unless($order->isPending(), 422, 'Order is no longer pending.');Testing with Pest
// Feature test
it('creates a user', function () {
$response = postJson('/api/users', [
'name' => 'Jane Doe',
'email' => 'jane@example.com',
'password' => 'secure-password',
]);
$response->assertCreated()
->assertJsonPath('data.name', 'Jane Doe');
$this->assertDatabaseHas('users', ['email' => 'jane@example.com']);
});
// Unit test with mocking
it('calculates order total with tax', function () {
$order = Order::factory()->create(['subtotal' => 10000]);
expect($order->totalWithTax())->toBe(10800);
});
// Use datasets for parameterized tests
it('validates required fields', function (string $field) {
$data = User::factory()->make()->toArray();
unset($data[$field]);
postJson('/api/users', $data)->assertUnprocessable()
->assertJsonValidationErrors($field);
})->with(['name', 'email', 'password']);Running Tests
# All tests
php artisan test
# With Pest directly
./vendor/bin/pest
# Specific test file
./vendor/bin/pest tests/Feature/UserTest.php
# Filter by name
./vendor/bin/pest --filter "creates a user"
# Parallel execution
php artisan test --parallelRunning Linter
./vendor/bin/pint
# Check only (no changes)
./vendor/bin/pint --test
# Static analysis
./vendor/bin/phpstan analyseDoes it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

