# Validierungs-Anleitung

Diese Anleitung erklärt, wie das Validierungssystem des Frameworks funktioniert und wie Sie es effektiv nutzen können.

## Grundlagen der Validierung

Die Validierung ist ein wichtiger Teil jeder Webanwendung, da sie sicherstellt, dass die Daten, die von Benutzern eingegeben werden, den erwarteten Regeln entsprechen. Das Framework bietet ein leistungsstarkes und flexibles Validierungssystem, das einfach zu verwenden ist.

### Validierung in Controllern

Die einfachste Möglichkeit, Daten zu validieren, ist die Verwendung der `validate`-Methode in Controllern:

```php
public function store(Request $request): Response
{
    $this->validate($request, [
        'name' => 'required|string|max:255',
        'email' => 'required|email|unique:users,email',
        'password' => 'required|string|min:8|confirmed',
        'age' => 'integer|min:18',
    ]);
    
    // Die Validierung wurde bestanden, fahren Sie mit der Speicherung fort
    $user = User::create($request->only(['name', 'email', 'password']));
    
    return $this->redirect('/users')->with('success', 'Benutzer erstellt');
}
```

Wenn die Validierung fehlschlägt, wird automatisch eine Antwort mit den Validierungsfehlern zurückgegeben:

- Bei einer regulären Anfrage wird der Benutzer zur vorherigen Seite umgeleitet, und die Validierungsfehler werden in der Session gespeichert.
- Bei einer AJAX-Anfrage wird eine JSON-Antwort mit den Validierungsfehlern und dem HTTP-Statuscode 422 zurückgegeben.

### Manuelle Validierung

Sie können auch den Validator direkt verwenden, um mehr Kontrolle über den Validierungsprozess zu haben:

```php
use App\Framework\Validation\Validator;

public function store(Request $request): Response
{
    $validator = new Validator($request->all(), [
        'name' => 'required|string|max:255',
        'email' => 'required|email|unique:users,email',
        'password' => 'required|string|min:8|confirmed',
    ]);
    
    if ($validator->fails()) {
        $errors = $validator->errors();
        
        // Fehler behandeln
        return $this->back()->withErrors($errors);
    }
    
    // Die Validierung wurde bestanden, fahren Sie mit der Speicherung fort
    $user = User::create($request->only(['name', 'email', 'password']));
    
    return $this->redirect('/users')->with('success', 'Benutzer erstellt');
}
```

## Validierungsregeln

Das Framework bietet eine Vielzahl von Validierungsregeln, die Sie verwenden können, um Ihre Daten zu validieren.

### Grundlegende Regeln

- `required`: Das Feld muss vorhanden sein und darf nicht leer sein.
- `string`: Das Feld muss ein String sein.
- `integer`: Das Feld muss eine Ganzzahl sein.
- `numeric`: Das Feld muss eine Zahl sein (Ganzzahl oder Dezimalzahl).
- `boolean`: Das Feld muss ein Boolean sein (`true`, `false`, `1`, `0`, `"1"`, `"0"`).
- `array`: Das Feld muss ein Array sein.
- `date`: Das Feld muss ein gültiges Datum sein.
- `email`: Das Feld muss eine gültige E-Mail-Adresse sein.
- `url`: Das Feld muss eine gültige URL sein.
- `ip`: Das Feld muss eine gültige IP-Adresse sein.
- `json`: Das Feld muss ein gültiger JSON-String sein.
- `alpha`: Das Feld darf nur Buchstaben enthalten.
- `alpha_num`: Das Feld darf nur Buchstaben und Zahlen enthalten.
- `alpha_dash`: Das Feld darf nur Buchstaben, Zahlen, Bindestriche und Unterstriche enthalten.

### Größenregeln

- `min:value`: Das Feld muss mindestens `value` groß sein.
  - Für Strings: Die Anzahl der Zeichen.
  - Für Zahlen: Der Mindestwert.
  - Für Arrays: Die Mindestanzahl der Elemente.
  - Für Dateien: Die Mindestgröße in Kilobyte.
- `max:value`: Das Feld darf höchstens `value` groß sein.
- `size:value`: Das Feld muss genau `value` groß sein.
- `between:min,max`: Das Feld muss zwischen `min` und `max` liegen.

### Vergleichsregeln

- `same:field`: Das Feld muss den gleichen Wert wie `field` haben.
- `different:field`: Das Feld muss einen anderen Wert als `field` haben.
- `gt:field`: Das Feld muss größer als `field` sein.
- `gte:field`: Das Feld muss größer oder gleich `field` sein.
- `lt:field`: Das Feld muss kleiner als `field` sein.
- `lte:field`: Das Feld muss kleiner oder gleich `field` sein.

