# Coding Standards

Diese Dokumentation beschreibt die Coding Standards, die bei der Entwicklung des Frameworks eingehalten werden sollten. Die Einhaltung dieser Standards gewährleistet einen konsistenten Codestil im gesamten Projekt und erleichtert die Zusammenarbeit zwischen Entwicklern.

## PHP-Standards

### PSR-Standards

Das Framework folgt den [PHP Standards Recommendations (PSR)](https://www.php-fig.org/psr/) des PHP Framework Interop Group (PHP-FIG):

- [PSR-1: Basic Coding Standard](https://www.php-fig.org/psr/psr-1/)
- [PSR-2: Coding Style Guide](https://www.php-fig.org/psr/psr-2/) und [PSR-12: Extended Coding Style](https://www.php-fig.org/psr/psr-12/) (ersetzt PSR-2)
- [PSR-4: Autoloading Standard](https://www.php-fig.org/psr/psr-4/)

### Allgemeine Richtlinien

#### Dateien

- Dateien MÜSSEN die UTF-8-Kodierung ohne BOM verwenden.
- Dateien SOLLTEN entweder Deklarationen (Klassen, Funktionen, Konstanten) ODER Nebeneffekte (z.B. Ausgaben, Änderungen an .ini-Einstellungen) enthalten, aber NICHT beides.
- Dateinamen MÜSSEN `PascalCase` für Klassen verwenden (z.B. `UserController.php`).
- Alle PHP-Dateien MÜSSEN mit einer einzelnen leeren Zeile enden.

#### PHP-Tags

- PHP-Code MUSS die langen Tags `<?php ?>` oder die kurzen Echo-Tags `<?= ?>` verwenden.
- Die schließenden Tags `?>` SOLLTEN bei Dateien, die nur PHP enthalten, weggelassen werden.

#### Zeichenkodierung und Zeilenumbrüche

- Der Code MUSS UTF-8 ohne BOM verwenden.
- Zeilenumbrüche MÜSSEN im Unix-Format (LF) sein.

### Namenskonventionen

#### Namespaces

- Namespaces MÜSSEN `PascalCase` verwenden.
- Der Basis-Namespace für das Framework ist `App\Framework`.
- Der Basis-Namespace für anwendungsspezifischen Code ist `App\Application`.

```php
namespace App\Framework\Http;
namespace App\Application\Controllers;
```

#### Klassen

- Klassennamen MÜSSEN `PascalCase` verwenden.
- Schnittstellen MÜSSEN mit dem Suffix `Interface` enden.
- Abstrakte Klassen SOLLTEN mit dem Präfix `Abstract` beginnen.
- Traits SOLLTEN mit dem Suffix `Trait` enden.

```php
class UserController
interface RepositoryInterface
abstract class AbstractController
trait LoggableTrait
```

#### Methoden und Funktionen

- Methoden- und Funktionsnamen MÜSSEN `camelCase` verwenden.
- Methoden SOLLTEN Verben sein, die ihre Aktion beschreiben.

```php
public function getUserById(int $id): ?User
public function createUser(array $data): User
public function updateUserProfile(User $user, array $data): bool
```

#### Eigenschaften und Variablen

- Eigenschaften und Variablen MÜSSEN `camelCase` verwenden.
- Private und geschützte Eigenschaften SOLLTEN NICHT mit einem Unterstrich beginnen.

```php
private string $firstName;
protected int $itemCount;
public bool $isActive;
```

#### Konstanten

- Klassenkonstanten MÜSSEN in `UPPER_CASE` mit Unterstrichen als Trennzeichen definiert werden.

```php
public const MAX_ATTEMPTS = 5;
private const DEFAULT_TIMEOUT = 30;
```

#### Enums

- Enum-Namen MÜSSEN `PascalCase` verwenden.
- Enum-Werte MÜSSEN `UPPER_CASE` mit Unterstrichen als Trennzeichen verwenden.

```php
enum HttpMethod
{
    case GET;
    case POST;
    case PUT;
    case DELETE;
}

enum LogLevel: string
{
    case DEBUG = 'debug';
    case INFO = 'info';
    case WARNING = 'warning';
    case ERROR = 'error';
}
```

### Codestruktur

#### Klassen

- Jede Klasse MUSS in einer eigenen Datei definiert werden.
- Die Struktur einer Klasse SOLLTE wie folgt sein:
  1. Namespace-Deklaration
  2. Verwendete Imports (alphabetisch sortiert)
  3. Klassendokumentation (PHPDoc)
  4. Klassendeklaration
  5. Konstanten (öffentlich, geschützt, privat)
  6. Eigenschaften (öffentlich, geschützt, privat)
  7. Konstruktor und Destruktor
  8. Öffentliche Methoden
  9. Geschützte Methoden
  10. Private Methoden

```php
<?php

namespace App\Framework\Database;

use App\Framework\Contracts\ConnectionInterface;
use App\Framework\Exceptions\DatabaseException;

/**
 * Database connection manager.
 */
class Connection implements ConnectionInterface
{
    /**
     * Default connection timeout in seconds.
     */
    public const DEFAULT_TIMEOUT = 30;
    
    /**
     * The active PDO connection.
     */
    private ?\PDO $pdo = null;
    
    /**
     * The database configuration.
     */
    private array $config;
    
    /**
     * Create a new database connection instance.
     */
    public function __construct(array $config)
    {
        $this->config = $config;
    }
    
    /**
     * Get the PDO connection.
     */
    public function getPdo(): \PDO
    {
        if ($this->pdo === null) {
            $this->connect();
        }
        
        return $this->pdo;
    }
    
    /**
     * Establish a database connection.
     */
    protected function connect(): void
    {
        // Implementation...
    }
    
    /**
     * Build the DSN string.
     */
    private function buildDsn(): string
    {
        // Implementation...
    }
}
```

#### Methoden

- Methoden SOLLTEN eine einzige Verantwortung haben (Single Responsibility Principle).
- Methoden SOLLTEN kurz sein und eine Sache gut machen.
- Methoden SOLLTEN früh zurückkehren, um die Verschachtelungstiefe zu reduzieren.

```php
// Gut
public function getUserById(int $id): ?User
{
    if ($id <= 0) {
        return null;
    }
    
    return $this->userRepository->find($id);
}

// Schlecht
public function getUserById(int $id): ?User
{
    if ($id > 0) {
        $user = $this->userRepository->find($id);
        if ($user !== null) {
            return $user;
        } else {
            return null;
        }
    } else {
        return null;
    }
}
```

### Typisierung

- Der Code MUSS strikte Typisierung verwenden.
- Jede Datei SOLLTE mit `declare(strict_types=1);` beginnen.
- Methoden und Funktionen MÜSSEN Typdeklarationen für Parameter und Rückgabewerte verwenden.
- Eigenschaften MÜSSEN Typdeklarationen verwenden.

```php
<?php

declare(strict_types=1);

namespace App\Framework\Http;

class Request
{
    private array $query;
    private array $request;
    
    public function __construct(array $query, array $request)
    {
        $this->query = $query;
        $this->request = $request;
    }
    
    public function query(string $key, mixed $default = null): mixed
    {
        return $this->query[$key] ?? $default;
    }
    
    public function input(string $key, mixed $default = null): mixed
    {
        return $this->request[$key] ?? $default;
    }
    
    public function has(string $key): bool
    {
        return isset($this->request[$key]);
    }
}
```

### Dokumentation

- Alle Klassen, Methoden, Eigenschaften und Konstanten MÜSSEN mit PHPDoc-Kommentaren dokumentiert werden.
- PHPDoc-Kommentare MÜSSEN eine Beschreibung und alle relevanten Tags enthalten.
- Komplexe Codeabschnitte SOLLTEN mit Inline-Kommentaren erklärt werden.

```php
/**
 * Represents an HTTP request.
 */
class Request
{
    /**
     * The query parameters.
     *
     * @var array<string, mixed>
     */
    private array $query;
    
    /**
     * Get a query parameter.
     *
     * @param string $key     The parameter key
     * @param mixed  $default The default value if the parameter does not exist
     *
     * @return mixed The parameter value or the default value
     */
    public function query(string $key, mixed $default = null): mixed
    {
        return $this->query[$key] ?? $default;
    }
}
```

### Fehlerbehandlung

- Exceptions SOLLTEN für außergewöhnliche Bedingungen verwendet werden.
- Benutzerdefinierte Exceptions SOLLTEN von einer Basis-Exception-Klasse erben.
- Exception-Nachrichten SOLLTEN klar und informativ sein.

```php
// Definieren einer benutzerdefinierten Exception
class DatabaseException extends \RuntimeException
{
    // ...
}

// Werfen einer Exception
if (!$this->isConnected()) {
    throw new DatabaseException('Database connection failed: ' . $this->getLastError());
}

// Fangen einer Exception
try {
    $user = $this->userRepository->find($id);
} catch (DatabaseException $e) {
    $this->logger->error('Database error: ' . $e->getMessage());
    throw new ServiceException('Could not retrieve user data', 0, $e);
}
```

## JavaScript-Standards

### Allgemeine Richtlinien

- JavaScript-Code SOLLTE [ESLint](https://eslint.org/) mit der Konfiguration des Projekts verwenden.
- ES6+ Features SOLLTEN verwendet werden.
- Semicolons MÜSSEN verwendet werden.

### Namenskonventionen

- Variablen und Funktionen MÜSSEN `camelCase` verwenden.
- Klassen MÜSSEN `PascalCase` verwenden.
- Konstanten MÜSSEN `UPPER_CASE` mit Unterstrichen als Trennzeichen verwenden.
- Private Eigenschaften und Methoden SOLLTEN mit einem Unterstrich beginnen.

```javascript
// Variablen
const maxItems = 10;
let currentIndex = 0;

// Konstanten
const MAX_RETRY_COUNT = 3;
const API_BASE_URL = 'https://api.example.com';

// Funktionen
function getUserData(userId) {
    // ...
}

// Klassen
class UserService {
    constructor(apiClient) {
        this._apiClient = apiClient;
    }
    
    async getUser(id) {
        return this._apiClient.get(`/users/${id}`);
    }
    
    _handleError(error) {
        console.error('API error:', error);
    }
}
```

### Codestruktur

- Jede Datei SOLLTE einen einzelnen Export haben.
- Imports SOLLTEN am Anfang der Datei stehen und nach Typ gruppiert werden.
- Funktionen SOLLTEN kurz sein und eine Sache gut machen.

```javascript
// Imports
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';

// Eigene Imports
import { UserService } from '../services/UserService';
import { ErrorBoundary } from '../components/ErrorBoundary';

// Komponente
function UserProfile({ userId }) {
    const [user, setUser] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    
    useEffect(() => {
        const fetchUser = async () => {
            try {
                setLoading(true);
                const userService = new UserService();
                const userData = await userService.getUser(userId);
                setUser(userData);
            } catch (err) {
                setError(err.message);
            } finally {
                setLoading(false);
            }
        };
        
        fetchUser();
    }, [userId]);
    
    if (loading) {
        return <div>Loading...</div>;
    }
    
    if (error) {
        return <div>Error: {error}</div>;
    }
    
    return (
        <div>
            <h1>{user.name}</h1>
            <p>{user.email}</p>
        </div>
    );
}

UserProfile.propTypes = {
    userId: PropTypes.string.isRequired
};

export default UserProfile;
```

## CSS-Standards

### Allgemeine Richtlinien

- CSS-Code SOLLTE [Stylelint](https://stylelint.io/) mit der Konfiguration des Projekts verwenden.
- CSS-Präprozessoren wie SASS oder LESS KÖNNEN verwendet werden.
- CSS-Klassen SOLLTEN nach dem BEM-Muster (Block, Element, Modifier) benannt werden.

### Namenskonventionen

- CSS-Klassen MÜSSEN `kebab-case` verwenden.
- BEM-Notation: `.block__element--modifier`

```css
/* Block */
.user-card {
    background-color: #fff;
    border-radius: 4px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    padding: 16px;
}

/* Element */
.user-card__avatar {
    border-radius: 50%;
    height: 64px;
    width: 64px;
}

/* Element */
.user-card__name {
    font-size: 18px;
    font-weight: bold;
    margin-top: 8px;
}

/* Modifier */
.user-card--premium {
    background-color: #f8f8f8;
    border: 1px solid #ddd;
}
```

### Codestruktur

- CSS-Regeln SOLLTEN nach Komponenten organisiert werden.
- Medienabfragen SOLLTEN am Ende jeder Komponente stehen.
- Vendor-Präfixe SOLLTEN automatisch mit Tools wie Autoprefixer hinzugefügt werden.

```css
/* Komponente */
.button {
    background-color: #007bff;
    border: none;
    border-radius: 4px;
    color: #fff;
    cursor: pointer;
    font-size: 16px;
    padding: 8px 16px;
    transition: background-color 0.2s;
}

.button:hover {
    background-color: #0069d9;
}

.button:focus {
    outline: none;
    box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}

.button--secondary {
    background-color: #6c757d;
}

.button--secondary:hover {
    background-color: #5a6268;
}

/* Medienabfragen */
@media (max-width: 768px) {
    .button {
        font-size: 14px;
        padding: 6px 12px;
    }
}
```

## Tools und Automatisierung

### Code-Linting

Das Projekt verwendet verschiedene Linting-Tools, um die Einhaltung der Coding Standards zu gewährleisten:

- [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) für PHP
- [ESLint](https://eslint.org/) für JavaScript
- [Stylelint](https://stylelint.io/) für CSS

### Automatische Formatierung

Das Projekt unterstützt automatische Codeformatierung mit:

- [PHP-CS-Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) für PHP
- [Prettier](https://prettier.io/) für JavaScript und CSS

### Verwendung der Tools

#### PHP_CodeSniffer

```bash
# Überprüfen des Codes
vendor/bin/phpcs src tests

# Automatisches Beheben von Problemen
vendor/bin/phpcbf src tests
```

#### PHP-CS-Fixer

```bash
# Überprüfen des Codes
vendor/bin/php-cs-fixer fix --dry-run --diff src

# Automatisches Beheben von Problemen
vendor/bin/php-cs-fixer fix src
```

#### ESLint

```bash
# Überprüfen des Codes
npm run lint:js

# Automatisches Beheben von Problemen
npm run lint:js:fix
```

#### Stylelint

```bash
# Überprüfen des Codes
npm run lint:css

# Automatisches Beheben von Problemen
npm run lint:css:fix
```

#### Prettier

```bash
# Formatieren von JavaScript und CSS
npm run format
```

## Weitere Informationen

- [Pull Request-Anleitung](pull-requests.md): Erfahren Sie, wie Sie Pull Requests erstellen und überprüfen.
- [Dokumentations-Anleitung](documentation.md): Erfahren Sie, wie Sie zur Dokumentation beitragen können.
- [Architekturübersicht](../architecture/overview.md): Überblick über die Architektur des Frameworks.
