关于 laravel-best-practices
面向 Laravel 13 应用开发者的实践指南,涵盖架构、Eloquent、控制器、验证和安全,并在规则文件中提供示例。
主要功能
- 01架构与结构指南
- 02Eloquent 和数据库实践
- 03控制器与路由模式
- 04验证与请求规则
- 05批量赋值安全指南
适用场景
- 01规划 Laravel 应用结构
- 02减少 N+1 数据库查询
- 03实现表单请求验证
- 04防范模型批量赋值风险
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ asyrafhussin/ agent-skills --skill laravel-best-practices安装后在 Claude Code 中输入/laravel-best-practices确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
AGENTS.mdmetadata.jsonREADME.mdrules/_sections.md_template.mdarch-action-classes.mdarch-dto-pattern.mdarch-event-driven.mdarch-feature-folders.mdarch-queue-routing.mdarch-repository-pattern.mdarch-service-classes.mdarch-value-objects.mdcontroller-api-resources.mdcontroller-dependency-injection.mdcontroller-form-requests.mdcontroller-middleware.mdcontroller-resource-controllers.mdcontroller-resource-methods.mdcontroller-single-action.mdeloquent-accessors-mutators.mdeloquent-casts.mdeloquent-chunking.mdeloquent-eager-loading.mdeloquent-model-events.mdeloquent-pruning.mdeloquent-query-scopes.mdeloquent-relationships.mdeloquent-soft-deletes.mdeloquent-vector-search.md详细介绍
Laravel 13 最佳实践
Laravel 13 应用的全面最佳实践指南。包含 7 个类别中的 31 条规则,助你构建可扩展、易维护的 Laravel 应用。
适用场景
在以下场景中参考这些指南:
- 创建控制器、模型和服务
- 编写迁移和数据库查询
- 实施验证和表单请求
- 使用 Laravel 构建 API
- 规划 Laravel 应用结构
按优先级排列的规则类别
| 优先级 | 类别 | 影响 | 前缀 |
|---|---|---|---|
| 1 | 架构与结构 | 严重 | arch- |
| 2 | Eloquent 与数据库 | 严重 | eloquent- |
| 3 | 控制器与路由 | 高 | controller-、ctrl- |
| 4 | 验证与请求 | 高 | validation-、valid- |
| 5 | 安全 | 高 | sec- |
| 6 | 性能 | 中 | perf- |
| 7 | API 设计 | 中 | api- |
快速参考
1. 架构与结构(严重)
arch-service-classes- 将业务逻辑提取到服务中arch-action-classes- 单一用途的操作类arch-repository-pattern- 何时使用仓储arch-dto-pattern- 数据传输对象arch-value-objects- 封装领域概念arch-event-driven- 使用事件和监听器实现解耦arch-feature-folders- 按领域/功能组织arch-queue-routing- 集中式作业队列路由(Laravel 13+)
2. Eloquent 与数据库(严重)
eloquent-eager-loading- 防止 N+1 查询eloquent-chunking- 处理大型数据集eloquent-query-scopes- 可复用的查询逻辑eloquent-model-events- 使用观察者处理副作用eloquent-relationships- 正确地定义关系eloquent-casts- 自动转换属性类型eloquent-accessors-mutators- 转换属性eloquent-soft-deletes- 安全删除并支持恢复eloquent-pruning- 自动清理旧记录eloquent-vector-search- 使用 pgvector 进行语义搜索(Laravel 13+)
3. 控制器与路由(高)
controller-resource-controllers- 使用资源控制器controller-single-action- 单操作可调用控制器controller-resource-methods- RESTful 资源方法controller-form-requests- 使用表单请求controller-api-resources- 转换 API 响应controller-middleware- 正确应用中间件controller-dependency-injection- 注入依赖项
4. 验证与请求(高)
validation-form-requests- 使用表单请求类validation-custom-rules- 创建自定义规则validation-conditional-rules- 条件验证validation-array-validation- 验证嵌套数组validation-after-hooks- 复杂验证逻辑
5. 安全(高)
sec-mass-assignment- 防止批量赋值
6. 性能(中)
此类别目前尚无规则文件。
7. API 设计(中)
此类别目前尚无规则文件。
基本模式
带表单请求的控制器
<?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.');
}
}
表单请求类
<?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.',
];
}
}
服务类模式
<?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 模型
<?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),
);
}
}
迁移最佳实践
<?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');
}
};
预加载
// N+1 Problem
$posts = Post::all();
foreach ($posts as $post) {
echo $post->author->name; // Query per post
}
// Eager loading — only 3 queries total
$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();
使用方法
阅读各条规则文件,了解详细说明和代码示例:
rules/arch-service-classes.md
rules/eloquent-eager-loading.md
rules/validation-form-requests.md
rules/_sections.md
每个规则文件都包含:
- 带元数据(标题、影响、标签)的 YAML frontmatter
- 简要说明该规则的重要性
- 错误示例及说明
- 正确示例及说明
- Laravel 13 和 PHP 8.3 的特定背景与参考资料
完整汇编文档
查看包含所有规则完整内容的指南:AGENTS.md
评论
支持 Markdown