GitHub

View Templating

TinyMVC provides a fast, lightweight templating system using plain PHP with additional conveniences for layouts, components, and data sharing.

Basic Usage

Rendering Views

// In controllers
return view('welcome', ['name' => 'John']);

// Using View class directly
return get(Response::class)->write(
    get(View::class)
        ->render('profile', ['user' => $user])
);

Template Structure

views/
├── layouts/
│   └── app.php      # Main layout
├── components/
│   └── alert.php    # Reusable components
└── pages/
    ├── home.php     # Page templates
    └── profile.php

Template Features

Passing Data

// Controller
return view('profile', [
    'user' => $user,
    'title' => 'User Profile'
]);

// Template (profile.php)
<h1><?= $title ?>></h1>
<p>Welcome, <?= $user->name ?>></p>

Layouts

// Using layout
return view('pages/home');

// Page template (pages/home.php)
<?php $view->layout('layouts/app'); ?>
<section>
    <h1>Home</h1>
    <p>Welcome to the home page!</p>
<section/>

// Layout template (layouts/app.php)
<!DOCTYPE html>
<html>
<head>
    <title>My App</title>
</head>
<body>
    <?= $content ?>>
</body>
</html>

Components

// In template
<?= $view->component('alert', ['type' => 'success', 'message' => 'Updated!']) ?>

// Component (components/alert.php)
<div class="alert alert-<?= $type ?>">
    <?= $message ?>
</div>

Automatic Context

These variables are always available in templates:

$app       // Application instance
$request   // Current Request object  
$session   // Session object
$errors    // Validation errors
$view      // Current View instance

View Methods

// Set/get view data
$view->set('key', 'value');
$value = $view->get('key');

// Check for data
if ($view->has('user')) {
    // ...
}

// Merge additional context
$view->mergeContext(['settings' => $settings]);

// Include partials
<?= $view->include('partials/header') ?>

// Check if template exists
if ($view->templateExists('special-page')) {
    // ...
}

Best Practices

  • Keep templates focused on presentation only
  • Use components for reusable UI elements
  • Pass only necessary data to views
  • Store complex logic in view composers
  • Use layouts for consistent page structures

Advanced Patterns

View Composers

// In service provider
view()->mergeContext([
    'categories' => Category::all(),
    'stats' => SiteStats::get()
]);

// Or create dedicated composer class
class ProfileComposer
{
    public function compose(View $view)
    {
        $view->set('friends', User::friends(auth()->id()));
    }
}

Error Handling

// Access validation errors
<?php if ($errors->has('email')): ?>
    <div class="error"><?= $errors->first('email') ?></div>
<?php endif ?>

AJAX Responses

if ($request->isAjax()) {
    return response()->json([
        'html' => view('partials/updates', $data)
    ]);
}

Full Example

// Controller
public function show($id)
{
    return view('products/show', [
        'product' => Product::find($id),
        'related' => Product::related($id)
    ]);
}

// Template (products/show.php)
<?php $view->layout('layouts/store'); ?>
<?= $view->include('partials/product-header') ?>

<div class="product-details">
    <h1><?= $product->name ?></h1>
    <?= $view->component('price', ['amount' => $product->price]) ?>
</div>

<?php if (!empty($related)): ?>
    <h2>Related Products</h2>
    <?= $view->include('partials/product-grid', ['products' => $related]) ?>
<?php endif ?>

// Layout (layouts/store.php)
<!DOCTYPE html>
<html>
<head>
    <title><?= $title ?? 'Store' ?></title>
</head>
<body>
    <?= $view->include('partials/nav') ?>
    <main>
        <?= $content ?>
    </main>
    <?= $view->include('partials/footer') ?>
</body>
</html>