# XComponentProcessor - Unified Component Syntax

**Einheitliche `<x-*>` Syntax für LiveComponents und HTML Components im Custom PHP Framework.**

## Übersicht

Der `XComponentProcessor` ist ein DOM-Processor, der eine einheitliche Syntax für **zwei verschiedene Component-Typen** bietet:

1. **LiveComponents** (Interaktiv/Stateful) - Komponenten mit #[LiveComponent] Attribut
2. **HTML Components** (Statisch) - Komponenten mit #[ComponentName] Attribut

**Unified Syntax**: `<x-componentname>`

```html
<!-- LiveComponent (Interactive) -->
<x-datatable id="users" page="1" pageSize="25" />

<!-- HTML Component (Static) -->
<x-button variant="primary">Click me</x-button>
```

## Architektur

### Component Auto-Detection Flow

```
<x-componentname> Syntax
         ↓
XComponentProcessor
         ↓
   ┌─────┴─────┐
   ↓           ↓
LiveComponent? HTML Component?
   ↓           ↓
   YES         NO
   ↓           ↓
Process as    Process as
Interactive   Static
```

**Detection Priority**:
1. **LiveComponent** prüfen (via `ComponentRegistry::isRegistered()`)
2. **HTML Component** prüfen (via `HtmlComponentRegistry::has()`)
3. **Not Found** → Helpful error message

### Klassen-Struktur

```php
final readonly class XComponentProcessor implements DomProcessor
{
    public function __construct(
        private ComponentRegistry $liveComponentRegistry,
        private HtmlComponentRegistry $htmlComponentRegistry,
        private ComponentMetadataCache $metadataCache,
        private DomComponentService $componentService
    ) {}

    public function process(DomWrapper $dom, RenderContext $context): DomWrapper
    {
        // Find all <x-*> elements
        $xComponents = $this->findXComponents($dom);

        foreach ($xComponents as $element) {
            try {
                $this->processXComponent($dom, $element, $context);
            } catch (\Throwable $e) {
                $this->handleProcessingError($dom, $element, $e);
            }
        }

        return $dom;
    }
}
```

## LiveComponents (Interactive)

### Verwendung

```html
<!-- LiveComponent mit Props -->
<x-datatable
    id="users-table"
    page="1"
    pageSize="25"
    sortBy="created_at"
    sortOrder="desc"
/>

<!-- LiveComponent ohne explizite ID (auto-generiert) -->
<x-counter initialValue="0" />

<!-- Mit JSON Props -->
<x-chart
    data='[{"x":1,"y":10},{"x":2,"y":20}]'
    options='{"type":"line","legend":true}'
/>
```

### LiveComponent Definition

```php
use App\Framework\LiveComponents\Attributes\LiveComponent;
use App\Framework\LiveComponents\Attributes\LiveProp;

#[LiveComponent(name: 'datatable')]
final class DataTableComponent
{
    #[LiveProp]
    public int $page = 1;

    #[LiveProp]
    public int $pageSize = 25;

    #[LiveProp]
    public string $sortBy = 'id';

    #[LiveProp]
    public string $sortOrder = 'asc';

    public function render(): RenderData
    {
        $data = $this->loadData();

        return new RenderData(
            template: 'components/datatable',
            data: [
                'rows' => $data,
                'currentPage' => $this->page,
                'totalPages' => $this->calculateTotalPages()
            ]
        );
    }
}
```

### Processing Flow

```
<x-datatable id="users" page="1" pageSize="25" />
         ↓
1. Extract component name: "datatable"
2. Check ComponentRegistry: isRegistered("datatable") → true
3. Extract props: ["id" => "users", "page" => "1", "pageSize" => "25"]
4. Type coercion: ["id" => "users", "page" => 1, "pageSize" => 25]
5. Validate props gegen ComponentMetadata
6. Create ComponentId: ComponentId::create("datatable", "users")
7. Create ComponentData: ComponentData::fromArray(["page" => 1, "pageSize" => 25])
8. Resolve component: $registry->resolve($componentId, $initialState)
9. Render with wrapper: $registry->renderWithWrapper($component)
10. Replace <x-datatable> with rendered HTML
         ↓
<div data-component-id="datatable:users" data-component-state="...">
    <!-- Rendered component HTML -->
</div>
```

