laravel-best-practices by asyrafhussin/agent-skills
npx skills add https://github.com/asyrafhussin/agent-skills --skill laravel-best-practices适用于 Laravel 12 应用程序的全面最佳实践指南。包含 7 个类别下的 29 条规则,用于构建可扩展、可维护的 Laravel 应用程序。
在以下情况下参考这些指南:
| 优先级 | 类别 | 影响 | 前缀 |
|---|---|---|---|
| 1 | 架构与结构 | 关键 | arch- |
| 2 | Eloquent 与数据库 | 关键 | eloquent- |
| 3 | 控制器与路由 | 高 | , |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
controller-ctrl-| 4 | 验证与请求 | 高 | validation-, valid- |
| 5 | 安全 | 高 | sec- |
| 6 | 性能 | 中 | perf- |
| 7 | API 设计 | 中 | api- |
arch-service-classes - 将业务逻辑提取到服务中arch-action-classes - 单一职责的操作类arch-repository-pattern - 何时使用仓库模式arch-dto-pattern - 数据传输对象arch-value-objects - 封装领域概念arch-event-driven - 使用事件和监听器解耦arch-feature-folders - 按领域/功能组织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 - 自动清理旧记录controller-resource-controllers - 使用资源控制器controller-single-action - 单一操作的可调用控制器controller-resource-methods - RESTful 资源方法controller-form-requests - 使用表单请求controller-api-resources - 转换 API 响应controller-middleware - 正确应用中间件controller-dependency-injection - 注入依赖validation-form-requests - 使用表单请求类validation-custom-rules - 创建自定义规则validation-conditional-rules - 条件验证validation-array-validation - 验证嵌套数组validation-after-hooks - 复杂验证逻辑sec-mass-assignment - 防止批量赋值攻击此类别暂无规则文件。
此类别暂无规则文件。
<?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
{
// 验证自动进行
$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();
});
}
}
<?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();
// 为常见查询添加索引
$table->index(['user_id', 'published_at']);
$table->index('category_id');
});
}
public function down(): void
{
Schema::dropIfExists('posts');
}
};
// N+1 问题
$posts = Post::all();
foreach ($posts as $post) {
echo $post->author->name; // 每个帖子都查询一次
}
// 预加载 — 总共只有 3 次查询
$posts = Post::with(['author', 'category', 'tags'])->get();
foreach ($posts as $post) {
echo $post->author->name; // 没有额外的查询
}
// 嵌套预加载
$posts = Post::with([
'author.profile',
'comments.user',
'tags',
])->get();
// 约束预加载
$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
每个规则文件包含:
获取包含所有规则详解的完整指南:AGENTS.md
每周安装数
343
代码仓库
GitHub 星标数
11
首次出现
2026年1月24日
安全审计
安装于
opencode297
codex292
gemini-cli282
github-copilot278
kimi-cli245
amp244
Comprehensive best practices guide for Laravel 12 applications. Contains 29 rules across 7 categories for building scalable, maintainable Laravel applications.
Reference these guidelines when:
| 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- |
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/featureeloquent-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 recordscontroller-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 dependenciesvalidation-form-requests - Use form request classesvalidation-custom-rules - Create custom rulesvalidation-conditional-rules - Conditional validationvalidation-array-validation - Validate nested arraysvalidation-after-hooks - Complex validation logicsec-mass-assignment - Protect against mass assignmentNo rule files exist yet for this category.
No rule files exist yet for this category.
<?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();
});
}
}
<?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();
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:
For the complete guide with all rules expanded: AGENTS.md
Weekly Installs
343
Repository
GitHub Stars
11
First Seen
Jan 24, 2026
Security Audits
Gen Agent Trust HubPassSocketFailSnykPass
Installed on
opencode297
codex292
gemini-cli282
github-copilot278
kimi-cli245
amp244
Laravel Eloquent 最佳实践指南:查询优化、关联关系与性能提升技巧
752 周安装
React前端开发模式实战:组件组合、复合组件与渲染属性模式详解
464 周安装
Mermaid 可视化工具 - 自动生成专业图表,优化文档与演示,兼容 Obsidian/GitHub
465 周安装
OpenAI API 完整指南:GPT-5、GPT-4o、DALL-E 3、Whisper 集成与Node.js/JavaScript开发
465 周安装
客户旅程地图制作指南:5步创建跨职能客户体验地图,提升转化与忠诚度
466 周安装
Next.js 15+ 最佳实践指南:文件约定、RSC边界、异步模式与性能优化
466 周安装
Airflow 2 到 3 迁移指南:代码变更、元数据访问与自动化升级
467 周安装