# LiveComponents Best Practices

## Template-System Philosophie

**Grundprinzip**: Templates sollten **nur für die Darstellung** zuständig sein, nicht für Logik.

### ✅ Was Templates können

- **Variable Substitution**: `{{variableName}}`
- **Conditional Rendering**: `{{#if condition}}...{{/if}}`
- **Loops**: `{{#each items}}...{{/each}}`
- **Nested Properties**: `{{user.name}}`, `{{item.value}}`

### ❌ Was Templates NICHT können

- Komplexe Expressions: `{{user.role === 'admin' && user.active}}`
- Berechnungen: `{{count * 2}}`, `{{items.length}}`
- Method Calls: `{{formatDate(created)}}`, `{{user.getName()}}`
- Vergleichsoperatoren in Platzhaltern: `{{price > 100}}`

## Best Practice: Daten im Component vorbereiten

### Anti-Pattern ❌

```php
// Component
public function getRenderData(): ComponentRenderData
{
    return new ComponentRenderData('user-card', [
        'user' => $this->user,
        'permissions' => $this->permissions
    ]);
}
```

```html
<!-- Template mit komplexer Logik -->
{{#if user.role}}
    {{#if user.role === 'admin'}}
        {{#if user.isActive}}
            <span class="badge">{{permissions.length}} Permissions</span>
        {{/if}}
    {{/if}}
{{/if}}
```

**Probleme:**
- ❌ Logik im Template schwer testbar
- ❌ Template-Syntax unterstützt keine Vergleichsoperatoren
- ❌ Keine Type Safety
- ❌ Schwer zu debuggen

### Best Practice ✅

```php
// Component - Daten vollständig vorbereiten
public function getRenderData(): ComponentRenderData
{
    return new ComponentRenderData('user-card', [
        'user' => $this->user,
        'showAdminBadge' => $this->shouldShowAdminBadge(),
        'permissionCount' => $this->getPermissionCount(),
        'badgeClass' => $this->getBadgeClass(),
        'badgeText' => $this->getBadgeText()
    ]);
}

private function shouldShowAdminBadge(): bool
{
    return $this->user->role === 'admin' && $this->user->isActive;
}

private function getPermissionCount(): int
{
    return count($this->permissions);
}

private function getBadgeClass(): string
{
    return $this->user->isActive ? 'badge-success' : 'badge-secondary';
}

private function getBadgeText(): string
{
    $count = $this->getPermissionCount();
    return "{$count} Permission" . ($count !== 1 ? 's' : '');
}
```

```html
<!-- Template - nur Darstellung -->
{{#if showAdminBadge}}
    <span class="badge {{badgeClass}}">{{badgeText}}</span>
{{/if}}
```

**Vorteile:**
- ✅ Business-Logik testbar in Component
- ✅ Template einfach und lesbar
- ✅ Type Safety durch PHP
- ✅ Einfach zu debuggen
- ✅ Wiederverwendbare Component-Methoden

## Praktische Beispiele

### Beispiel 1: Conditional Rendering

**❌ Anti-Pattern:**
```html
{{#if user.orders.length > 0}}
    <div>User has {{user.orders.length}} orders</div>
{{/if}}
```

**✅ Best Practice:**
```php
// Component
public function getRenderData(): ComponentRenderData
{
    return new ComponentRenderData('user-summary', [
        'hasOrders' => $this->hasOrders(),
        'orderCount' => $this->getOrderCount(),
        'orderText' => $this->getOrderText()
    ]);
}

private function hasOrders(): bool
{
    return count($this->user->orders) > 0;
}

private function getOrderCount(): int
{
    return count($this->user->orders);
}

private function getOrderText(): string
{
    $count = $this->getOrderCount();
    return "User has {$count} order" . ($count !== 1 ? 's' : '');
}
```

```html
<!-- Template -->
{{#if hasOrders}}
    <div>{{orderText}}</div>
{{/if}}
```