### Type Coercion (LiveComponents only)

Der XComponentProcessor führt automatische **Type Coercion** für LiveComponent-Props durch:

```php
// Input: HTML Attributes (always strings)
<x-component
    stringProp="text"
    intProp="123"
    floatProp="12.5"
    boolTrue="true"
    boolFalse="false"
    nullProp="null"
    arrayProp="[1,2,3]"
    objectProp='{"key":"value"}'
/>

// Output: Coerced PHP types
[
    'stringProp' => 'text',              // string
    'intProp' => 123,                    // int
    'floatProp' => 12.5,                 // float
    'boolTrue' => true,                  // bool
    'boolFalse' => false,                // bool
    'nullProp' => null,                  // null
    'arrayProp' => [1, 2, 3],           // array
    'objectProp' => ['key' => 'value']   // array
]
```

**Coercion Rules**:
- `"true"` / `"false"` → `bool`
- `"null"` → `null`
- `"123"` → `int`
- `"12.5"` → `float`
- `"[...]"` / `"{...}"` → JSON decode
- Alles andere → `string`

### Prop Validation

```php
// Component Definition
#[LiveComponent(name: 'counter')]
final class CounterComponent
{
    #[LiveProp]
    public int $initialValue = 0;

    #[LiveProp]
    public int $step = 1;
}

// ✅ Valid Usage
<x-counter initialValue="10" step="2" />

// ❌ Invalid: Unknown prop 'invalidProp'
<x-counter invalidProp="test" />
// → Development: Error message
// → Production: Silent removal

// ❌ Invalid: Wrong type (caught at component level)
<x-counter initialValue="not-a-number" />
// → Type coercion to string, component validation throws error
```

**Validation Error (Development Mode)**:
```html
<div style="border:2px solid red;padding:1rem;background:#fee;color:#c00;">
    <strong>XComponentProcessor Error:</strong><br>
    <pre>LiveComponent 'counter' has no property 'invalidProp'.
Available properties: initialValue, step</pre>
    <small>Component: x-counter</small>
</div>
```

## HTML Components (Static)

### Verwendung

```html
<!-- Static Button Component -->
<x-button variant="primary">Click me</x-button>

<!-- Card Component with content -->
<x-card title="User Profile">
    <p>User information goes here</p>
</x-card>

<!-- Badge Component -->
<x-badge color="blue">New</x-badge>
```

### HTML Component Definition

```php
use App\Framework\View\Attributes\ComponentName;

#[ComponentName('button')]
final readonly class ButtonComponent
{
    public function render(string $content, array $attributes): string
    {
        $variant = $attributes['variant'] ?? 'default';
        $class = "btn btn-{$variant}";

        return "<button class=\"{$class}\">{$content}</button>";
    }
}
```

### Processing Flow

```
<x-button variant="primary">Click me</x-button>
         ↓
1. Extract component name: "button"
2. Check ComponentRegistry: isRegistered("button") → false
3. Check HtmlComponentRegistry: has("button") → true
4. Extract content: "Click me"
5. Extract attributes: ["variant" => "primary"] (as strings)
6. Render: $registry->render("button", "Click me", ["variant" => "primary"])
7. Replace <x-button> with rendered HTML
         ↓
<button class="btn btn-primary">Click me</button>
```

### Unterschiede zu LiveComponents

**HTML Components**:
- ❌ **Keine Type Coercion** - alle Attribute bleiben strings
- ❌ **Keine Prop Validation** - Component entscheidet selbst
- ❌ **Kein State Management** - rein statisches Rendering
- ❌ **Keine ComponentId/ComponentData** - nur template rendering
- ✅ **Schneller** - keine Metadata-Prüfung, kein State-Handling
- ✅ **Einfacher** - nur `render(content, attributes)` Method

**LiveComponents**:
- ✅ **Type Coercion** für alle Props
- ✅ **Prop Validation** gegen Metadata
- ✅ **State Management** mit ComponentData
- ✅ **Interactive** mit AJAX/WebSocket updates
- ⚠️ **Komplexer** - mehr Overhead für Metadata/State

## Component Registration

