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>