practical capstone projects

Template Rendering

Templates turn application data into HTML. Add product templates to the catalog app while keeping repository calls, validation, and authorization outside the view files.

Render A Known Template

Create a renderer that receives a code-owned template path and an explicit context:

PHP example
<?php

declare(strict_types=1);

function render(string $template, array $context): string
{
    extract($context, EXTR_SKIP);

    ob_start();
    require dirname(__DIR__) . '/templates/' . $template . '.php';

    return (string) ob_get_clean();
}

function e(string $value): string
{
    return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

Only application code chooses $template. Never pass request text into a dynamic include path.

Prepare Data Before Rendering

A controller can load rows and prepare a narrow context:

PHP example
<?php

echo render('products/index', [
    'products' => $repository->list(limit: 50),
]);

Inside templates/products/index.php, escape product names with e((string) $product['name']). Format trusted integer prices deliberately. Do not run SQL or permission checks in the template.

Verify Escaping

Create a product named <script>alert(1)</script> and load the list page. The page should display the characters as text; it must not execute markup. Check text nodes and HTML attributes separately because each output context has its own escaping rules.

Practice

Practice: Render A Safe Product Card

Implement the renderer and escaped product list template from the lesson.

Requirements

  • Use a narrow template context array.
  • Escape HTML text and attributes with correct context-aware helpers.
  • Keep database access and business rules outside templates.
  • Separate trusted markup from ordinary text.
  • Do not rely on input sanitisation instead of output escaping.
  • Avoid global variables hidden inside templates.
  • Do not execute template filenames chosen by request data.

Insert a product name containing HTML markup and prove the page displays text rather than executing markup.

Show solution
PHP example
<?php foreach ($products as $product): ?>
    <article>
        <h2><?= e((string) $product['name']) ?></h2>
        <p><?= (int) $product['price_cents'] ?> cents</p>
    </article>
<?php endforeach; ?>

The repository call stays in the controller. The template receives prepared data and escapes untrusted text where it becomes HTML.