mcpField
L
laravel-specialist

laravel-specialist

github.com/farmage开发224279 次安装5 周前更新
代码仓库

关于 laravel-specialist

面向 Laravel 和 PHP 工程师的开发技能,适用于使用 Laravel 10+ 与 PHP 8.2+ 构建应用。内容涵盖架构、Eloquent、API、队列,以及通过测试和命令验证实现。

主要功能

  1. 01设计 Laravel 应用架构
  2. 02构建 Eloquent 模型与关联
  3. 03开发 API 和队列任务
  4. 04编写功能与单元测试
  5. 05验证迁移、路由和任务

适用场景

  1. 01实现 API 功能
  2. 02建模数据库关联
  3. 03通过队列处理长时任务
  4. 04在发布前验证改动

安装

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

$npx skills add https://github.com/farmage/opencode-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新路由以正确的 HTTP 方法显示
分发作业后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、广播、事件/监听器、通知、任务调度

文档

评论

支持 Markdown