### LiveComponent Registration

```php
// Automatisch via #[LiveComponent] Attribute Discovery
use App\Framework\LiveComponents\Attributes\LiveComponent;

#[LiveComponent(name: 'datatable')]
final class DataTableComponent implements LiveComponentContract
{
    // Component implementation
}

// Framework registriert automatisch bei Bootstrap:
// ComponentRegistry::register('datatable', DataTableComponent::class)
```

### HTML Component Registration

```php
// Automatisch via #[ComponentName] Attribute Discovery
use App\Framework\View\Attributes\ComponentName;

#[ComponentName('button')]
final readonly class ButtonComponent
{
    public function render(string $content, array $attributes): string
    {
        // Rendering logic
    }
}

// Framework registriert automatisch:
// HtmlComponentRegistry::register('button', ButtonComponent::class)
```

## Error Handling

### Component Not Found

```html
<x-unknown-component />
```

**Development Mode**:
```html
<div style="border:2px solid red;padding:1rem;background:#fee;color:#c00;">
    <strong>XComponentProcessor Error:</strong><br>
    <pre>Unknown component: <x-unknown-component>

Available LiveComponents: datatable, counter, chart
Available HTML Components: button, card, badge</pre>
    <small>Component: x-unknown-component</small>
</div>
```

**Production Mode**:
- Element wird **silently removed**
- Kein Error-HTML im Output
- Optional: Logging via `error_log()`

### Invalid Props (LiveComponents)

```html
<x-counter invalidProp="test" />
```

**Development Mode**:
```html
<div style="border:2px solid red;">
    <strong>XComponentProcessor Error:</strong><br>
    <pre>LiveComponent 'counter' has no property 'invalidProp'.
Available properties: initialValue, step</pre>
    <small>Component: x-counter</small>
</div>
```

**Production Mode**:
- Component wird **nicht gerendert**
- Silent removal
- Optional: Logging

### Rendering Errors

Wenn `ComponentRegistry::renderWithWrapper()` oder `HtmlComponentRegistry::render()` fehlschlägt:

**Development Mode**: Error message with stack trace
**Production Mode**: Silent removal + logging

## Auto-Detection Priority

**Wenn Component in BEIDEN Registries existiert**:

```
LiveComponent Priority > HTML Component
```

**Beispiel**:
```php
// BOTH registered:
#[LiveComponent(name: 'button')]
class ButtonLiveComponent { ... }

#[ComponentName('button')]
class ButtonHtmlComponent { ... }

// Usage:
<x-button id="my-button" />
// → Processed as LiveComponent (Priority!)
```

**Best Practice**: Verwende unterschiedliche Namen für LiveComponents und HTML Components, um Verwirrung zu vermeiden.

## Performance Characteristics

### LiveComponent Processing

- **Prop Extraction**: O(n) wo n = Anzahl Attribute
- **Type Coercion**: O(n) wo n = Anzahl Props
- **Prop Validation**: O(n) wo n = Anzahl Props (Metadata lookup cached)
- **Component Resolution**: Container DI Resolution
- **Rendering**: Depends on component logic

**Durchschnittliche Latenz**: ~5-15ms pro LiveComponent

### HTML Component Processing

- **Attribute Extraction**: O(n) wo n = Anzahl Attribute
- **Content Extraction**: O(1)
- **Rendering**: Component-spezifische Logic

**Durchschnittliche Latenz**: ~1-5ms pro HTML Component

### Optimization Strategies

```php
// 1. ComponentMetadataCache nutzen (automatisch)
$metadata = $this->metadataCache->get($className);

// 2. Registry Lookups cachen (automatisch)
if ($this->liveComponentRegistry->isRegistered($name)) { ... }

// 3. Batch-Processing für multiple Components
foreach ($xComponents as $element) {
    $this->processXComponent($dom, $element, $context);
}
```

## Framework Integration

### DomProcessingPipeline Integration

```php
// In TemplateRendererInitializer
$domProcessors = [
    ForProcessor::class,              // Priority 100
    IfProcessor::class,               // Priority 200
    XComponentProcessor::class,       // Priority 300 ← Here
    ComponentProcessor::class,        // Priority 400 (legacy <component>)
    IncludeProcessor::class,          // Priority 500
    // ...
];
```

