- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
8.9 KiB
8.9 KiB
View System Overview
Advanced template processing system with DOM manipulation, component architecture, and intelligent caching.
🏗 Architecture
The view system is built around DOM-based processing using PHP 8.4's native HTML5 parser, enabling sophisticated template manipulation while maintaining performance through intelligent caching.
Core Components
src/Framework/View/
├── Engine.php # Main template engine
├── TemplateRenderer.php # Rendering coordinator
├── DomProcessor.php # DOM manipulation interface
├── RenderContext.php # Template context data
├── ComponentRenderer.php # Component system
├── Processors/ # Template processors
├── Caching/ # Multi-level caching
└── Loading/ # Template resolution
📝 Basic Usage
Simple Template Rendering
// Controller
class HomeController
{
public function index(TemplateRenderer $renderer): ViewResult
{
return new ViewResult('home', [
'title' => 'Welcome',
'user' => $user,
'stats' => $this->getStats()
]);
}
}
Template Structure
<!-- templates/home.view.php -->
<layout name="main">
<slot name="title">{title}</slot>
<slot name="content">
<div class="welcome">
<h1>Hello, {user.name}!</h1>
<div class="stats">
<for data="stats" as="stat">
<div class="stat-item">
<span class="value">{stat.value}</span>
<span class="label">{stat.label}</span>
</div>
</for>
</div>
</div>
</slot>
</layout>
🧩 Component System
Component Definition
<!-- components/card.view.php -->
<div class="card {classes}">
<if condition="title">
<header class="card-header">
<h3>{title}</h3>
</header>
</if>
<div class="card-body">
<slot name="content">{content}</slot>
</div>
<if condition="actions">
<footer class="card-footer">
<slot name="actions"></slot>
</footer>
</if>
</div>
Component Usage
<component name="card" title="User Profile" classes="profile-card">
<slot name="content">
<p>User: {user.name}</p>
<p>Email: {user.email}</p>
</slot>
<slot name="actions">
<button>Edit Profile</button>
<button>View History</button>
</slot>
</component>
🔄 Template Processors
Available Processors
| Processor | Purpose | Documentation |
|---|---|---|
| LayoutTagProcessor | Layout system implementation | Details |
| ComponentProcessor | Reusable UI components | Details |
| SlotProcessor | Content injection system | Details |
| IfProcessor | Conditional rendering | Details |
| ForProcessor | Loop iteration | Details |
| PlaceholderReplacer | Variable substitution | Details |
| AssetInjector | JS/CSS asset injection | Details |
| MetaManipulator | Meta tag extraction | Details |
Processing Pipeline
1. Structure Processors
├── LayoutTagProcessor # Apply layouts
└── IncludeProcessor # Include external files
2. Component Processors
├── ComponentProcessor # Process components
└── SlotProcessor # Handle slots
3. Logic Processors
├── IfProcessor # Conditional logic
├── ForProcessor # Loops
└── SwitchCaseProcessor # Switch statements
4. Content Processors
├── PlaceholderReplacer # Variable substitution
├── DateFormatProcessor # Date formatting
└── MetaManipulator # Meta extraction
5. Asset Processors
└── AssetInjector # CSS/JS injection
6. Optimization Processors
├── CommentStripProcessor # Remove comments
├── RemoveEmptyLinesProcessor
└── VoidElementsSelfClosingProcessor
🎯 Advanced Features
Conditional Rendering
<!-- Simple conditions -->
<if condition="user.isAdmin">
<admin-panel></admin-panel>
</if>
<!-- Complex conditions -->
<if condition="user.role === 'admin' && features.adminPanel">
<component name="admin-dashboard"></component>
</if>
<!-- If-else chains -->
<if condition="user.isAdmin">
<admin-view></admin-view>
<else-if condition="user.isModerator">
<moderator-view></moderator-view>
<else>
<user-view></user-view>
</if>
Loop Iteration
<!-- Simple loops -->
<for data="users" as="user">
<div class="user-card">
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
</for>
<!-- Loops with keys -->
<for data="categories" as="category" key="categoryId">
<section data-category="{categoryId}">
<h2>{category.name}</h2>
<for data="category.items" as="item">
<article>{item.title}</article>
</for>
</section>
</for>
<!-- Loops with index -->
<for data="items" as="item" index="i">
<div class="item-{i}">
Position: {i + 1} - {item.name}
</div>
</for>
Layout System
<!-- Layout definition: layouts/main.view.php -->
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title><slot name="title">Default Title</slot></title>
<meta name="description" content="<slot name="description"></slot>">
<slot name="head"></slot>
</head>
<body>
<header>
<nav><!-- Navigation --></nav>
</header>
<main>
<slot name="content"></slot>
</main>
<footer>
<slot name="footer">© 2024 Framework</slot>
</footer>
<slot name="scripts"></slot>
</body>
</html>
💾 Caching System
Cache Strategies
// Automatic caching based on template analysis
$cacheStrategy = $analyzer->determineCacheStrategy($template);
// Manual cache control
$context = new RenderContext($data);
$context->setCacheStrategy(CacheStrategy::FULL_PAGE);
$context->setCacheTags(['user:123', 'posts']);
$context->setCacheTtl(3600);
Cache Invalidation
// Tag-based invalidation
$cache->invalidateByTags(['user:123']);
// Template-based invalidation
$cache->invalidateTemplate('user-profile');
// Smart invalidation on data changes
$user->save(); // Automatically invalidates user-related caches
🔧 Template Functions
Built-in Functions
<!-- URL generation -->
<a href="{url('user.profile', {id: user.id})}">Profile</a>
<!-- Image slots with responsive images -->
<img src="{imageSlot('hero', 'medium')}"
srcset="{imageSlot('hero', 'small')} 480w,
{imageSlot('hero', 'medium')} 768w,
{imageSlot('hero', 'large')} 1200w">
<!-- Date formatting -->
<time datetime="{user.createdAt|iso8601}">
{user.createdAt|date('d.m.Y H:i')}
</time>
<!-- Asset URLs -->
<link rel="stylesheet" href="{asset('css/app.css')}">
<script src="{asset('js/app.js')}" defer></script>
Custom Functions
// Register custom function
$templateEngine->registerFunction('currency', function ($amount, $currency = 'EUR') {
return number_format($amount, 2, ',', '.') . ' ' . $currency;
});
<!-- Use custom function -->
<span class="price">{product.price|currency('USD')}</span>
🎨 Integration with CSS/JS
Asset Management
<!-- Vite asset injection -->
<head>
{vite('resources/css/app.css')}
{vite('resources/js/app.js')}
</head>
<!-- Conditional assets -->
<if condition="isDevelopment">
<script src="http://localhost:3000/@vite/client" type="module"></script>
</if>
Component-specific Assets
<!-- components/chart.view.php -->
<div class="chart-container" data-chart="{chartData}">
<slot name="head">
<link rel="stylesheet" href="{asset('css/charts.css')}">
</slot>
<slot name="scripts">
<script src="{asset('js/charts.js')}" defer></script>
</slot>
</div>
🔍 Debugging & Development
Template Debugging
<!-- Debug mode shows processing steps -->
<debug>
Template: {template.name}
Context: {context.data|json}
Cache: {cache.status}
</debug>
Performance Analysis
// Template performance metrics
$metrics = $templateEngine->getMetrics();
echo "Render time: {$metrics->renderTime}ms\n";
echo "Cache hits: {$metrics->cacheHits}\n";
echo "Processors: {$metrics->processorsRun}\n";
For detailed processor documentation, see Template Processors
For component examples, see Component Library
For caching strategies, see View Caching