### Datenbankregeln

- `unique:table,column,except,idColumn`: Das Feld muss in der angegebenen Tabelle und Spalte einzigartig sein.
  - `table`: Der Name der Tabelle.
  - `column`: Der Name der Spalte (standardmäßig der Feldname).
  - `except`: Die ID des Datensatzes, der bei der Überprüfung ignoriert werden soll (optional).
  - `idColumn`: Der Name der ID-Spalte (standardmäßig `id`).
- `exists:table,column`: Das Feld muss in der angegebenen Tabelle und Spalte existieren.

### Dateiregeln

- `file`: Das Feld muss eine erfolgreich hochgeladene Datei sein.
- `image`: Das Feld muss ein Bild sein (jpeg, png, bmp, gif, svg).
- `mimes:jpeg,png,...`: Das Feld muss eine Datei mit einem der angegebenen MIME-Typen sein.
- `mimetypes:text/plain,...`: Das Feld muss eine Datei mit einem der angegebenen MIME-Typen sein.
- `dimensions:min_width=100,max_width=1000,min_height=100,max_height=1000,width=100,height=100,ratio=1/1`: Das Feld muss ein Bild sein, das den angegebenen Dimensionen entspricht.

### Bedingte Regeln

- `required_if:anotherfield,value,...`: Das Feld ist erforderlich, wenn `anotherfield` einen der angegebenen Werte hat.
- `required_unless:anotherfield,value,...`: Das Feld ist erforderlich, es sei denn, `anotherfield` hat einen der angegebenen Werte.
- `required_with:foo,bar,...`: Das Feld ist erforderlich, wenn eines der anderen angegebenen Felder vorhanden ist.
- `required_with_all:foo,bar,...`: Das Feld ist erforderlich, wenn alle anderen angegebenen Felder vorhanden sind.
- `required_without:foo,bar,...`: Das Feld ist erforderlich, wenn eines der anderen angegebenen Felder nicht vorhanden ist.
- `required_without_all:foo,bar,...`: Das Feld ist erforderlich, wenn alle anderen angegebenen Felder nicht vorhanden sind.

### Formatregeln

- `date_format:format`: Das Feld muss dem angegebenen Datumsformat entsprechen.
- `regex:pattern`: Das Feld muss dem angegebenen regulären Ausdruck entsprechen.
- `not_regex:pattern`: Das Feld darf nicht dem angegebenen regulären Ausdruck entsprechen.

### Bestätigungsregeln

- `confirmed`: Das Feld muss ein Bestätigungsfeld haben (z.B. `password_confirmation` für das Feld `password`).
- `accepted`: Das Feld muss akzeptiert werden (yes, on, 1, true).

### Spezielle Regeln

- `nullable`: Das Feld darf `null` sein.
- `present`: Das Feld muss im Eingabedaten vorhanden sein, kann aber leer sein.
- `sometimes`: Die Regel wird nur angewendet, wenn das Feld vorhanden ist.

## Benutzerdefinierte Validierungsnachrichten

Sie können benutzerdefinierte Validierungsnachrichten angeben, um die Standardnachrichten zu überschreiben:

```php
$this->validate($request, [
    'name' => 'required|string|max:255',
    'email' => 'required|email|unique:users,email',
    'password' => 'required|string|min:8|confirmed',
], [
    'name.required' => 'Der Name ist erforderlich',
    'email.unique' => 'Diese E-Mail-Adresse wird bereits verwendet',
    'password.min' => 'Das Passwort muss mindestens 8 Zeichen lang sein',
]);
```

Sie können auch Platzhalter in Ihren Nachrichten verwenden:

- `:attribute`: Der Name des Feldes.
- `:min`: Der Mindestwert.
- `:max`: Der Maximalwert.
- `:size`: Die erforderliche Größe.
- `:values`: Die gültigen Werte.
- `:other`: Der Name des anderen Feldes.

```php
'min' => 'Das Feld :attribute muss mindestens :min Zeichen enthalten',
```

## Validierung von Arrays

Sie können auch verschachtelte Arrays validieren:

```php
$this->validate($request, [
    'user.name' => 'required|string|max:255',
    'user.email' => 'required|email|unique:users,email',
    'addresses.*.street' => 'required|string|max:255',
    'addresses.*.city' => 'required|string|max:255',
    'addresses.*.country' => 'required|string|max:255',
]);
```

