# Naming Conventions

Framework-weite Naming Conventions für das Custom PHP Framework.

## Philosophie

**Kernprinzipien:**
1. **Keine redundanten Suffixe** - Domain-Code ist suffixfrei, Infrastructure hat Suffixe für Klarheit
2. **Semantische Klarheit** - Namen beschreiben Absicht, nicht technische Implementation
3. **Namespace-Kontext** - Namespace gibt primären Kontext, Namen sind prägnant
4. **Konsistenz** - Einheitliche Patterns über das gesamte Framework

## Übersicht

| Komponente | Pattern | Beispiel | Suffix/Prefix |
|------------|---------|----------|---------------|
| **View Controller** | `Show{Feature}` | `ShowContact`, `ShowHome` | - |
| **Action Controller** | `{Verb}{Feature}` | `SubmitContact`, `CreateUser` | - |
| **Repository Interface** | `{Entity}Repository` | `UserRepository` | ✅ Repository |
| **Repository Implementation** | `{Type}{Entity}Repository` | `InMemoryUserRepository` | ✅ Repository |
| **Service** | `{Domain}Service` | `EmailService`, `UserService` | ✅ Service |
| **Manager** | `{Capability}Manager` | `SessionManager`, `CacheManager` | ✅ Manager |
| **Handler (Generic)** | `{Capability}Handler` | `ErrorHandler`, `FileHandler` | ✅ Handler |
| **Handler (Command)** | `{Command}Handler` | `StoreContactHandler` | ✅ Handler |
| **CQRS Command** | `{Verb}{Noun}` | `SendEmail`, `CreateUser` | - |
| **Console Command** | `{Feature}Command` | `HealthCheckCommand` | ✅ Command |
| **Domain Exception** | `{Condition}` | `UserNotFound`, `PaymentFailed` | - |
| **Technical Exception** | `{Type}Exception` | `DatabaseException` | ✅ Exception |
| **Value Object** | `{Concept}` | `Email`, `Price`, `Duration` | - |
| **Event** | `{Entity}{Action}` | `UserCreated`, `OrderPlaced` | - |
| **Middleware** | `{Purpose}Middleware` | `AuthMiddleware` | ✅ Middleware |
| **Initializer** | `{Service}Initializer` | `DatabaseInitializer` | ✅ Initializer |

## Detaillierte Patterns

### 1. Controller Naming

**Strikte Trennung zwischen View und Business Logic.**

#### View Controllers - `Show{Feature}`

**Zweck:** Nur View-Rendering, keine Business Logic

```php
// ✅ View-Only Controller
final readonly class ShowContact
{
    #[Route('/contact', method: Method::GET)]
    public function __invoke(): ViewResult
    {
        return new ViewResult('contact', $metaData);
    }
}

final readonly class ShowHome
{
    #[Route('/', method: Method::GET)]
    public function __invoke(): ViewResult
    {
        return new ViewResult('home', $metaData);
    }
}
```

**Regeln:**
- ✅ NUR GET-Requests
- ✅ NUR ViewResult als Return Type
- ✅ Darf Daten aus Repository laden (für View)
- ❌ KEINE POST/PUT/DELETE Routes
- ❌ KEINE Business Logic (CommandBus, Services)

#### Action Controllers - `{Verb}{Feature}`

**Zweck:** Business Logic, Form Processing, API Operations

```php
// ✅ Action Controller mit Business Logic
final readonly class SubmitContact
{
    #[Route('/contact', method: Method::POST)]
    public function __invoke(ContactRequest $request): ActionResult
    {
        $this->commandBus->dispatch(new StoreContact(...));
        return new Redirect('/contact/success');
    }
}

final readonly class CreateUser
{
    #[Route('/users', method: Method::POST)]
    public function __invoke(CreateUserRequest $request): JsonResult
    {
        $user = $this->userService->create($request);
        return new JsonResult($user, Status::CREATED);
    }
}
```

**Verfügbare Verben:**
- `Submit{Feature}` - Form submission
- `Create{Feature}` - Resource creation (POST)
- `Update{Feature}` - Resource update (PUT/PATCH)
- `Delete{Feature}` - Resource deletion (DELETE)
- `Handle{Feature}` - Generic processing (Webhooks, Events)
- `Process{Feature}` - Complex operations (Payments, Orders)
- `Execute{Feature}` - Task execution (Jobs, Commands)