**Processing Order**:
1. `<for>` loops werden zuerst verarbeitet
2. `<if>` conditionals danach
3. **`<x-*>` Components** werden resolved
4. Legacy `<component>` tags (fallback)
5. `<include>` templates einbinden

### RenderContext Integration

```php
$context = RenderContext::create([
    'users' => $users,
    'currentPage' => $page
]);

// XComponentProcessor hat Zugriff auf $context->data
// Aber: Props werden via Attribute übergeben, nicht via Context
```

## Testing

### Unit Tests

Der XComponentProcessor hat **umfassende Test-Coverage**:

```php
describe('XComponentProcessor', function () {
    describe('LiveComponent Processing', function () {
        it('processes LiveComponent with basic props');
        it('coerces prop types correctly');
        it('validates props against ComponentMetadata');
        it('generates unique ID if not provided');
    });

    describe('HTML Component Processing', function () {
        it('processes HTML Component');
        it('extracts content from HTML Component');
    });

    describe('Error Handling', function () {
        it('shows helpful error when component not found');
        it('removes component silently in production');
    });

    describe('Auto-Detection Priority', function () {
        it('prioritizes LiveComponent over HTML Component');
    });
});
```

**Test File**: `tests/Unit/Framework/View/Processors/XComponentProcessorTest.php`

### Integration Testing

```php
// Full Template Processing mit XComponentProcessor
$template = <<<HTML
<html>
<body>
    <h1>Dashboard</h1>
    <x-datatable id="users" page="1" />
    <x-button variant="primary">Add User</x-button>
</body>
</html>
HTML;

$context = RenderContext::create([]);
$rendered = $this->templateProcessor->render($context, $template);

// Assert: LiveComponent rendered with data-component-id
expect($rendered)->toContain('data-component-id="datatable:users"');

// Assert: HTML Component rendered as button
expect($rendered)->toContain('<button class="btn btn-primary">');
```

## Best Practices

### 1. Naming Conventions

```php
// ✅ Good: Clear, descriptive names
#[LiveComponent(name: 'user-datatable')]
#[LiveComponent(name: 'product-filter')]
#[ComponentName('primary-button')]

// ❌ Bad: Generic or conflicting names
#[LiveComponent(name: 'table')]  // Too generic
#[ComponentName('button')]       // Conflicts with LiveComponent 'button'
```

### 2. Prop Design (LiveComponents)

```php
// ✅ Good: Specific, typed props
#[LiveComponent(name: 'datatable')]
final class DataTableComponent
{
    #[LiveProp]
    public int $page = 1;

    #[LiveProp]
    public int $pageSize = 25;

    #[LiveProp]
    public string $sortBy = 'id';
}

// ❌ Bad: Generic array props (lose type safety)
#[LiveProp]
public array $config = [];  // What keys? What types?
```

### 3. ID Management

```php
// ✅ Good: Explicit IDs for wichtige Components
<x-datatable id="users-table" page="1" />
<x-datatable id="products-table" page="1" />

// ⚠️ OK: Auto-generated IDs für einmalige Components
<x-counter initialValue="0" />
// → "counter-a3f2d8e1" (auto-generated)

// ❌ Bad: Duplicate IDs
<x-counter id="counter-1" />
<x-counter id="counter-1" />  // ID collision!
```

### 4. Content vs Props

```php
// ✅ HTML Component: Content via innerHTML
<x-button variant="primary">Click me</x-button>

// ✅ LiveComponent: Data via Props
<x-datatable data='[{"id":1,"name":"Alice"}]' />

// ❌ Bad: Mixing approaches
<x-datatable>
    <!-- Content ignored for LiveComponents! -->
    Some data here
</x-datatable>
```

### 5. Error Handling

```php
// ✅ Good: Graceful error handling in component
#[LiveComponent(name: 'chart')]
final class ChartComponent
{
    #[LiveProp]
    public array $data = [];

    public function render(): RenderData
    {
        if (empty($this->data)) {
            return new RenderData(
                template: 'components/chart-empty',
                data: ['message' => 'No data available']
            );
        }

        return new RenderData(
            template: 'components/chart',
            data: ['chartData' => $this->processData()]
        );
    }
}

// ❌ Bad: Throwing exceptions ohne Fallback
public function render(): RenderData
{
    if (empty($this->data)) {
        throw new \Exception('No data!'); // User sieht error!
    }
    // ...
}
```

