Laravel Architecture Patterns
Улучшите разработку на Laravel с помощью production-уровневых архитектурных шаблонов, оптимизаций Eloquent и масштабируемых дизайнов API с использованием Claude Code.
Этот навык предоставляет исчерпывающее руководство по созданию корпоративных Laravel-приложений с использованием лучших практик индустрии. Он упрощает процесс разработки за счёт соблюдения чёткого разделения ответственности через слои Actions и Services, оптимизирует взаимодействие с базой данных с помощью паттернов Eloquent и обеспечивает надёжный дизайн API через Resources. Будь то управление сложными фоновыми задачами с помощью очередей или внедрение безопасной мультитенантной маршрутизации — этот навык помогает разработчикам поддерживать чистую и сопровождаемую кодовую базу, следующую современным соглашениям Laravel.
Ключевые особенности
Варианты использования
| name | laravel-patterns |
|---|---|
| description | Laravel architecture patterns, routing/controllers, Eloquent ORM, service layers, queues, events, caching, and API resources for production apps. |
| origin | ECC |
Ölçeklenebilir, bakım yapılabilir uygulamalar için üretim seviyesi Laravel mimari desenleri.
- Laravel web uygulamaları veya API'ler oluşturma
- Controller'lar, servisler ve domain mantığını yapılandırma
- Eloquent model'ler ve ilişkiler ile çalışma
- Resource'lar ve sayfalama ile API tasarlama
- Kuyruklar, event'ler, caching ve arka plan işleri ekleme
- Uygulamayı net sınırlar etrafında yapılandırın (controller'lar -> servisler/action'lar -> model'ler).
- Routing'i öngörülebilir tutmak için açık binding'ler ve scoped binding'ler kullanın; erişim kontrolü için yetkilendirmeyi yine de uygulayın.
- Domain mantığını tutarlı tutmak için typed model'leri, cast'leri ve scope'ları tercih edin.
- IO-ağır işleri kuyruklarda tutun ve pahalı okumaları önbelleğe alın.
- Config'i
config/*içinde merkezileştirin ve ortamları açık tutun.
Net katman sınırları (HTTP, servisler/action'lar, model'ler) ile geleneksel bir Laravel düzeni kullanın.
app/
├── Actions/ # Tek amaçlı kullanım durumları
├── Console/
├── Events/
├── Exceptions/
├── Http/
│ ├── Controllers/
│ ├── Middleware/
│ ├── Requests/ # Form request validation
│ └── Resources/ # API resources
├── Jobs/
├── Models/
├── Policies/
├── Providers/
├── Services/ # Domain servislerini koordine etme
└── Support/
config/
database/
├── factories/
├── migrations/
└── seeders/
resources/
├── views/
└── lang/
routes/
├── api.php
├── web.php
└── console.php
Controller'ları ince tutun. Orkestrasyon'u servislere ve tek amaçlı mantığı action'lara koyun.
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);
}
}Netlik için route-model binding ve resource controller'ları tercih edin.
use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->group(function () {
Route::apiResource('projects', ProjectController::class);
});Çapraz kiracı erişimini önlemek için scoped binding'leri kullanın.
Route::scopeBindings()->group(function () {
Route::get('/accounts/{account}/projects/{project}', [ProjectController::class, 'show']);
});- Çift iç içe geçmeyi önlemek için prefix'leri ve path'leri tutarlı tutun (örn.
conversationvsconversations). - Bound model'e uyan tek bir parametre ismi kullanın (örn.
Conversationiçin{conversation}). - İç içe geçirirken üst-alt ilişkilerini zorlamak için scoped binding'leri tercih edin.
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');
});
});Bir parametrenin farklı bir model sınıfına çözümlenmesini istiyorsanız, açık binding tanımlayın. Özel binding mantığı için Route::bind() kullanın veya model'de resolveRouteBinding() uygulayın.
use App\Models\AiConversation;
use Illuminate\Support\Facades\Route;
Route::model('conversation', AiConversation::class);Net bağımlılık bağlantısı için bir service provider'da interface'leri implementasyonlara bağlayın.
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);
}
}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');
}
}Sıkı tiplemeler için enum'lar veya value object'leri kullanın.
use Illuminate\Database\Eloquent\Casts\Attribute;
protected $casts = [
'status' => ProjectStatus::class,
];protected function budgetCents(): Attribute
{
return Attribute::make(
get: fn (int $value) => Money::fromCents($value),
set: fn (Money $money) => $money->toCents(),
);
}$orders = Order::query()
->with(['customer', 'items.product'])
->latest()
->paginate(25);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;
}
}Varsayılan filtreleme için global scope'ları ve geri kurtarılabilir kayıtlar için SoftDeletes kullanın.
Katmanlı davranış istemediğiniz sürece, aynı filtre için global scope veya named scope kullanın, ikisini birden değil.
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');
});
}
}use Illuminate\Database\Eloquent\Builder;
final class Project extends Model
{
public function scopeOwnedBy(Builder $query, int $userId): Builder
{
return $query->where('owner_id', $userId);
}
}
// Servis, repository vb. içinde
$projects = Project::ownedBy($user->id)->get();use Illuminate\Support\Facades\DB;
DB::transaction(function (): void {
$order->update(['status' => 'paid']);
$order->items()->update(['paid_at' => now()]);
});- Dosya isimleri zaman damgası kullanır:
YYYY_MM_DD_HHMMSS_create_users_table.php - Migration'lar anonim sınıflar kullanır (isimlendirilmiş sınıf yok); dosya ismi amacı iletir
- Tablo isimleri varsayılan olarak
snake_caseve çoğuldur
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');
}
};Validation'ı form request'lerde tutun ve input'ları DTO'lara dönüştürün.
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'),
);
}
}Resource'lar ve sayfalama ile API yanıtlarını tutarlı tutun.
$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(),
],
]);- Yan etkiler için domain event'leri yayınlayın (email'ler, analytics)
- Yavaş işler için kuyruğa alınmış job'ları kullanın (raporlar, export'lar, webhook'lar)
- Yeniden deneme ve backoff ile idempotent handler'ları tercih edin
- Okuma-ağırlıklı endpoint'leri ve pahalı sorguları önbelleğe alın
- Model event'lerinde (created/updated/deleted) önbellekleri geçersiz kılın
- Kolay geçersiz kılma için ilgili verileri önbelleğe alırken tag'leri kullanın
- Gizli bilgileri
.env'de ve yapılandırmayıconfig/*.php'de tutun - Ortama özel yapılandırma geçersiz kılmaları kullanın ve production'da
config:cachekullanın
Что это 🧱
Laravel Architecture Patterns — это свод проверенных архитектурных решений и шаблонов для создания масштабируемых и поддерживаемых Laravel-приложений. Skill охватывает организацию кода от маршрутизации и контроллеров до Eloquent-моделей, сервисного слоя, очередей, кэширования и API-ресурсов. Материал ориентирован на production-проекты и помогает разработчику выстроить чёткие границы между слоями приложения.
Как работает 🔧
🗂️ Рекомендуемая структура проекта
Приложение делится на логические папки:
app/Actions— одноцелевые use-case классы (например,CreateOrderAction)app/Http/Controllers— тонкие контроллерыapp/Http/Requests— Form Request с валидацией и преобразованием в DTOapp/Http/Resources— API-ресурсы для форматирования ответовapp/Services— сервисы, координирующие доменную логикуapp/Models,app/Policies,app/Jobs,app/Events— стандартные слоиconfig/,database/,routes/— конфигурация, миграции, маршруты
🚦 Контроллеры → Сервисы → Actions
Контроллеры должны оставаться тонкими. Оркестрация выносится в сервисы, а одноцелевая логика — в Action-классы.
Пример Action:
final class CreateOrderAction
{
public function __construct(private OrderRepository $orders) {}
public function handle(CreateOrderData $data): Order
{
return $this->orders->create($data);
}
}
Контроллер вызывает Action и возвращает JSON с ресурсом:
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);
}
}
🧭 Маршрутизация и привязка моделей
- Для API используются Resource-контроллеры с middleware
auth:sanctum. - Scoped binding предотвращает кросс-арендный доступ — параметры вкладываются друг в друга:
/accounts/{account}/projects/{project}. - Если нужно привязать параметр к другой модели, используется явный
Route::model()илиresolveRouteBinding(). - Имена параметров должны совпадать с именами связанных моделей (единственное число, snake_case).
Пример гибкой вложенности:
Route::prefix('conversations')->group(function () {
Route::post('/', [ConversationController::class, 'store']);
Route::scopeBindings()->group(function () {
Route::get('/{conversation}', [ConversationController::class, 'show']);
Route::post('/{conversation}/messages', [MessageController::class, 'store']);
Route::get('/{conversation}/messages/{message}', [MessageController::class, 'show']);
});
});
🧩 Eloquent-модели
Skill предлагает несколько шаблонов:
- Типизированные касты — enum'ы и value object'ы для строгих типов.
- Атрибут-касты с геттером/сеттером для преобразования (например,
Moneyиз cents). - Eager loading —
with(['customer', 'items.product'])для предотвращения N+1. - Query Object — класс с цепочкой фильтров (
ownedBy,active) для сложных запросов. - Global Scopes — автоматическая фильтрация (например, только активные проекты).
- Named Scopes — переиспользуемые методы на модели (
scopeOwnedBy). - SoftDeletes — мягкое удаление с восстановлением.
- Транзакции — для многошаговых обновлений:
DB::transaction(...).
📥 Form Request и DTO
Валидация инкапсулируется в FormRequest, который также превращает входные данные в DTO:
public function toDto(): CreateOrderData
{
return new CreateOrderData(
customerId: (int) $this->validated('customer_id'),
items: $this->validated('items'),
);
}
🌐 API-ресурсы
Ответы строятся единообразно — с полями success, data, error, meta. Пагинация передаётся в meta (page, per_page, total).
⚙️ Events, Jobs, Queues
- Domain events — для побочных эффектов (email, аналитика).
- Queue jobs — для тяжёлых операций (отчёты, экспорт, вебхуки).
- Обработчики должны быть идемпотентными, с настройками retry и backoff.
🧠 Кэширование
- Кэшируются read-heavy endpoint'ы и дорогие запросы.
- Инвалидация кэша происходит в событиях модели (
created,updated,deleted). - Для групповой инвалидации используются теги (если драйвер поддерживает).
📦 Конфигурация и окружение
- Секреты хранятся в
.env, настройки — вconfig/*.php. - Для production обязательно выполнять
config:cache, чтобы объединить все конфиги. - Миграции используют анонимные классы и snake_case-имена таблиц с временными метками.
Когда использовать 📌
- При построении нового Laravel-проекта — чтобы сразу заложить правильную архитектуру.
- При рефакторинге существующего монолита — для разделения ответственности между слоями.
- Если нужно масштабировать команду — чёткие границы упрощают параллельную разработку.
- Когда проект предполагает сложную бизнес-логику, очереди и событийную модель.
- Для API-first приложений — с ресурсами, пагинацией и Form Request.
Важно знать ⚠️
- Не смешивайте Global Scope и Named Scope для одного и того же фильтра — это приводит к непредсказуемому поведению.
- Action-классы не должны быть толстыми; если в них появляется оркестрация — выносите её в сервисы.
- Scoped binding обязателен для вложенных ресурсов, иначе пользователь сможет получить доступ к чужим данным.
- Имена параметров в маршрутах должны быть в единственном числе и совпадать с именем модели (например,
{conversation}). - Не забывайте про
config:cacheна production — это ускоряет загрузку конфигов в 10+ раз.
Skill написан на турецком языке, но код и структура универсальны для любого Laravel-разработчика.
Подходит ли это для крупномасштабных приложений?
Безусловно. Предоставляемые паттерны специально разработаны для масштабирования на уровне продакшена, удобства поддержки и четкого разделения ответственности.
Как этот навык улучшает производительность Laravel?
Он обеспечивает Eager Loading для предотвращения N+1 запросов и предоставляет стратегии кэширования дорогих операций чтения и выгрузки задач в фоновые очереди.
Могу ли я использовать это для разработки API?
Да, он включает специализированные паттерны для API Resources, согласованные структуры пагинации и валидацию запросов форм для надежных RESTful сервисов.
Помогает ли это с безопасностью базы данных?
Да, он предоставляет паттерны для scoped route-model binding, чтобы предотвратить несанкционированный доступ к данным между арендаторами в многопользовательских приложениях.
Какой архитектурный паттерн он использует?
Он продвигает подход 'Thin Controller', перенося бизнес-логику в выделенные классы Service и Action для лучшей тестируемости и повторного использования.
Синхронизируйте навыки с Claude Cowork, Claude Code, Codex и другими.
Установка одной командой.
npx skillfish add affaan-m/everything-claude-code laravel-patternsИсточник: https://mcpmarket.com/tools/skills/laravel-architecture-patterns-3
Комментарии
Комментариев пока нет. Будьте первым.