Manage Apple Reminders via the `remindctl` CLI on macOS (list, add, edit, complete, delete)....
npx skills add AsyrafHussin/agent-skills --skill "laravel-best-practices"
Install specific skill from multi-skill repository
# Description
Laravel 12 conventions and best practices. Use when creating controllers, models, migrations, validation, services, or structuring Laravel applications. Triggers on tasks involving Laravel architecture, Eloquent, database, API development, or PHP patterns.
# SKILL.md
name: laravel-best-practices
description: Laravel 12 conventions and best practices. Use when creating controllers, models, migrations, validation, services, or structuring Laravel applications. Triggers on tasks involving Laravel architecture, Eloquent, database, API development, or PHP patterns.
license: MIT
metadata:
author: Laravel Community
version: "1.0.0"
laravelVersion: "12.x"
phpVersion: "8.5+"
Laravel 12 Best Practices
Comprehensive best practices guide for Laravel 12 applications. Contains 45+ rules across 8 categories for building scalable, maintainable Laravel applications.
When to Apply
Reference these guidelines when:
- Creating controllers, models, and services
- Writing migrations and database queries
- Implementing validation and form requests
- Building APIs with Laravel
- Structuring Laravel applications
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Architecture & Structure | CRITICAL | arch- |
| 2 | Eloquent & Database | CRITICAL | eloquent- |
| 3 | Controllers & Routing | HIGH | controller-, ctrl- |
| 4 | Validation & Requests | HIGH | validation-, valid- |
| 5 | Security | HIGH | sec- |
| 6 | Performance | MEDIUM | perf- |
| 7 | API Design | MEDIUM | api- |
Quick Reference
1. Architecture & Structure (CRITICAL)
arch-service-classes- Extract business logic to servicesarch-action-classes- Single-purpose action classesarch-repository-pattern- When to use repositoriesarch-dto-pattern- Data transfer objectsarch-value-objects- Encapsulate domain conceptsarch-event-driven- Decouple with events and listenersarch-feature-folders- Organize by domain/feature
2. Eloquent & Database (CRITICAL)
eloquent-eager-loading- Prevent N+1 querieseloquent-chunking- Process large datasetseloquent-query-scopes- Reusable query logiceloquent-model-events- Use observers for side effectseloquent-relationships- Define relationships properlyeloquent-casts- Automatic attribute castingeloquent-accessors-mutators- Transform attributeseloquent-soft-deletes- Safe deletion with recoveryeloquent-pruning- Automatic cleanup of old records
3. Controllers & Routing (HIGH)
ctrl-resource-controllers- Use resource controllerscontroller-single-action- Single action invokable controllerscontroller-resource-methods- RESTful resource methodscontroller-form-requests- Use form requestscontroller-api-resources- Transform API responsescontroller-middleware- Apply middleware properlycontroller-dependency-injection- Inject dependencies
4. Validation & Requests (HIGH)
validation-form-requests- Use form request classesvalidation-custom-rules- Create custom rulesvalidation-conditional-rules- Conditional validationvalidation-array-validation- Validate nested arraysvalidation-after-hooks- Complex validation logic
5. Security (HIGH)
sec-mass-assignment- Protect against mass assignment- Additional security rules can be added as needed
6. Performance (MEDIUM)
- Performance rules can be added for caching, queues, and optimization
7. API Design (MEDIUM)
- API design rules can be added for versioning and response formatting
Essential Patterns
Controller with Form Request
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StorePostRequest;
use App\Http\Requests\UpdatePostRequest;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
class PostController extends Controller
{
public function store(StorePostRequest $request): RedirectResponse
{
// Validation happens automatically
$validated = $request->validated();
$post = Post::create($validated);
return redirect()
->route('posts.show', $post)
->with('success', 'Post created successfully.');
}
public function update(UpdatePostRequest $request, Post $post): RedirectResponse
{
$post->update($request->validated());
return redirect()
->route('posts.show', $post)
->with('success', 'Post updated successfully.');
}
}
Form Request Class
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StorePostRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()->can('create', Post::class);
}
public function rules(): array
{
return [
'title' => ['required', 'string', 'max:255'],
'body' => ['required', 'string', 'min:100'],
'category_id' => ['required', 'exists:categories,id'],
'tags' => ['nullable', 'array'],
'tags.*' => ['exists:tags,id'],
'published_at' => ['nullable', 'date', 'after:now'],
];
}
public function messages(): array
{
return [
'body.min' => 'The post body must be at least 100 characters.',
];
}
}
Service Class Pattern
<?php
namespace App\Services;
use App\Models\User;
use App\Models\Post;
use App\Events\PostPublished;
use Illuminate\Support\Facades\DB;
class PostService
{
public function __construct(
private readonly NotificationService $notifications,
) {}
public function publish(Post $post): Post
{
return DB::transaction(function () use ($post) {
$post->update([
'published_at' => now(),
'status' => 'published',
]);
event(new PostPublished($post));
$this->notifications->notifyFollowers($post->author, $post);
return $post->fresh();
});
}
}
Eloquent Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Builder;
class Post extends Model
{
use HasFactory;
protected $fillable = [
'title',
'slug',
'body',
'category_id',
'published_at',
];
protected $casts = [
'published_at' => 'datetime',
];
// Relationships
public function author(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id');
}
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class)->withTimestamps();
}
// Scopes
public function scopePublished(Builder $query): Builder
{
return $query->whereNotNull('published_at')
->where('published_at', '<=', now());
}
public function scopeByCategory(Builder $query, int $categoryId): Builder
{
return $query->where('category_id', $categoryId);
}
// Accessors & Mutators
protected function title(): Attribute
{
return Attribute::make(
set: fn (string $value) => ucfirst($value),
);
}
}
Migration Best Practices
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->foreignId('category_id')->constrained()->cascadeOnDelete();
$table->string('title');
$table->string('slug')->unique();
$table->text('body');
$table->timestamp('published_at')->nullable();
$table->timestamps();
// Indexes for common queries
$table->index(['user_id', 'published_at']);
$table->index('category_id');
});
}
public function down(): void
{
Schema::dropIfExists('posts');
}
};
Eager Loading
// β N+1 Problem
$posts = Post::all();
foreach ($posts as $post) {
echo $post->author->name; // Query per post
}
// β
Eager loading
$posts = Post::with(['author', 'category', 'tags'])->get();
foreach ($posts as $post) {
echo $post->author->name; // No additional queries
}
// β
Nested eager loading
$posts = Post::with([
'author.profile',
'comments.user',
'tags',
])->get();
// β
Constrained eager loading
$posts = Post::with([
'comments' => fn ($query) => $query->latest()->limit(5),
])->get();
How to Use
Read individual rule files for detailed explanations and code examples:
rules/arch-service-classes.md
rules/eloquent-eager-loading.md
rules/validation-form-requests.md
rules/_sections.md
Each rule file contains:
- YAML frontmatter with metadata (title, impact, tags)
- Brief explanation of why it matters
- Incorrect code example with explanation
- Correct code example with explanation
- Laravel 12 and PHP 8.5 specific context and references
Full Compiled Document
For the complete guide with all rules expanded: AGENTS.md
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.