## Migration Guide

### Von Legacy `<component>` zu `<x-*>` Syntax

**Vorher** (Legacy Syntax):
```html
<component name="button" variant="primary">Click me</component>
```

**Nachher** (Unified Syntax):
```html
<x-button variant="primary">Click me</x-button>
```

**Migration Steps**:

1. **HTML Components**: Einfach Syntax ändern
   ```html
   <!-- Old -->
   <component name="card" title="Profile">Content</component>

   <!-- New -->
   <x-card title="Profile">Content</x-card>
   ```

2. **LiveComponents**: Prüfen ob #[LiveComponent] Attribute vorhanden
   ```php
   // Ensure component is registered
   #[LiveComponent(name: 'datatable')]
   final class DataTableComponent { ... }
   ```

3. **Props**: Gleiche Attribute-Namen funktionieren
   ```html
   <!-- Old -->
   <component name="datatable" page="1" pageSize="25" />

   <!-- New -->
   <x-datatable page="1" pageSize="25" />
   ```

## Troubleshooting

### Problem: Component wird nicht gefunden

```
Unknown component: <x-my-component>
Available LiveComponents: datatable, counter
Available HTML Components: button, card
```

**Lösung**:
1. Prüfe Attribute: `#[LiveComponent(name: 'my-component')]` oder `#[ComponentName('my-component')]`
2. Prüfe Auto-Discovery: `php console.php framework:discover`
3. Cache leeren: `php console.php cache:clear`

### Problem: Props werden nicht übergeben

```html
<x-counter initialValue="10" />
<!-- Component erhält initialValue nicht -->
```

**Lösung**:
1. Prüfe `#[LiveProp]` Attribute auf Property
2. Prüfe ComponentMetadata Cache
3. Development Mode aktivieren für Validation Errors

### Problem: Type Coercion funktioniert nicht

```html
<x-chart data="[1,2,3]" />
<!-- Component erhält string statt array -->
```

**Lösung**:
1. **HTML Component?** → Keine Type Coercion, nur LiveComponents!
2. JSON valid? → Teste mit `json_decode('[1,2,3]')`
3. Alternativ: Props als separate Attribute

### Problem: Component rendered nicht in Production

**Ursache**: Silent error handling in production mode

**Lösung**:
1. Development Mode aktivieren: `APP_ENV=development`
2. Error logs prüfen
3. Component-Validation durchführen

## Framework-Compliance

Der XComponentProcessor folgt **allen Framework-Patterns**:

✅ **readonly class** - Unveränderlichkeit
✅ **final** - Keine Vererbung
✅ **Composition** - Dependencies via Constructor Injection
✅ **Interface Implementation** - `DomProcessor` Interface
✅ **Value Objects** - `ComponentId`, `ComponentData`, `RenderData`
✅ **Attribute Discovery** - Automatische Component Registration
✅ **Error Handling** - Graceful degradation (dev/prod modes)
✅ **Type Safety** - Strict types via `declare(strict_types=1)`

## Zusammenfassung

**XComponentProcessor** bietet:
- ✅ **Unified Syntax** - `<x-*>` für alle Component-Typen
- ✅ **Auto-Detection** - LiveComponent vs HTML Component
- ✅ **Type Coercion** - Automatische Typ-Konvertierung (LiveComponents)
- ✅ **Prop Validation** - Gegen ComponentMetadata (LiveComponents)
- ✅ **Error Handling** - Development vs Production Modes
- ✅ **Performance** - Optimized mit Caching
- ✅ **Framework-Compliant** - Alle Patterns korrekt umgesetzt

**Use Cases**:
- **Interactive Components**: DataTables, Forms, Counters, Charts
- **Static Components**: Buttons, Cards, Badges, Icons
- **Unified Developer Experience**: Eine Syntax für beide Typen
- **Progressive Enhancement**: Start mit HTML Component, upgrade zu LiveComponent
