Proje: OkulUp API · Hub: OkulUp API — Conventions

OkulUp API — API Kod Konvansiyonları

PHP Zorunlulukları

declare(strict_types=1);  // Her dosyanın başında
 
// Constructor property promotion:
public function __construct(
    private AuthorizationService $authService,
) {}
 
// Explicit return type zorunlu:
public function show(Request $request, User $student): JsonResponse

Controller Pattern

  • Tüm controller’lar app/Http/Controllers/Api/ altında (versiyonsuz)
  • Her action için ayrı Form Request class (app/Http/Requests/)
  • Inline validation YOK — her zaman Form Request kullanılır
  • OpenAPI attribute’ları controller action’larına eklenir (#[OA\Get(...)])
  • Response: her zaman JsonResponse veya AnonymousResourceCollection
  • Hata response: response()->json(['message' => '...'], 4xx)
// Tipik controller action:
public function store(StoreMealMenuRequest $request): JsonResponse
{
    /** @var \App\Models\User $user */
    $user = $request->user();
    
    // Logic...
    
    return response()->json([
        'data' => new MealMenuResource($model),
    ], 201);
}

Model Pattern

  • Casts: casts() method, $casts property değil (Laravel 12 stili)
  • PHPDoc @property annotation’ları için date/Carbon nesneleri belirtilmeli
  • SoftDeletes sık kullanılıyor (User, Attendance, Payment, Assignment vb.)
  • Auditable trait: created/updated/deleted otomatik AuditLog (User, Attendance, Payment, DocumentRequest)
  • İlişki metodları: explicit return type (BelongsTo, HasMany vb.)
  • isXxx() metodlar için boolean helper metod pattern:
    public function isDraft(): bool { return $this->status === 'draft'; }

Eloquent FK Kuralı (KRİTİK)

// schools.id ve users.id = unsigned int (increments)
$table->unsignedInteger('school_id');
$table->unsignedInteger('user_id');
 
// classes.id = unsigned bigint (id())
$table->unsignedBigInteger('class_id');
 
// ASLA foreignId() kullanma → type mismatch

Resource Pattern

  • Her model için app/Http/Resources/ altında XxxResource
  • whenLoaded() ile lazy loading koruması
  • Avatar URL: str_starts_with($url, 'avatars/') ise S3 URL’ye çevir
  • Timestamp: toISOString() formatı

Servis Kullanımı

// DI ile inject et:
public function __construct(
    private AuthorizationService $authService,
) {}
 
// Ya da app():
$authService = app(AuthorizationService::class);

Query Scope Pattern

// Model üzerinde scope tanımla:
public function scopePending(Builder $query): Builder
{
    return $query->where('status', 'pending');
}
 
// Type hint şart:
// @param Builder<ModelName> $query
// @return Builder<ModelName>

Throttle Middleware Alias’ları

throttle:api — genel API
throttle:login, throttle:register, throttle:upload, throttle:message, throttle:forgot-password, throttle:school-search