Proje: Okul Platform · Hub: Okul Platform — Conventions

StringEnumType Pattern

Boolean alanlar '1'/'0' string olarak saklanır, PHP enum ile sarılır:

enum StringEnumType: string {
    case TRUE = '1';
    case FALSE = '0';
}

Model $attributes’ında varsayılan olarak atanır, $casts da kullanılmaz — dikkat!

Revisionable

sofa/revisionable paketi — Tüm değişiklikler revisions tablosunda loglanır.

  • Kullanan modeller: School, Lead, Customer, CustomerAgreement, Checkout
  • Her modelde $revisionPresenter = Presenters\X::class tanımı var

HasDynamicIncludes Trait

School, Lead, User modellerinde var. İstek üzerinden dinamik with() include’larına izin verir. Spatie QueryBuilder ile entegre çalışır.

SoftDeletes

Neredeyse tüm modellerde var. deleted_at field’ı. Pivot tablolarda da deleted_at var (withPivot içinde).

Repository Pattern

  • Interface: app/Repositories/Interfaces/
  • Implementasyon: app/Repositories/Repos/
  • DI binding: app/Providers/RepositoryServiceProvider.php
  • Tüm repository’ler interface üzerinden inject edilir

DTO Pattern

  • app/DTO/ — HTTP katmanından servise geçen veri
  • Adlandırma: IndexXDTO, StoreXDTO, UpdateXDTO
  • Admin vs Repo DTO ayrımı var: Admin/Checkout/StoreCheckoutDTO vs Repository/Checkout/CreateCheckoutDTO

Service Katmanı

  • app/Services/ — İş mantığı burada
  • Admin servisleri: app/Services/Admin/
  • Customer servisleri: app/Services/Customer/
  • final readonly class CheckoutService — İmmutable service pattern (PHP 8.2)

Validation: Route Bazlı Özel Mesajlar

AppServiceProvider::boot() içinde Validator resolver override edilmiş:

  1. Route adını alır (ör: api.admin.school-comments.store)
  2. api. prefix’ini kaldırır
  3. admin. veya customer. ile başlamıyorsa general. prefix ekler
  4. lang/{locale}/{route_name}.php dosyasından mesajları çeker
  5. CustomValidationRule ile birleştirir

Carbon Macro: trDate

$date->trDate()           // 'dd.MM.YYYY HH:mm'
$date->trDate(false)      // 'dd.MM.YYYY'
$date->trDate(true, 'long')  // 'dd MMMM YYYY HH:mm' (Türkçe)

QueryBuilder Macros

  • whereFindInSet($column, $value) — MySQL FIND_IN_SET (SQLite’da no-op)
  • excludeTestData($column, $testType) — Non-admin kullanıcılardan test verisi gizle
  • excludeTestDataWithNullable(...) — NULL değerleri de dahil

Morphmap Zorunluluğu

constants.phpOLD_USER_MODEL = 'App\User' AppServiceProviderRelation::morphMap(['App\User' => 'App\Models\User']) Eski veri App\User olarak saklanmış, morph map ile yeni yola çevriliyor.

Pint (Code Style)

pint.json — Laravel Pint ile PHP CS Fixer stili uygulanır. CI’da ./vendor/bin/pint --test çalıştırılıyor.

PHPStan

phpstan.neon.dist + phpstan-baseline.neon Level: Larastan larastan/larastan kullanıyor.

Testler

  • PHPUnit 11
  • hotmeteor/spectator — API spec testi (OpenAPI)
  • Test DB: SQLite (in-memory)
  • excludeTestData macro SQLite’da skip ediyor (FIND_IN_SET desteği yok)