LilaPHP

Views & Frontend

Native View Engine & Bluebird CSS

LilaPHP includes a high-performance native PHP View Engine in _core/View.php. It eliminates template compiler latency, provides seamless layout inheritance, partial includes, heredoc execution, tiered multi-driver caching (APCu, Redis, File), automatic asset versioning, SEO metadata generation, PWA manifests, CSRF context, and live development hot reload.

1. Architectural Philosophy

Instead of compiling third-party template languages into PHP at runtime, LilaPHP views are native PHP scripts located in app/views/. They execute at C-speed, are compiled directly by OPcache, and have zero external dependencies.

  • Zero Compiler Overhead: Native PHP template rendering with output buffering.
  • Layout Inheritance: Wrap templates in a common outer layout (app/views/layout.php) or specify custom layouts per route.
  • Embeddable Views: Render partials or embed views without outer layouts via ['layout' => false].
  • Tiered Caching: Fast multi-level view caching across APCu, Redis, and filesystem storage.
  • Built-in Security: Automatic injection of $csrf_token and $csrf_input in all template scopes.

2. Rendering Views (`View::render`)

Invoke View::render() or the global helper view() inside your web route files located in app/routes/*.php:

<?php
use Core\Request;
use Core\View;

Request::GET(function () {
    $products = [
        ['id' => 1, 'name' => 'Ultralight Laptop', 'price' => 999.00],
        ['id' => 2, 'name' => 'Wireless Headphones', 'price' => 149.50],
    ];

    View::render('products', [
        'products' => $products,
        'category' => 'Electronics'
    ], [
        'title'       => 'Product Catalog — LilaPHP',
        'description' => 'Browse our catalog of high-performance electronics.',
        'keywords'    => 'electronics, laptops, gadgets',
        'canonical'   => 'https://example.com/products',
        'cache'       => 300
    ]);
});

The view template file is resolved from app/views/products.php or app/views/products/index.php. Variables passed in the data array are automatically extracted into local scope.

3. Layouts & Slots

By default, View::render() wraps the view inside app/views/layout.php. The rendered view content is passed into the layout as $content.

<!doctype html>
<html lang="<?= e($lang ?? 'en') ?>" data-theme="light">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <?= $seo_meta ?? '' ?>
    <?= $csrf_meta ?? '' ?>
    <link rel="stylesheet" href="<?= asset('/css/bluebird.css') ?>">
</head>
<body>
    <header class="navbar">
        <a href="/" class="brand"><?= e($app_name ?? 'LilaPHP') ?></a>
        <nav>
            <a href="/">Home</a>
            <a href="/about">About</a>
        </nav>
    </header>

    <main class="container">
        <?= $content ?>
    </main>

    <footer class="footer">
        <p>&copy; <?= date('Y') ?> <?= e($app_name ?? 'LilaPHP') ?></p>
    </footer>
    <?= $hot_reload ?? '' ?>
</body>
</html>

Custom Layouts and Embed Mode

You can specify a different layout via the options array or disable layouts completely:

View::render('dashboard', $data, ['layout' => 'admin']);

View::render('components/table', $data, ['layout' => false]);

4. Heredoc View Execution (`View::html`)

Inside template files (such as app/views/about.php), you can render standard PHP templates or use View::html() with closures or heredoc syntax for structured string templates:

<?php
use Core\View;

echo View::html(function ($data) {
    $version = e($data['version'] ?? '1.0.0');
    $name = e($data['app_name'] ?? 'LilaPHP');

    return <<<HTML
<section class="card">
    <h1>About {$name}</h1>
    <p>Running framework version <strong>{$version}</strong>.</p>
</section>
HTML;
}, get_defined_vars());

5. Component Partials (`View::partial`)

Break complex pages into reusable components using View::partial(). Partials are loaded from app/views/partials/{name}.php or app/views/{name}.php:

<div class="catalog">
    <?php foreach ($products as $item): ?>
        <?= View::partial('product_card', ['item' => $item]) ?>
    <?php endforeach; ?>
</div>

6. Asset Fingerprinting & Versioning (`View::asset`)

Prevent stale browser caching using View::asset() or the global helper asset(). LilaPHP automatically appends a timestamp hash of the physical file in public/:

<link rel="stylesheet" href="<?= asset('/css/bluebird.css') ?>">
<script src="<?= asset('/js/app.js') ?>" defer></script>

Generated output in production:

<link rel="stylesheet" href="/css/bluebird.css?v=68f2ba1c">
<script src="/js/app.js?v=9a0d8e21" defer></script>

7. SEO Metadata & Progressive Web App (PWA)

Pass metadata directly into View::render() options to automatically generate canonical links, meta tags, and structured JSON-LD data:

View::render('article', ['post' => $post], [
    'title'       => $post['title'] . ' — My Blog',
    'description' => $post['summary'],
    'keywords'    => 'php, webdev, performance',
    'canonical'   => 'https://example.com/blog/' . $post['slug'],
    'jsonLD'      => [
        '@context'      => 'https://schema.org',
        '@type'         => 'Article',
        'headline'      => $post['title'],
        'datePublished' => $post['created_at'],
    ],
    'pwa'         => true,
    'manifest'    => '/manifest.json'
]);

When pwa => true is specified, the view automatically links public/manifest.json and injects the client-side install banner handler.

8. CSRF Protection in Views

Every view and layout automatically receives CSRF helper variables in its scope:

  • $csrf_input: Renders <input type="hidden" id="_csrf" name="_csrf" value="...">.
  • $csrf_token: Raw CSRF token string for JavaScript fetch/axios headers.
  • $csrf_meta: Renders <meta name="csrf-token" content="..."> for the document head.
<form method="POST" action="/contact">
    <?= $csrf_input ?>
    <div class="form-group">
        <label for="email">Email Address</label>
        <input type="email" id="email" name="email" required>
    </div>
    <button type="submit" class="btn primary">Send Message</button>
</form>

9. Tiered View Caching

Pass the cache option with a TTL in seconds to enable automated multi-driver view caching. The cache driver is read from CACHE_DRIVER in .env by default and can be overridden per call:

// Public page — safe to cache globally (no user-specific content)
View::render('home', $data, [
    'cache'    => true,
    'cacheTtl' => 600,           // 10 minutes
    'driver'   => 'apcu',        // Override .env CACHE_DRIVER for this view
]);

// Per-user personalised cache (scoped to user ID to prevent data leaks)
View::render('dashboard', $data, [
    'cache'    => true,
    'cacheTtl' => 60,
    'userKey'  => (string) ($_SESSION['user_id'] ?? ''),
]);

The engine resolves cached HTML in order:

  1. APCu Shared Memory: Sub-millisecond RAM retrieval with zero network latency.
  2. Redis Memory Cluster: Shared distributed cache across multiple web workers.
  3. File System Cache: Atomic disk storage under _core/cache/data/.

⚠️ Session & User Data Safety

View caching stores the fully rendered HTML string — including any user-specific content interpolated from $data or $_SESSION. If two users request the same route while caching is active, the first rendered HTML is returned to all subsequent callers until the TTL expires, potentially exposing private data.

  • Never enable 'cache' => true for pages that render user-specific data (dashboards, profile pages, authenticated views, shopping carts, etc.)
  • If you need per-user caching (e.g. personalised but cacheable content), always supply 'userKey' => $userId to namespace the cache key per user.
  • For purely public pages with no session-dependent content (landing pages, blog posts, product listings) view caching is safe and recommended.

10. Development Hot Reload

When APP_DEBUG=true is set in .env, LilaPHP automatically injects a lightweight background poll client in views. It monitors file modifications across app/views/ and public/css/, automatically reloading the browser when files change.

php cli.php dev 8080

11. Bluebird CSS Micro-Framework

Docs

LilaPHP includes public/css/bluebird.css, a semantic zero-dependency CSS micro-framework providing responsive layouts, dark/light theme switching, cards, forms, tables, modals, and toasts:

<div class="grid grid-cols-2 gap-4">
    <div class="card">
        <h3>Card Title</h3>
        <p>Card content styled automatically.</p>
        <button class="btn primary">Action</button>
    </div>
</div>

Toggle themes by setting the data-theme attribute on the <html> element:

document.documentElement.setAttribute('data-theme', 'dark');