Skip to content

Views

Introduction

Views separate presentation logic from application logic. Lighthouse uses plain PHP templates — no new syntax to learn.

Configuration

Configure the views directory:

php
$app->useViews(__DIR__ . '/../views');

Basic Usage

Create a view file:

php
// views/welcome.php
<h1>Welcome, <?= $view->e($name) ?>!</h1>

Render it:

php
$app->get('/', function () use ($app) {
    return $app->view('welcome', ['name' => 'John']);
});

Or from a controller:

php
return $this->view('welcome', ['name' => 'John']);

Escaping Output

Always escape user data with $view->e():

php
<p><?= $view->e($userInput) ?></p>

This prevents XSS attacks by converting <script> to &lt;script&gt;.

For JSON in JavaScript:

php
<script>
    const data = <?= $view->json($data) ?>;
</script>

Layouts

Create a layout:

php
// views/layouts/main.php
<!DOCTYPE html>
<html>
<head>
    <title><?= $view->yield('title', 'My App') ?></title>
</head>
<body>
    <header>
        <nav><!-- Navigation --></nav>
    </header>

    <main>
        <?= $view->yield('content') ?>
    </main>

    <footer>
        <p>&copy; 2025 My App</p>
    </footer>
</body>
</html>

Extend it in child views:

php
// views/home.php
<?php $view->extends('layouts.main'); ?>

<?php $view->section('title'); ?>
Home
<?php $view->endSection(); ?>

<?php $view->section('content'); ?>
<h1>Welcome Home!</h1>
<p>This is the homepage.</p>
<?php $view->endSection(); ?>

Sections

Define sections in child views:

php
<?php $view->section('sidebar'); ?>
<ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about">About</a></li>
</ul>
<?php $view->endSection(); ?>

Output in layouts:

php
<aside>
    <?= $view->yield('sidebar') ?>
</aside>

Default content:

php
<?= $view->yield('sidebar', '<p>No sidebar</p>') ?>

Check if section exists:

php
<?php if ($view->hasSection('sidebar')): ?>
    <aside><?= $view->yield('sidebar') ?></aside>
<?php endif; ?>

Partials

Extract reusable components:

php
// views/partials/user-card.php
<div class="user-card">
    <h3><?= $view->e($user['name']) ?></h3>
    <p><?= $view->e($user['email']) ?></p>
</div>

Include them:

php
<?php foreach ($users as $user): ?>
    <?php $view->include('partials.user-card', ['user' => $user]); ?>
<?php endforeach; ?>

Or capture the output:

php
<?= $view->partial('partials.user-card', ['user' => $user]) ?>

Shared Data

Share data across all views:

php
// In public/index.php
$app->getView()->share('appName', 'My App');
$app->getView()->share([
    'currentYear' => date('Y'),
    'user' => $currentUser,
]);

Access in any view:

php
<title><?= $view->e($appName) ?></title>
<p>&copy; <?= $currentYear ?></p>

Dot Notation

Use dots for subdirectories:

php
return $this->view('users.index');
// Loads: views/users/index.php

return $this->view('admin.users.edit');
// Loads: views/admin/users/edit.php

Full Example

Layout:

php
// views/layouts/app.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title><?= $view->yield('title', $appName) ?></title>
    <?= $view->yield('head') ?>
</head>
<body>
    <?php $view->include('partials.nav'); ?>

    <main class="container">
        <?= $view->yield('content') ?>
    </main>

    <footer>
        <p>&copy; <?= date('Y') ?> <?= $view->e($appName) ?></p>
    </footer>

    <?= $view->yield('scripts') ?>
</body>
</html>

Page:

php
// views/users/index.php
<?php $view->extends('layouts.app'); ?>

<?php $view->section('title'); ?>
Users - <?= $view->e($appName) ?>
<?php $view->endSection(); ?>

<?php $view->section('content'); ?>
<h1>Users</h1>

<?php if (empty($users)): ?>
    <p>No users found.</p>
<?php else: ?>
    <ul>
        <?php foreach ($users as $user): ?>
            <li><?= $view->e($user['name']) ?></li>
        <?php endforeach; ?>
    </ul>
<?php endif; ?>
<?php $view->endSection(); ?>

Released under the MIT License.