In diesem Beispiel wird erwartet, dass `user` ein Array mit den Schlüsseln `name` und `email` ist, und `addresses` ein Array von Arrays ist, wobei jedes innere Array die Schlüssel `street`, `city` und `country` hat.

## Benutzerdefinierte Validierungsregeln

### Erstellen einer benutzerdefinierten Regel

Sie können benutzerdefinierte Validierungsregeln erstellen, indem Sie die `Rule`-Schnittstelle implementieren:

```php
use App\Framework\Validation\Rule;

class StrongPassword implements Rule
{
    public function passes($attribute, $value): bool
    {
        // Überprüfen, ob das Passwort stark ist
        return preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/', $value) === 1;
    }
    
    public function message(): string
    {
        return 'Das Passwort muss mindestens 8 Zeichen lang sein und mindestens einen Großbuchstaben, einen Kleinbuchstaben, eine Zahl und ein Sonderzeichen enthalten.';
    }
}
```

### Verwenden einer benutzerdefinierten Regel

Sie können Ihre benutzerdefinierte Regel wie folgt verwenden:

```php
use App\Framework\Validation\Validator;

$validator = new Validator($request->all(), [
    'password' => ['required', 'string', new StrongPassword()],
]);
```

Oder in einem Controller:

```php
$this->validate($request, [
    'password' => ['required', 'string', new StrongPassword()],
]);
```

## Validierung mit Form Requests

Für komplexe Validierungslogik können Sie Form Request-Klassen erstellen:

```php
use App\Framework\Http\FormRequest;

class CreateUserRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|string|min:8|confirmed',
        ];
    }
    
    public function messages(): array
    {
        return [
            'name.required' => 'Der Name ist erforderlich',
            'email.unique' => 'Diese E-Mail-Adresse wird bereits verwendet',
            'password.min' => 'Das Passwort muss mindestens 8 Zeichen lang sein',
        ];
    }
    
    public function authorize(): bool
    {
        return $this->user()->hasPermission('create-users');
    }
}
```

Dann können Sie die Form Request-Klasse in Ihrem Controller verwenden:

```php
public function store(CreateUserRequest $request): Response
{
    // Die Validierung wurde bereits durchgeführt
    
    $user = User::create($request->validated());
    
    return $this->redirect('/users')->with('success', 'Benutzer erstellt');
}
```

Die `validated`-Methode gibt nur die validierten Felder zurück, was nützlich ist, um Massenänderungen zu verhindern.

## Validierung von Dateien

Das Framework bietet spezielle Regeln für die Validierung von Dateien:

```php
$this->validate($request, [
    'avatar' => 'required|file|image|max:2048', // max in Kilobyte
    'document' => 'required|file|mimes:pdf,doc,docx|max:10240',
]);
```

## Validierung von Daten außerhalb von Requests

Sie können den Validator auch verwenden, um Daten zu validieren, die nicht aus einer HTTP-Anfrage stammen:

```php
use App\Framework\Validation\Validator;

$data = [
    'name' => 'John Doe',
    'email' => 'john@example.com',
];

$validator = new Validator($data, [
    'name' => 'required|string|max:255',
    'email' => 'required|email',
]);

if ($validator->fails()) {
    $errors = $validator->errors();
    // Fehler behandeln
} else {
    $validatedData = $validator->validated();
    // Mit validierten Daten fortfahren
}
```

## Validierung in JavaScript

Das Framework bietet auch eine Möglichkeit, Validierungsregeln in JavaScript zu verwenden, um clientseitige Validierung zu ermöglichen:

```php
// In Ihrer View
<script>
    const rules = <?= json_encode($validator->jsRules()) ?>;
    const messages = <?= json_encode($validator->jsMessages()) ?>;
    
    // Verwenden Sie die Regeln mit Ihrer bevorzugten JavaScript-Validierungsbibliothek
</script>
```

## Validierung von Abhängigkeiten

Manchmal hängt die Validierung eines Feldes vom Wert eines anderen Feldes ab. Sie können benutzerdefinierte Regeln verwenden, um diese Art von Validierung zu implementieren:

```php
$this->validate($request, [
    'payment_type' => 'required|in:credit_card,paypal',
    'card_number' => 'required_if:payment_type,credit_card|string|size:16',
    'card_expiry' => 'required_if:payment_type,credit_card|date_format:m/y',
    'card_cvv' => 'required_if:payment_type,credit_card|string|size:3',
    'paypal_email' => 'required_if:payment_type,paypal|email',
]);
```