**Regeln:**
- ✅ POST/PUT/DELETE Operations
- ✅ Business Logic (CommandBus, Services, Repositories)
- ✅ Alle Result-Typen (ViewResult, JsonResult, Redirect, etc.)

#### Anti-Patterns

```php
// ❌ FALSCH: "Controller" Suffix ist redundant
class ContactController { }
class UserController { }

// ❌ FALSCH: View und Logic vermischt
class ShowContact
{
    #[Route('/contact', GET)]
    public function show(): ViewResult { }

    #[Route('/contact', POST)]  // ❌ Sollte SubmitContact sein
    public function submit(): ActionResult { }
}
```

---

### 2. Repository Pattern

**Pattern: Interface + Implementations mit Type-Prefix**

```php
// ✅ Repository Interface
interface UserRepository
{
    public function find(UserId $id): ?User;
    public function save(User $user): void;
}

// ✅ Repository Implementations mit Type-Prefix
final readonly class InMemoryUserRepository implements UserRepository
{
    public function find(UserId $id): ?User { }
    public function save(User $user): void { }
}

final readonly class DatabaseUserRepository implements UserRepository
{
    public function find(UserId $id): ?User { }
    public function save(User $user): void { }
}

final readonly class CacheUserRepository implements UserRepository
{
    private readonly UserRepository $decorated;

    public function find(UserId $id): ?User
    {
        return $this->cache->remember("user_{$id}",
            fn() => $this->decorated->find($id)
        );
    }
}
```

**Type-Prefixes:**
- `InMemory{Entity}Repository` - In-Memory Implementation
- `Database{Entity}Repository` - Database-backed
- `Cache{Entity}Repository` - Caching Decorator
- `File{Entity}Repository` - File-based Storage

**Regeln:**
- ✅ Interface ohne Type-Prefix
- ✅ Implementations mit Type-Prefix
- ✅ Suffix "Repository" immer vorhanden
- ❌ Kein Suffix-Pattern: `UserRepositoryDatabase`

---

### 3. Service Layer

**Pattern: `{Domain}Service` oder `{Capability}Service`**

```php
// ✅ Domain Services
final readonly class UserService
{
    public function createUser(Email $email, UserName $name): User { }
    public function findUserById(UserId $id): ?User { }
}

final readonly class EmailService
{
    public function sendWelcomeEmail(User $user): void { }
    public function sendPasswordResetEmail(Email $email, ResetToken $token): void { }
}

// ✅ Capability Services
final readonly class JobCleanupService
{
    public function cleanupExpiredJobs(): int { }
}

final readonly class MediaCleanupService
{
    public function cleanupOrphanedFiles(): void { }
}
```

**Regeln:**
- ✅ "Service" Suffix immer vorhanden
- ✅ Beschreibender Prefix (Domain oder Capability)
- ❌ Keine generischen Namen: `DataService`, `HelperService`

---

### 4. Manager Pattern

**Pattern: `{Capability}Manager` für komplexe State-Verwaltung**

```php
// ✅ Manager für State/Resource Management
final readonly class SessionManager
{
    public function start(): void { }
    public function regenerate(): void { }
    public function destroy(): void { }
}

final readonly class CacheManager
{
    public function clear(): void { }
    public function warmup(): void { }
    public function getStats(): CacheStats { }
}

final readonly class EntityManager
{
    public function persist(object $entity): void { }
    public function flush(): void { }
    public function clear(): void { }
}
```

**Unterschied Service vs Manager:**
- **Service**: Business Logic, stateless Operations
- **Manager**: State/Resource Management, komplexe Lifecycle

---

### 5. Handler Pattern

**Pattern: Namespace-basierte Unterscheidung**

#### Log Handlers

```php
// ✅ Log Handlers (Namespace gibt Kontext)
namespace App\Framework\Logging\Handlers;

final readonly class FileHandler implements LogHandler { }
final readonly class ConsoleHandler implements LogHandler { }
final readonly class SyslogHandler implements LogHandler { }
```

#### Command Handlers (CQRS)

```php
// ✅ Command Handlers
namespace App\Application\Contact;

final readonly class StoreContactHandler
{
    public function handle(StoreContact $command): void { }
}

namespace App\Framework\Mail\Commands;

final readonly class SendEmailCommandHandler
{
    public function handle(SendEmailCommand $command): void { }
}
```

**Regeln:**
- ✅ "Handler" Suffix immer vorhanden
- ✅ Namespace gibt primären Kontext
- ✅ Kein redundanter Prefix (kein "LogFileHandler")

---

### 6. Command Pattern

