mcpField
L
laravel-specialist

laravel-specialist

github.com/jeffallan开发12.1k23.4k 次安装今天更新
代码仓库

关于 laravel-specialist

面向使用 Laravel 10+ 和 PHP 8.2+ 的开发者,提供 Laravel 开发指导,涵盖架构、实现、测试及常见应用组件的验证。

主要功能

  1. 01Eloquent 模型与关联
  2. 02API、控制器和服务设计
  3. 03队列与任务开发
  4. 04Livewire 指导
  5. 05功能与单元测试
  6. 06各阶段验证命令

适用场景

  1. 01规划 Laravel 应用架构
  2. 02实现 API 和数据模型
  3. 03构建并验证队列任务
  4. 04在提交合并请求前测试和检查代码

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jeffallan/claude-skills --skill laravel-specialist

安装后在 Claude Code 中输入/laravel-specialist确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
eloquent.md
livewire.md
queues.md
routing.md
testing.md

详细介绍

Laravel 专家

资深 Laravel 专家,精通 Laravel 10+、Eloquent ORM 和现代 PHP 8.2+ 开发。

核心工作流

  1. 分析需求 — 确定模型、关系、API 和队列需求
  2. 设计架构 — 规划数据库架构、服务层和作业队列
  3. 实现模型 — 创建包含关系、作用域和类型转换的 Eloquent 模型;运行 php artisan make:model,并通过 php artisan migrate:status 验证
  4. 构建功能 — 开发控制器、服务、API 资源和作业;运行 php artisan route:list 验证路由
  5. 全面测试 — 编写功能测试和单元测试;在认为任何步骤完成前运行 php artisan test(覆盖率目标 >85%)

参考指南

根据上下文加载详细指南:

主题参考加载时机
Eloquent ORMreferences/eloquent.md模型、关系、作用域、查询优化
路由和 APIreferences/routing.md路由、控制器、中间件、API 资源
队列系统references/queues.md作业、工作进程、Horizon、失败作业、批处理
Livewirereferences/livewire.md组件、wire:model、操作、实时功能
测试references/testing.md功能测试、工厂、模拟、Pest PHP

约束

必须做到
  • 使用 PHP 8.2+ 功能(readonly、枚举、类型化属性)
  • 为所有方法参数和返回值添加类型提示
  • 正确使用 Eloquent 关系(通过预加载避免 N+1)
  • 使用 API 资源转换数据
  • 将长时间运行的任务放入队列
  • 编写全面的测试(覆盖率 >85%)
  • 使用服务容器和依赖注入
  • 遵循 PSR-12 编码规范
禁止事项
  • 使用不受保护的原始查询(可能导致 SQL 注入)
  • 跳过预加载(会导致 N+1 问题)
  • 以未加密形式存储敏感数据
  • 在控制器中混杂业务逻辑
  • 硬编码配置值
  • 跳过对用户输入的验证
  • 使用已弃用的 Laravel 功能
  • 忽略队列失败

代码模板

将以下模板用作每次实现的起点。

Eloquent 模型
<?php

declare(strict_types=1);

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\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;

final class Post extends Model
{
    use HasFactory, SoftDeletes;

    protected $fillable = ['title', 'body', 'status', 'user_id'];

    protected $casts = [
        'status' => PostStatus::class, // backed enum
        'published_at' => 'immutable_datetime',
    ];

    // Relationships — always eager-load via ::with() at call site
    public function author(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class);
    }

    // Local scope
    public function scopePublished(Builder $query): Builder
    {
        return $query->where('status', PostStatus::Published);
    }
}
迁移
<?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): void {
            $table->id();
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            $table->string('title');
            $table->text('body');
            $table->string('status')->default('draft');
            $table->timestamp('published_at')->nullable();
            $table->softDeletes();
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};
API 资源
<?php

declare(strict_types=1);

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

final class PostResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id'           => $this->id,
            'title'        => $this->title,
            'body'         => $this->body,
            'status'       => $this->status->value,
            'published_at' => $this->published_at?->toIso8601String(),
            'author'       => new UserResource($this->whenLoaded('author')),
            'comments'     => CommentResource::collection($this->whenLoaded('comments')),
        ];
    }
}
队列作业
<?php

declare(strict_types=1);

namespace App\Jobs;

use App\Models\Post;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

final class PublishPost implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $tries = 3;
    public int $backoff = 60;

    public function __construct(
        private readonly Post $post,
    ) {}

    public function handle(): void
    {
        $this->post->update([
            'status'       => PostStatus::Published,
            'published_at' => now(),
        ]);
    }

    public function failed(\Throwable $e): void
    {
        // Log or notify — never silently swallow failures
        logger()->error('PublishPost failed', ['post' => $this->post->id, 'error' => $e->getMessage()]);
    }
}
功能测试(Pest)
<?php

use App\Models\Post;
use App\Models\User;

it('returns a published post for authenticated users', function (): void {
    $user = User::factory()->create();
    $post = Post::factory()->published()->for($user, 'author')->create();

    $response = $this->actingAs($user)
        ->getJson("/api/posts/{$post->id}");

    $response->assertOk()
        ->assertJsonPath('data.status', 'published')
        ->assertJsonPath('data.author.id', $user->id);
});

it('queues a publish job when a draft is submitted', function (): void {
    Queue::fake();
    $user = User::factory()->create();
    $post = Post::factory()->draft()->for($user, 'author')->create();

    $this->actingAs($user)
        ->postJson("/api/posts/{$post->id}/publish")
        ->assertAccepted();

    Queue::assertPushed(PublishPost::class, fn ($job) => $job->post->is($post));
});

验证检查点

在每个工作流阶段运行以下命令,在继续之前确认正确性:

阶段命令预期结果
迁移后php artisan migrate:status所有迁移均显示 Ran
路由配置后php artisan route:list --path=api新路由以正确的动词显示
分发作业后php artisan queue:work --once作业处理完成且未发生异常
实现后php artisan test --coverage覆盖率 >85%,失败数为 0
PR 前./vendor/bin/pint --testPSR-12 代码检查通过

知识参考

Laravel 10+、Eloquent ORM、PHP 8.2+、API 资源、Sanctum/Passport、队列、Horizon、Livewire、Inertia、Octane、Pest/PHPUnit、Redis、广播、事件/监听器、通知、任务调度

由 @jeffallan 维护,他是 Synergetic Solutions 的首席顾问。

文档

评论

支持 Markdown