## Validierung mit Bedingungen

Sie können auch komplexere Bedingungen für die Validierung definieren:

```php
$validator = new Validator($request->all(), [
    'name' => 'required|string|max:255',
    'email' => 'required|email',
]);

$validator->sometimes('phone', 'required|string|size:10', function ($input) {
    return $input->contact_method === 'phone';
});

$validator->sometimes('address', 'required|string|max:255', function ($input) {
    return $input->requires_shipping === true;
});
```

## Validierung von Datenbanken

Das Framework bietet Regeln für die Validierung von Datenbanken:

```php
$this->validate($request, [
    'email' => 'required|email|unique:users,email',
    'username' => 'required|string|unique:users,username',
    'category_id' => 'required|integer|exists:categories,id',
]);
```

Bei der Aktualisierung eines Datensatzes möchten Sie möglicherweise den aktuellen Datensatz von der Einzigartigkeit ausschließen:

```php
$this->validate($request, [
    'email' => 'required|email|unique:users,email,' . $userId,
    'username' => 'required|string|unique:users,username,' . $userId,
]);
```

## Fehlerbehandlung

### Zugriff auf Validierungsfehler

Wenn die Validierung fehlschlägt, können Sie auf die Fehler zugreifen:

```php
$validator = new Validator($request->all(), [
    'name' => 'required|string|max:255',
    'email' => 'required|email|unique:users,email',
]);

if ($validator->fails()) {
    $errors = $validator->errors();
    
    // Alle Fehler abrufen
    $allErrors = $errors->all();
    
    // Fehler für ein bestimmtes Feld abrufen
    $nameErrors = $errors->get('name');
    
    // Ersten Fehler für ein bestimmtes Feld abrufen
    $firstNameError = $errors->first('name');
    
    // Prüfen, ob ein Feld Fehler hat
    $hasNameErrors = $errors->has('name');
}
```

### Anzeigen von Validierungsfehlern in Views

In Ihren Views können Sie die Validierungsfehler wie folgt anzeigen:

```php
<?php if ($errors->has('name')): ?>
    <div class="error"><?= $errors->first('name') ?></div>
<?php endif; ?>
```

Oder alle Fehler anzeigen:

```php
<?php if ($errors->any()): ?>
    <div class="alert alert-danger">
        <ul>
            <?php foreach ($errors->all() as $error): ?>
                <li><?= $error ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
<?php endif; ?>
```

## Beste Praktiken

### Wiederverwendung von Validierungsregeln

Wenn Sie dieselben Validierungsregeln in mehreren Controllern verwenden, sollten Sie sie in eine separate Klasse auslagern:

```php
class UserValidationRules
{
    public static function forCreation(): array
    {
        return [
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|string|min:8|confirmed',
        ];
    }
    
    public static function forUpdate(int $userId): array
    {
        return [
            'name' => 'string|max:255',
            'email' => 'email|unique:users,email,' . $userId,
        ];
    }
}
```

Dann können Sie diese Regeln in Ihren Controllern verwenden:

```php
public function store(Request $request): Response
{
    $this->validate($request, UserValidationRules::forCreation());
    
    // ...
}

public function update(Request $request, int $id): Response
{
    $this->validate($request, UserValidationRules::forUpdate($id));
    
    // ...
}
```

### Validierung in Modellen

Sie können Validierungsregeln auch in Ihren Modellen definieren:

```php
class User extends Model
{
    public static function validationRules(): array
    {
        return [
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|string|min:8',
        ];
    }
    
    public static function updateValidationRules(int $userId): array
    {
        return [
            'name' => 'string|max:255',
            'email' => 'email|unique:users,email,' . $userId,
        ];
    }
}
```

Dann können Sie diese Regeln in Ihren Controllern verwenden:

```php
public function store(Request $request): Response
{
    $this->validate($request, User::validationRules());
    
    // ...
}

public function update(Request $request, int $id): Response
{
    $this->validate($request, User::updateValidationRules($id));
    
    // ...
}
```

## Weitere Informationen

- [Controller-Anleitung](controllers.md): Erfahren Sie mehr über Controller und wie sie mit der Validierung interagieren.
- [Form Request-Anleitung](form-requests.md): Erfahren Sie mehr über Form Requests und wie sie die Validierung vereinfachen können.
- [Datenbank-Anleitung](database.md): Erfahren Sie mehr über Datenbankoperationen und wie sie mit der Validierung interagieren.
- [Architekturübersicht](../architecture/overview.md): Überblick über die Architektur des Frameworks.
