laravel-specialist by jeffallan/claude-skills
npx skills add https://github.com/jeffallan/claude-skills --skill laravel-specialist资深 Laravel 专家,在 Laravel 10+、Eloquent ORM 和现代 PHP 8.2+ 开发方面拥有深厚专业知识。
php artisan make:model 并使用 php artisan migrate:status 验证php artisan route:list 以验证路由php artisan test(目标覆盖率 >85%)根据上下文加载详细指导:
| 主题 | 参考 | 加载时机 |
|---|---|---|
| Eloquent ORM |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
references/eloquent.md |
| 模型、关联关系、作用域、查询优化 |
| 路由与 API | references/routing.md | 路由、控制器、中间件、API 资源 |
| 队列系统 | references/queues.md | 任务、工作进程、Horizon、失败任务、批处理 |
| Livewire | references/livewire.md | 组件、wire:model、操作、实时功能 |
| 测试 | references/testing.md | 功能测试、工厂、模拟、Pest PHP |
将这些作为每次实现的起点。
<?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');
}
};
<?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()]);
}
}
<?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 --test | PSR-12 代码检查通过 |
Laravel 10+、Eloquent ORM、PHP 8.2+、API 资源、Sanctum/Passport、队列、Horizon、Livewire、Inertia、Octane、Pest/PHPUnit、Redis、广播、事件/监听器、通知、任务调度
每周安装量
6.4K
代码仓库
GitHub 星标数
7.2K
首次出现
Jan 21, 2026
安全审计
安装于
opencode4.5K
gemini-cli4.4K
codex4.4K
github-copilot4.4K
kimi-cli4.0K
amp4.0K
Senior Laravel specialist with deep expertise in Laravel 10+, Eloquent ORM, and modern PHP 8.2+ development.
php artisan make:model and verify with php artisan migrate:statusphp artisan route:list to verify routingphp artisan test before considering any step complete (target >85% coverage)Load detailed guidance based on context:
| Topic | Reference | Load When |
|---|---|---|
| Eloquent ORM | references/eloquent.md | Models, relationships, scopes, query optimization |
| Routing & APIs | references/routing.md | Routes, controllers, middleware, API resources |
| Queue System | references/queues.md | Jobs, workers, Horizon, failed jobs, batching |
| Livewire | references/livewire.md | Components, wire:model, actions, real-time |
| Testing | references/testing.md | Feature tests, factories, mocking, Pest PHP |
Use these as starting points for every implementation.
<?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');
}
};
<?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()]);
}
}
<?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));
});
Run these at each workflow stage to confirm correctness before proceeding:
| Stage | Command | Expected Result |
|---|---|---|
| After migration | php artisan migrate:status | All migrations show Ran |
| After routing | php artisan route:list --path=api | New routes appear with correct verbs |
| After job dispatch | php artisan queue:work --once | Job processes without exception |
| After implementation | php artisan test --coverage | >85% coverage, 0 failures |
Laravel 10+, Eloquent ORM, PHP 8.2+, API resources, Sanctum/Passport, queues, Horizon, Livewire, Inertia, Octane, Pest/PHPUnit, Redis, broadcasting, events/listeners, notifications, task scheduling
Weekly Installs
6.4K
Repository
GitHub Stars
7.2K
First Seen
Jan 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode4.5K
gemini-cli4.4K
codex4.4K
github-copilot4.4K
kimi-cli4.0K
amp4.0K
97,600 周安装
| Before PR |
./vendor/bin/pint --test |
| PSR-12 linting passes |