mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-04-05 08:43:29 +08:00
* Add Turkish (tr) docs and update README Add a full set of Turkish documentation under docs/tr (agents, changelog, CLAUDE guide, contributing, code of conduct, and many agents/commands/skills/rules files). Update README to include a link to the Turkish docs and increment the supported language count from 5 to 6. This commit adds localized guidance and references to help Turkish-speaking contributors and users. * Update docs/tr/TROUBLESHOOTING.md Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * Update docs/tr/README.md Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * docs(tr): fix license link and update readmes Update Turkish docs: change license badge link to point to repository root (../../LICENSE), increment displayed language count from 5 to 6, and remove two outdated related links from docs/tr/examples/README.md to keep references accurate. * Update docs/tr/commands/instinct-import.md Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * Update docs/tr/commands/checkpoint.md Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
416 lines
11 KiB
Markdown
416 lines
11 KiB
Markdown
---
|
||
name: laravel-patterns
|
||
description: Laravel architecture patterns, routing/controllers, Eloquent ORM, service layers, queues, events, caching, and API resources for production apps.
|
||
origin: ECC
|
||
---
|
||
|
||
# Laravel Geliştirme Desenleri
|
||
|
||
Ölçeklenebilir, bakım yapılabilir uygulamalar için üretim seviyesi Laravel mimari desenleri.
|
||
|
||
## Ne Zaman Kullanılır
|
||
|
||
- 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
|
||
|
||
## Nasıl Çalışır
|
||
|
||
- 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.
|
||
|
||
## Örnekler
|
||
|
||
### Proje Yapısı
|
||
|
||
Net katman sınırları (HTTP, servisler/action'lar, model'ler) ile geleneksel bir Laravel düzeni kullanın.
|
||
|
||
### Önerilen Düzen
|
||
|
||
```
|
||
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
|
||
```
|
||
|
||
### Controllers -> Services -> Actions
|
||
|
||
Controller'ları ince tutun. Orkestrasyon'u servislere ve tek amaçlı mantığı action'lara koyun.
|
||
|
||
```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 ve Controllers
|
||
|
||
Netlik için route-model binding ve resource controller'ları tercih edin.
|
||
|
||
```php
|
||
use Illuminate\Support\Facades\Route;
|
||
|
||
Route::middleware('auth:sanctum')->group(function () {
|
||
Route::apiResource('projects', ProjectController::class);
|
||
});
|
||
```
|
||
|
||
### Route Model Binding (Scoped)
|
||
|
||
Çapraz kiracı erişimini önlemek için scoped binding'leri kullanın.
|
||
|
||
```php
|
||
Route::scopeBindings()->group(function () {
|
||
Route::get('/accounts/{account}/projects/{project}', [ProjectController::class, 'show']);
|
||
});
|
||
```
|
||
|
||
### İç İçe Route'lar ve Binding İsimleri
|
||
|
||
- Çift iç içe geçmeyi önlemek için prefix'leri ve path'leri tutarlı tutun (örn. `conversation` vs `conversations`).
|
||
- Bound model'e uyan tek bir parametre ismi kullanın (örn. `Conversation` için `{conversation}`).
|
||
- İç içe geçirirken üst-alt ilişkilerini zorlamak için scoped binding'leri tercih edin.
|
||
|
||
```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');
|
||
});
|
||
});
|
||
```
|
||
|
||
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.
|
||
|
||
```php
|
||
use App\Models\AiConversation;
|
||
use Illuminate\Support\Facades\Route;
|
||
|
||
Route::model('conversation', AiConversation::class);
|
||
```
|
||
|
||
### Service Container Binding'leri
|
||
|
||
Net bağımlılık bağlantısı için bir service provider'da interface'leri implementasyonlara bağlayın.
|
||
|
||
```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 Desenleri
|
||
|
||
### Model Yapılandırması
|
||
|
||
```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');
|
||
}
|
||
}
|
||
```
|
||
|
||
### Özel Cast'ler ve Value Object'ler
|
||
|
||
Sıkı tiplemeler için enum'lar veya value object'leri kullanın.
|
||
|
||
```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(),
|
||
);
|
||
}
|
||
```
|
||
|
||
### N+1'i Önlemek için Eager Loading
|
||
|
||
```php
|
||
$orders = Order::query()
|
||
->with(['customer', 'items.product'])
|
||
->latest()
|
||
->paginate(25);
|
||
```
|
||
|
||
### Karmaşık Filtreler için Query Object'leri
|
||
|
||
```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 Scope'lar ve Soft Delete'ler
|
||
|
||
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.
|
||
|
||
```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');
|
||
});
|
||
}
|
||
}
|
||
```
|
||
|
||
### Yeniden Kullanılabilir Filtreler için Query Scope'ları
|
||
|
||
```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);
|
||
}
|
||
}
|
||
|
||
// Servis, repository vb. içinde
|
||
$projects = Project::ownedBy($user->id)->get();
|
||
```
|
||
|
||
### Çok Adımlı Güncellemeler için Transaction'lar
|
||
|
||
```php
|
||
use Illuminate\Support\Facades\DB;
|
||
|
||
DB::transaction(function (): void {
|
||
$order->update(['status' => 'paid']);
|
||
$order->items()->update(['paid_at' => now()]);
|
||
});
|
||
```
|
||
|
||
### Migration'lar
|
||
|
||
### İsimlendirme Kuralı
|
||
|
||
- 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_case` ve çoğuldur
|
||
|
||
### Örnek 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 Request'ler ve Validation
|
||
|
||
Validation'ı form request'lerde tutun ve input'ları DTO'lara dönüştürün.
|
||
|
||
```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 Resource'ları
|
||
|
||
Resource'lar ve sayfalama ile API yanıtlarını tutarlı tutun.
|
||
|
||
```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(),
|
||
],
|
||
]);
|
||
```
|
||
|
||
### Event'ler, Job'lar ve Kuyruklar
|
||
|
||
- 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
|
||
|
||
### Caching
|
||
|
||
- 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
|
||
|
||
### Yapılandırma ve Ortamlar
|
||
|
||
- 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:cache` kullanın
|