affaan-m/everything-claude-code/laravel-patterns

Claude Code and agent skill by affaan-m/everything-claude-code

Trust tier 3
  • community
  • ext:[{"type":"config","description":"Configuration overrides"}]
Source check pending

Checking that the SKILL.md file is still in the repository.

Laravel architecture patterns, routing/controllers, Eloquent ORM, service layers, queues, events, caching, and API resources for production apps. Use when building or reviewing Laravel apps — controllers, Eloquent, service layers, queues, or API resources.

Install

npx vskill@latest install affaan-m/everything-claude-code/laravel-patterns

Semi-extensibleMentions customization, but needs skill-specific knowledge. Read the extensible skills standard

SKILL.md

Laravel Development Patterns

Production-grade Laravel architecture patterns for scalable, maintainable applications.

When to Use

  • Building Laravel web applications or APIs
  • Structuring controllers, services, and domain logic
  • Working with Eloquent models and relationships
  • Designing APIs with resources and pagination
  • Adding queues, events, caching, and background jobs

How It Works

  • Structure the app around clear boundaries (controllers -> services/actions -> models).
  • Use explicit bindings and scoped bindings to keep routing predictable; still enforce authorization for access control.
  • Favor typed models, casts, and scopes to keep domain logic consistent.
  • Keep IO-heavy work in queues and cache expensive reads.
  • Centralize config in config/* and keep environments explicit.

Examples

Project Structure

Use a conventional Laravel layout with clear layer boundaries (HTTP, services/actions, models).

Recommended Layout
app/
├── Actions/ # Single-purpose use cases
├── Console/
├── Events/
├── Exceptions/
├── Http/
│ ├── Controllers/
│ ├── Middleware/
│ ├── Requests/ # Form request validation
│ └── Resources/ # API resources
├── Jobs/
├── Models/
├── Policies/
├── Providers/
├── Services/ # Coordinating domain services
└── Support/
config/
database/
├── factories/
├── migrations/
└── seeders/
resources/
├── views/
└── lang/
routes/
├── api.php
├── web.php
└── console.php
Controllers -> Services -> Actions

Keep controllers thin. Put orchestration in services and single-purpose logic in actions.

php
final class CreateOrderAction
{
public function __construct(private OrderRepository $orders) {}
public function handle(CreateOrderData $data): Order
{
return $this->orders->create($data);
}
}
final class OrdersController extends Controller
{
public function __construct(private CreateOrderAction $createOrder) {}
public function store(StoreOrderRequest $request): JsonResponse
{
$order = $this->createOrder->handle($request->toDto());
return response()->json([
'success' => true,
'data' => OrderResource::make($order),
'error' => null,
'meta' => null,
], 201);
}
}
Routing and Controllers

Prefer route-model binding and resource controllers for clarity.

php
use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->group(function () {
Route::apiResource('projects', ProjectController::class);
});
Route Model Binding (Scoped)

Use scoped bindings to prevent cross-tenant access.

php
Route::scopeBindings()->group(function () {
Route::get('/accounts/{account}/projects/{project}', [ProjectController::class, 'show']);
});
Nested Routes and Binding Names
  • Keep prefixes and paths consistent to avoid double nesting (e.g., conversation vs conversations).
  • Use a single parameter name that matches the bound model (e.g., {conversation} for Conversation).
  • Prefer scoped bindings when nesting to enforce parent-child relationships.
php
use App\Http\Controllers\Api\ConversationController;
use App\Http\Controllers\Api\MessageController;
use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->prefix('conversations')->group(function () {
Route::post('/', [ConversationController::class, 'store'])->name('conversations.store');
Route::scopeBindings()->group(function () {
Route::get('/{conversation}', [ConversationController::class, 'show'])
->name('conversations.show');
Route::post('/{conversation}/messages', [MessageController::class, 'store'])
->name('conversation-messages.store');
Route::get('/{conversation}/messages/{message}', [MessageController::class, 'show'])
->name('conversation-messages.show');
});
});

If you want a parameter to resolve to a different model class, define explicit binding. For custom binding logic, use Route::bind() or implement resolveRouteBinding() on the model.

php
use App\Models\AiConversation;
use Illuminate\Support\Facades\Route;
Route::model('conversation', AiConversation::class);
Service Container Bindings

Bind interfaces to implementations in a service provider for clear dependency wiring.

php
use App\Repositories\EloquentOrderRepository;
use App\Repositories\OrderRepository;
use Illuminate\Support\ServiceProvider;
final class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->bind(OrderRepository::class, EloquentOrderRepository::class);
}
}
Eloquent Model Patterns
Model Configuration
php
final class Project extends Model
{
use HasFactory;
protected $fillable = ['name', 'owner_id', 'status'];
protected $casts = [
'status' => ProjectStatus::class,
'archived_at' => 'datetime',
];
public function owner(): BelongsTo
{
return $this->belongsTo(User::class, 'owner_id');
}
public function scopeActive(Builder $query): Builder
{
return $query->whereNull('archived_at');
}
}
Custom Casts and Value Objects

Use enums or value objects for strict typing.

php
use Illuminate\Database\Eloquent\Casts\Attribute;
protected $casts = [
'status' => ProjectStatus::class,
];
php
protected function budgetCents(): Attribute
{
return Attribute::make(
get: fn (int $value) => Money::fromCents($value),
set: fn (Money $money) => $money->toCents(),
);
}
Eager Loading to Avoid N+1
php
$orders = Order::query()
->with(['customer', 'items.product'])
->latest()
->paginate(25);
Query Objects for Complex Filters
php
final class ProjectQuery
{
public function __construct(private Builder $query) {}
public function ownedBy(int $userId): self
{
$query = clone $this->query;
return new self($query->where('owner_id', $userId));
}
public function active(): self
{
$query = clone $this->query;
return new self($query->whereNull('archived_at'));
}
public function builder(): Builder
{
return $this->query;
}
}
Global Scopes and Soft Deletes

Use global scopes for default filtering and SoftDeletes for recoverable records. Use either a global scope or a named scope for the same filter, not both, unless you intend layered behavior.

php
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Builder;
final class Project extends Model
{
use SoftDeletes;
protected static function booted(): void
{
static::addGlobalScope('active', function (Builder $builder): void {
$builder->whereNull('archived_at');
});
}
}
Query Scopes for Reusable Filters
php
use Illuminate\Database\Eloquent\Builder;
final class Project extends Model
{
public function scopeOwnedBy(Builder $query, int $userId): Builder
{
return $query->where('owner_id', $userId);
}
}
// In service, repository etc.
$projects = Project::ownedBy($user->id)->get();
Transactions for Multi-Step Updates
php
use Illuminate\Support\Facades\DB;
DB::transaction(function (): void {
$order->update(['status' => 'paid']);
$order->items()->update(['paid_at' => now()]);
});
Migrations
Naming Convention
  • File names use timestamps: YYYY_MM_DD_HHMMSS_create_users_table.php
  • Migrations use anonymous classes (no named class); the filename communicates intent
  • Table names are snake_case and plural by default
Example Migration
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('orders', function (Blueprint $table): void {
$table->id();
$table->foreignId('customer_id')->constrained()->cascadeOnDelete();
$table->string('status', 32)->index();
$table->unsignedInteger('total_cents');
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('orders');
}
};
Form Requests and Validation

Keep validation in form requests and transform inputs to DTOs.

php
use App\Models\Order;
final class StoreOrderRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()?->can('create', Order::class) ?? false;
}
public function rules(): array
{
return [
'customer_id' => ['required', 'integer', 'exists:customers,id'],
'items' => ['required', 'array', 'min:1'],
'items.*.sku' => ['required', 'string'],
'items.*.quantity' => ['required', 'integer', 'min:1'],
];
}
public function toDto(): CreateOrderData
{
return new CreateOrderData(
customerId: (int) $this->validated('customer_id'),
items: $this->validated('items'),
);
}
}
API Resources

Keep API responses consistent with resources and pagination.

php
$projects = Project::query()->active()->paginate(25);
return response()->json([
'success' => true,
'data' => ProjectResource::collection($projects->items()),
'error' => null,
'meta' => [
'page' => $projects->currentPage(),
'per_page' => $projects->perPage(),
'total' => $projects->total(),
],
]);
Events, Jobs, and Queues
  • Emit domain events for side effects (emails, analytics)
  • Use queued jobs for slow work (reports, exports, webhooks)
  • Prefer idempotent handlers with retries and backoff
Caching
  • Cache read-heavy endpoints and expensive queries
  • Invalidate caches on model events (created/updated/deleted)
  • Use tags when caching related data for easy invalidation
Configuration and Environments
  • Keep secrets in .env and config in config/*.php
  • Use per-environment config overrides and config:cache in production

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
109,615
Repository forks
14,299
Repository npm downloads, 7 days
1,792
7-day trend score
75

Stars and forks are for the whole GitHub repository, not this skill alone. Downloads are for the repository's npm package. Refreshed 17 Mar 2026, 7 months ago.

Extension points

  • configConfiguration overrides

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/affaan-m/everything-claude-code/laravel-patterns/badge)](https://verified-skill.com/skills/affaan-m/everything-claude-code/laravel-patterns)

Something wrong with this skill or its page? Tell us.