**Zwei Typen: CQRS Commands (kein Suffix) vs Console Commands (mit Suffix)**

#### CQRS Commands - Business Logic

```php
// ✅ CQRS Commands - KEIN Suffix
namespace App\Application\Contact;

final readonly class SendEmail
{
    public function __construct(
        public Email $to,
        public string $subject,
        public string $body
    ) {}
}

final readonly class StoreContact
{
    public function __construct(
        public Email $email,
        public string $name,
        public string $message
    ) {}
}

final readonly class CreateUser
{
    public function __construct(
        public Email $email,
        public UserName $name
    ) {}
}
```

#### Console Commands - Infrastructure

```php
// ✅ Console Commands - MIT "Command" Suffix
namespace App\Framework\Console\Commands;

final readonly class HealthCheckCommand implements ConsoleCommand
{
    public function execute(ConsoleInput $input): int { }
}

namespace App\Framework\Database\Migration\Commands;

final readonly class MakeMigrationCommand implements ConsoleCommand
{
    public function execute(ConsoleInput $input): int { }
}
```

**Regeln:**
- ✅ CQRS/Business Logic: Verb-Noun ohne Suffix
- ✅ Console/CLI: Noun + "Command" Suffix
- ❌ Keine Vermischung

---

### 7. Exception Pattern

**Hybrid-Ansatz: Domain ohne Suffix, Technical mit Suffix**

#### Domain Exceptions - OHNE Suffix

```php
// ✅ Domain Exceptions - ausdrucksstark, kein Suffix
namespace App\Domain\User\Exceptions;

final class UserNotFound extends FrameworkException
{
    public static function byId(UserId $id): self
    {
        return self::create(
            ErrorCode::ENTITY_NOT_FOUND,
            "User with ID '{$id}' not found"
        )->withData(['user_id' => $id->toString()]);
    }

    public static function byEmail(Email $email): self
    {
        return self::create(
            ErrorCode::ENTITY_NOT_FOUND,
            "User with email not found"
        )->withData(['email' => $email->getMasked()]);
    }
}

final class PaymentFailed extends FrameworkException
{
    public static function becauseOf(string $reason): self
    {
        return self::create(
            ErrorCode::PAYMENT_FAILED,
            "Payment failed: {$reason}"
        );
    }
}
```

#### Technical Exceptions - MIT Suffix

```php
// ✅ Technical/Infrastructure Exceptions - mit Suffix für Klarheit
namespace App\Framework\Database\Exception;

final class DatabaseException extends FrameworkException { }
final class SerializationException extends FrameworkException { }

namespace App\Framework\Validation\Exceptions;

final class ValidationException extends FrameworkException { }
```

**Regeln:**
- ✅ Domain/Business Logic: KEIN "Exception" Suffix
- ✅ Framework/Infrastructure: MIT "Exception" Suffix
- ✅ Factory Methods für expressiveness: `::byId()`, `::becauseOf()`
- ✅ Base Exception behält Suffix: `FrameworkException`

**Verwendung:**
```php
// Sehr lesbar und ausdrucksstark
throw UserNotFound::byEmail($email);
throw PaymentFailed::becauseOf('Insufficient funds');
throw OrderCancelled::byUser($userId);

// Technical Exceptions bleiben explizit
throw new DatabaseException('Connection failed');
throw new ValidationException('Invalid input');
```

---

### 8. Value Object Pattern

**Pattern: Keine Suffixe, beschreibende Namen**

```php
// ✅ Value Objects - kurz und prägnant
final readonly class Email
{
    public function __construct(public string $value)
    {
        $this->validate();
    }

    public function getMasked(): string
    {
        // email → e***@example.com
    }
}

final readonly class Price
{
    public function __construct(
        public int $cents,
        public Currency $currency
    ) {}

    public function toDecimal(): string
    {
        return number_format($this->cents / 100, 2);
    }
}

final readonly class Duration
{
    private function __construct(public int $seconds) {}

    public static function fromMinutes(int $minutes): self
    {
        return new self($minutes * 60);
    }

    public static function fromHours(int $hours): self
    {
        return new self($hours * 3600);
    }
}
```

**Regeln:**
- ✅ Beschreibende Namen ohne Suffix
- ✅ Immutable (readonly)
- ✅ Rich Domain Logic
- ❌ Kein "VO", "ValueObject" Suffix
- ❌ Keine primitiven Properties (nutze Validation)

---

### 9. Event Pattern

**Pattern: `{Entity}{PastTenseAction}`**