### Beispiel 2: Formatierung & Berechnungen

**❌ Anti-Pattern:**
```html
<div class="price">€ {{price * 1.19}}</div>
<div class="date">{{created.format('d.m.Y')}}</div>
```

**✅ Best Practice:**
```php
// Component
public function getRenderData(): ComponentRenderData
{
    return new ComponentRenderData('product-card', [
        'priceWithTax' => $this->getPriceWithTax(),
        'formattedDate' => $this->getFormattedDate(),
        'priceDisplay' => $this->getPriceDisplay()
    ]);
}

private function getPriceWithTax(): float
{
    return $this->price * 1.19;
}

private function getFormattedDate(): string
{
    return $this->created->format('d.m.Y');
}

private function getPriceDisplay(): string
{
    return '€ ' . number_format($this->getPriceWithTax(), 2, ',', '.');
}
```

```html
<!-- Template -->
<div class="price">{{priceDisplay}}</div>
<div class="date">{{formattedDate}}</div>
```

### Beispiel 3: CSS-Klassen basierend auf Status

**❌ Anti-Pattern:**
```html
<div class="status {{status === 'active' ? 'status-active' : 'status-inactive'}}">
    {{status}}
</div>
```

**✅ Best Practice:**
```php
// Component
public function getRenderData(): ComponentRenderData
{
    return new ComponentRenderData('status-badge', [
        'statusClass' => $this->getStatusClass(),
        'statusText' => $this->getStatusText(),
        'statusIcon' => $this->getStatusIcon()
    ]);
}

private function getStatusClass(): string
{
    return match($this->status) {
        'active' => 'status-active',
        'pending' => 'status-pending',
        'inactive' => 'status-inactive',
        default => 'status-unknown'
    };
}

private function getStatusText(): string
{
    return ucfirst($this->status);
}

private function getStatusIcon(): string
{
    return match($this->status) {
        'active' => '✓',
        'pending' => '⏳',
        'inactive' => '✗',
        default => '?'
    };
}
```

```html
<!-- Template -->
<div class="status {{statusClass}}">
    <span class="icon">{{statusIcon}}</span>
    {{statusText}}
</div>
```

### Beispiel 4: Listen mit berechneten Werten

**❌ Anti-Pattern:**
```html
{{#each items}}
    <div class="item">
        {{name}} - {{price * quantity}} €
        {{#if inStock && quantity > 0}}
            <span class="available">Available</span>
        {{/if}}
    </div>
{{/each}}
```

**✅ Best Practice:**
```php
// Component
public function getRenderData(): ComponentRenderData
{
    return new ComponentRenderData('order-items', [
        'items' => $this->prepareItems()
    ]);
}

private function prepareItems(): array
{
    return array_map(function($item) {
        return [
            'name' => $item->name,
            'totalPrice' => $this->formatPrice($item->price * $item->quantity),
            'showAvailable' => $item->inStock && $item->quantity > 0,
            'itemClass' => $item->inStock ? 'item-available' : 'item-unavailable'
        ];
    }, $this->items);
}

private function formatPrice(float $price): string
{
    return number_format($price, 2, ',', '.') . ' €';
}
```

```html
<!-- Template -->
{{#each items}}
    <div class="item {{itemClass}}">
        {{name}} - {{totalPrice}}
        {{#if showAvailable}}
            <span class="available">Available</span>
        {{/if}}
    </div>
{{/each}}
```

## LiveComponent-Spezifische Patterns

### Pattern 1: Event-Daten vorbereiten

```php
// Component
public function increment(): ComponentUpdate
{
    $oldValue = $this->initialData['count'];
    $newValue = $oldValue + 1;

    return new ComponentUpdate(
        newState: ['count' => $newValue],
        events: [
            new ComponentEvent(
                name: 'counter:changed',
                data: [
                    'old_value' => $oldValue,
                    'new_value' => $newValue,
                    'change' => '+1',
                    'isEven' => $newValue % 2 === 0,
                    'isMilestone' => $newValue % 10 === 0
                ]
            )
        ]
    );
}
```

