xref: /web-bugs/docs/templates.md (revision e8bab353)
1# Templates
2
3A simple template engine separates logic from the presentation and provides
4methods for creating nested templates and escaping strings to protect against
5too common XSS vulnerabilities.
6
7Template engine initialization:
8
9```php
10$template = new App\Template\Engine(__DIR__.'/../path/to/templates');
11```
12
13Site-wide configuration parameters can be assigned before rendering so they are
14available in all templates:
15
16```php
17$template->assign([
18    'siteUrl' => 'https://bugs.php.net',
19    // ...
20]);
21```
22
23Page can be rendered in the controller:
24
25```php
26echo $template->render('pages/how_to_report.php', [
27    'mainHeading' => 'How to report a bug?',
28]);
29```
30
31The `templates/pages/how_to_report.php`:
32
33```php
34<?php $this->extends('layout.php', ['title' => 'Reporting bugs']) ?>
35
36<?php $this->start('main_content') ?>
37    <h1><?= $this->noHtml($mainHeading) ?></h1>
38
39    <p><?= $siteUrl ?></p>
40<?php $this->end('main_content') ?>
41
42<?php $this->start('scripts') ?>
43    <script src="/js/feature.js"></script>
44<?php $this->end('scripts') ?>
45```
46
47The `templates/layout.php`:
48
49```html
50<!DOCTYPE html>
51<html lang="en">
52    <head>
53        <meta charset="utf-8">
54        <link rel="stylesheet" href="/css/style.css">
55        <title>PHP Bug Tracking System :: <?= $title ?? '' ?></title>
56    </head>
57    <body>
58        <?= $this->block('main_content') ?>
59
60        <div><?= $siteUrl ?></div>
61
62        <script src="/js/app.js"></script>
63        <?= $this->block('scripts') ?>
64    </body>
65</html>
66```
67
68## Including templates
69
70To include a partial template snippet file:
71
72```php
73<?php $this->include('forms/report_bug.php') ?>
74```
75
76which is equivalent to `<?php include __DIR__.'/../forms/contact.php' ?>`,
77except that the variable scope is not inherited by the template that included
78the file. To import variables into the included template snippet file:
79
80```php
81<?php $this->include('forms/contact.php', ['formHeading' => 'value', 'foo' => 'bar']) ?>
82```
83
84## Blocks
85
86Blocks are main building elements that contain template snippets and can be
87included into the parent file(s).
88
89Block is started with the `$this->start('block_name')` call and ends with
90`$this->end('block_name')`:
91
92```php
93<?php $this->start('block_name') ?>
94    <h1>Heading</h1>
95
96    <p>...</p>
97<?php $this->end('block_name') ?>
98```
99
100### Appending blocks
101
102Block content can be appended to existing blocks by the
103`$this->append('block_name')`.
104
105The `templates/layout.php`:
106
107```html
108<html>
109<head></head>
110<body>
111    <?= $this->block('content'); ?>
112
113    <?= $this->block('scripts'); ?>
114</body>
115</html>
116```
117
118The `templates/pages/index.php`:
119
120```php
121<?php $this->extends('layout.php'); ?>
122
123<?php $this->start('scripts'); ?>
124    <script src="/js/foo.js"></script>
125<?php $this->end('scripts'); ?>
126
127<?php $this->start('content') ?>
128    <?php $this->include('forms/form.php') ?>
129<?php $this->end('content') ?>
130```
131
132The `templates/forms/form.php`:
133
134```php
135<form>
136    <input type="text" name="title">
137    <input type="submit" value="Submit">
138</form>
139
140<?php $this->append('scripts'); ?>
141    <script src="/js/bar.js"></script>
142<?php $this->end('scripts'); ?>
143```
144
145The final rendered page:
146
147```html
148<html>
149<head></head>
150<body>
151    <form>
152        <input type="text" name="title">
153        <input type="submit" value="Submit">
154    </form>
155
156    <script src="/js/foo.js"></script>
157    <script src="/js/bar.js"></script>
158</body>
159</html>
160```
161
162## Helpers
163
164Registering additional template helpers can be useful when a custom function or
165class method needs to be called in the template.
166
167### Registering function
168
169```php
170$template->register('formatDate', function (int $timestamp): string {
171    return gmdate('Y-m-d H:i e', $timestamp - date('Z', $timestamp));
172});
173```
174
175### Registering object method
176
177```php
178$template->register('doSomething', [$object, 'methodName']);
179```
180
181Using helpers in templates:
182
183```php
184<p>Time: <?= $this->formatDate(time()) ?></p>
185<div><?= $this->doSomething('arguments') ?></div>
186```
187
188## Escaping
189
190When protecting against XSS there are two built-in methods provided.
191
192To replace all characters to their applicable HTML entities in the given string:
193
194```php
195<?= $this->noHtml($var) ?>
196```
197
198To escape given string and still preserve certain characters as HTML:
199
200```php
201<?= $this->e($var) ?>
202```
203