```php
// ✅ Domain Events
final readonly class UserCreated
{
    public function __construct(
        public UserId $userId,
        public Email $email,
        public DateTimeImmutable $occurredAt
    ) {}
}

final readonly class OrderPlaced
{
    public function __construct(
        public OrderId $orderId,
        public UserId $userId,
        public Money $total,
        public DateTimeImmutable $occurredAt
    ) {}
}

final readonly class PaymentProcessed
{
    public function __construct(
        public PaymentId $paymentId,
        public Money $amount,
        public DateTimeImmutable $occurredAt
    ) {}
}
```

**Regeln:**
- ✅ Past Tense (Ereignis ist bereits passiert)
- ✅ Immutable Event Data
- ✅ `occurredAt` Timestamp
- ❌ Kein "Event" Suffix (Namespace gibt Kontext)

---

### 10. Middleware Pattern

**Pattern: `{Purpose}Middleware`**

```php
// ✅ Middleware
final readonly class AuthMiddleware implements Middleware
{
    public function process(Request $request, callable $next): Response { }
}

final readonly class CsrfMiddleware implements Middleware
{
    public function process(Request $request, callable $next): Response { }
}

final readonly class LoggingMiddleware implements Middleware
{
    public function process(Request $request, callable $next): Response { }
}
```

**Regeln:**
- ✅ "Middleware" Suffix immer vorhanden
- ✅ Beschreibender Purpose-Prefix

---

### 11. Initializer Pattern

**Pattern: `{Service}Initializer` für DI Container Setup**

```php
// ✅ Initializers
final readonly class DatabaseInitializer
{
    #[Initializer]
    public function __invoke(Container $container): ConnectionInterface
    {
        return new PdoConnection(
            DatabaseConfig::fromEnvironment($this->env)
        );
    }
}

final readonly class LoggerInitializer
{
    #[Initializer]
    public function __invoke(Container $container): Logger
    {
        return new DefaultLogger(
            handlers: [$this->fileHandler, $this->consoleHandler]
        );
    }
}
```

**Regeln:**
- ✅ "Initializer" Suffix
- ✅ `#[Initializer]` Attribute
- ✅ Returns configured service instance

---

### 12. Interface Pattern

**Pattern: Beschreibender Name OHNE "Interface" Suffix**

#### Framework Interfaces

```php
// ✅ KORREKT - Beschreibende, behavior-fokussierte Namen
namespace App\Framework\Cache;

interface Cache
{
    public function get(string $key): mixed;
    public function set(string $key, mixed $value, int $ttl = 3600): bool;
    public function delete(string $key): bool;
    public function clear(): bool;
}

namespace App\Framework\Logging;

interface Logger
{
    public function emergency(string $message, array $context = []): void;
    public function error(string $message, array $context = []): void;
    public function info(string $message, array $context = []): void;
}

namespace App\Domain\User;

interface UserRepository
{
    public function find(UserId $id): ?User;
    public function save(User $user): void;
    public function findByEmail(Email $email): ?User;
}
```

#### Anti-Patterns

```php
// ❌ FALSCH - "Interface" Suffix ist redundant
interface CacheInterface { }
interface LoggerInterface { }
interface RepositoryInterface { }
interface UserRepositoryInterface { }
interface EventDispatcherInterface { }

// ❌ FALSCH - Generic "I" Prefix (C# Style)
interface ICache { }
interface ILogger { }
interface IRepository { }
```

**Regeln:**
- ✅ Beschreibender Name der das Verhalten/Contract beschreibt
- ✅ Kein "Interface" Suffix
- ✅ Kein "I" Prefix
- ✅ Fokus auf Behavior/Capability: "Was kann es tun?"

**Philosophie:**
- Interface Namen sollten selbsterklärend sein
- Der Typ "Interface" ist aus dem Kontext ersichtlich
- Fokus auf Contract/Behavior, nicht auf Implementation Details

---

## Directory Structure

**Feature-basierte, flache Struktur (DDD-Style)**