### Pattern 2: Conditional Actions basierend auf State

```php
// Component
public function getRenderData(): ComponentRenderData
{
    $count = $this->initialData['count'];

    return new ComponentRenderData('counter', [
        'count' => $count,
        'canDecrement' => $count > 0,
        'canIncrement' => $count < 100,
        'showReset' => $count !== 0,
        'decrementClass' => $count > 0 ? 'btn-danger' : 'btn-disabled',
        'incrementClass' => $count < 100 ? 'btn-success' : 'btn-disabled'
    ]);
}
```

```html
<!-- Template -->
<div class="counter">
    <h2>Count: {{count}}</h2>

    {{#if canDecrement}}
        <button data-live-action="decrement" class="{{decrementClass}}">
            - Decrement
        </button>
    {{/if}}

    {{#if canIncrement}}
        <button data-live-action="increment" class="{{incrementClass}}">
            + Increment
        </button>
    {{/if}}

    {{#if showReset}}
        <button data-live-action="reset" class="btn-secondary">
            Reset
        </button>
    {{/if}}
</div>
```

### Pattern 3: Cache-optimierte Datenvorbereitung

```php
// Component mit Caching
final readonly class StatsComponent implements LiveComponentContract, Cacheable
{
    public function getRenderData(): ComponentRenderData
    {
        // Teure Berechnung einmal durchführen
        $stats = $this->computeExpensiveStats();

        // Alle Darstellungs-Daten vorbereiten
        return new ComponentRenderData('stats', [
            'stats' => $stats,
            'totalUsers' => number_format($stats['total_users'], 0, ',', '.'),
            'activeSessionsText' => $this->getActiveSessionsText($stats['active_sessions']),
            'revenueFormatted' => $this->formatRevenue($stats['revenue']),
            'showAlert' => $stats['total_users'] > 5000,
            'alertClass' => $stats['total_users'] > 5000 ? 'alert-warning' : 'alert-info'
        ]);
    }

    private function getActiveSessionsText(int $count): string
    {
        return "{$count} active session" . ($count !== 1 ? 's' : '');
    }

    private function formatRevenue(int $revenue): string
    {
        return '€ ' . number_format($revenue, 2, ',', '.');
    }
}
```

## Template-System Referenz

### Unterstützte Syntax

**Variable Substitution:**
```html
{{variableName}}
{{object.property}}
{{array.0.name}}
```

**Conditionals:**
```html
{{#if condition}}
    Content when true
{{/if}}

{{#if condition}}
    True content
{{else}}
    False content
{{/if}}
```

**Loops:**
```html
{{#each items}}
    {{name}} - {{value}}
{{/each}}
```

**Nested Templates:**
```html
{{#if user}}
    {{#each user.orders}}
        <div>Order {{id}}: {{total}}</div>
    {{/each}}
{{/if}}
```

## Zusammenfassung

**Goldene Regeln:**

1. ✅ **Bereite alle Daten im Component vor** - keine Logik im Template
2. ✅ **Verwende aussagekräftige Property-Namen** - `showAdminBadge` statt `isAdminAndActive`
3. ✅ **Formatiere Daten in PHP** - `priceFormatted` statt Berechnung im Template
4. ✅ **CSS-Klassen vorbereiten** - `statusClass` statt Conditional im Template
5. ✅ **Boolean Flags für Conditionals** - `hasOrders` statt `orders.length > 0`
6. ✅ **Listen vorverarbeiten** - Arrays mit allen Display-Daten vorbereiten
7. ✅ **Teste Component-Logik** - nicht Template-Rendering

**Das Template-System ist bewusst einfach gehalten, um saubere Separation of Concerns zu fördern.**