```
src/
├── Application/
│   ├── Contact/
│   │   ├── ShowContact.php              # View Controller
│   │   ├── SubmitContact.php            # Action Controller
│   │   ├── ContactRequest.php           # Request VO
│   │   ├── StoreContact.php             # CQRS Command
│   │   └── StoreContactHandler.php      # Command Handler
│   ├── User/
│   │   ├── ShowUserProfile.php
│   │   ├── UpdateUserProfile.php
│   │   ├── DeleteUser.php
│   │   └── UserService.php
│   └── Admin/
│       ├── ShowImageManager.php
│       ├── CreateImage.php
│       └── DeleteImage.php
├── Domain/
│   ├── User/
│   │   ├── User.php                     # Entity
│   │   ├── UserId.php                   # Value Object
│   │   ├── UserRepository.php           # Interface
│   │   ├── Exceptions/
│   │   │   ├── UserNotFound.php         # Domain Exception
│   │   │   └── InvalidEmail.php
│   │   └── Events/
│   │       ├── UserCreated.php
│   │       └── UserDeleted.php
│   └── Order/
│       ├── Order.php
│       ├── OrderId.php
│       ├── OrderRepository.php
│       └── Exceptions/
│           └── OrderNotFound.php
└── Framework/
    ├── Database/
    │   ├── DatabaseManager.php
    │   ├── EntityManager.php
    │   ├── Exception/
    │   │   └── DatabaseException.php    # Technical Exception
    │   └── Repository/
    │       └── EntityRepository.php
    └── Logging/
        ├── Logger.php
        ├── LoggerInitializer.php
        └── Handlers/
            ├── FileHandler.php
            ├── ConsoleHandler.php
            └── SyslogHandler.php
```

**Regeln:**
- ✅ Feature-basierte Gruppierung
- ✅ Zusammengehörige Klassen im selben Namespace
- ✅ Keine `/Controllers/` Subfolder
- ✅ Exceptions in `/Exceptions/` Subnamespace
- ✅ Events in `/Events/` Subnamespace

---

## Method Naming

### Public API Methods

```php
// ✅ Verb-Noun Pattern
public function getUser(UserId $id): User { }
public function createOrder(CreateOrderData $data): Order { }
public function updateProfile(UpdateProfileData $data): void { }
public function deleteImage(ImageId $id): void { }

// ✅ Boolean Methods
public function isValid(): bool { }
public function hasExpired(): bool { }
public function canAccess(User $user): bool { }
public function shouldRetry(): bool { }

// ✅ Factory Methods
public static function fromArray(array $data): self { }
public static function fromString(string $value): self { }
public static function create(...$args): self { }

// ✅ Transformation Methods
public function toArray(): array { }
public function toString(): string { }
public function toJson(): string { }
public function toDecimal(): string { }
```

### Readonly Classes - Public Properties statt Getters

```php
// ✅ Readonly Classes: Public Properties
final readonly class User
{
    public function __construct(
        public UserId $id,
        public Email $email,
        public UserName $name
    ) {}
}

// Verwendung:
$user->email;  // ✅ Direkt zugreifen
$user->name;   // ✅ Kein Getter nötig

// ❌ FALSCH bei readonly Classes
public function getEmail(): Email { return $this->email; }  // Redundant!
```

---

## Anti-Patterns

### ❌ Vermeiden

```php
// ❌ Redundante Suffixe bei Domain Code
class UserController { }          // Nutze: ShowUser, CreateUser
class EmailVO { }                 // Nutze: Email
class SendEmailCommand { }        // Nutze: SendEmail (CQRS)

// ❌ Generische Namen
class Helper { }
class Util { }
class Manager { }                 // Ohne Kontext
class Service { }                 // Ohne Kontext

// ❌ Technische Details in Namen
class MySQLUserRepository { }     // Nutze: DatabaseUserRepository
class RedisCache { }              // Nutze: CacheManager mit Redis-Implementation

// ❌ Unklare Abkürzungen
class UsrCtrl { }
class PrdMgr { }

// ❌ Vermischte Patterns
class ShowContact
{
    public function show(): ViewResult { }
    public function submit(): ActionResult { }  // Sollte SubmitContact sein
}
```

---

## Zusammenfassung

**Domain Code (Business Logic):**
- Keine redundanten Suffixe
- Ausdrucksstark und semantisch
- Beispiele: `ShowContact`, `SubmitContact`, `UserNotFound`, `Email`

**Infrastructure Code (Framework/Technical):**
- Explizite Suffixe für Klarheit
- Beispiele: `DatabaseException`, `HealthCheckCommand`, `FileHandler`, `UserRepository`

**Hybride Komponenten:**
- Nutze Namespace für primären Kontext
- Suffix nur wenn wirklich nötig
- Beispiele: `Handler` (verschiedene Typen), `Service` (immer mit Suffix)

Diese Conventions schaffen Konsistenz über das gesamte Framework und machen den Code selbstdokumentierend und wartbar.
