View scripts
A view script is a file with HTML and PHP inserts that turns data into a page. View scripts have the .phtml extension and live in the module's view folder. A controller action passes data to the view script through a ViewModel object.
Where view scripts are looked up
First tell Laminas that the module has a folder with view scripts. Add a section to module/Blog/config/module.config.php:
// module/Blog/config/module.config.php
'view_manager' => [
'template_path_stack' => [
__DIR__ . '/../view',
],
],template_path_stack is the list of folders where the framework looks for view scripts. Here it is module/Blog/view.
The file name
The path to a view script is made of three lowercase names: the module, the controller without the word Controller, and the action.
| Action | View script file |
|---|---|
PostController::indexAction() | module/Blog/view/blog/post/index.phtml |
PostController::viewAction() | module/Blog/view/blog/post/view.phtml |
PostController::addAction() | module/Blog/view/blog/post/add.phtml |
The first view script
Change the action so that it returns a ViewModel:
// module/Blog/src/Controller/PostController.php
use Laminas\View\Model\ViewModel;
public function indexAction()
{
return new ViewModel([
'heading' => 'Posts',
]);
}Create the folders module/Blog/view/blog/post and the file index.phtml:
<!-- module/Blog/view/blog/post/index.phtml -->
<h1><?= $this->escapeHtml($this->heading) ?></h1>The array key heading became the property $this->heading in the view script. Open /blog: the heading "Posts" appears inside the site's common frame with the header.
A list in a view script
Pass an array of posts to the view script:
return new ViewModel([
'heading' => 'Posts',
'posts' => [
['id' => 1, 'title' => 'First post'],
['id' => 2, 'title' => 'Second post'],
],
]);View scripts use the colon syntax for loops and conditions — it reads better among HTML:
<!-- module/Blog/view/blog/post/index.phtml -->
<h1><?= $this->escapeHtml($this->heading) ?></h1>
<?php if (count($this->posts) === 0): ?>
<p>No posts yet.</p>
<?php endif; ?>
<ul>
<?php foreach ($this->posts as $post): ?>
<li><?= $this->escapeHtml($post['title']) ?></li>
<?php endforeach; ?>
</ul>The page shows a list of two titles.
Escaping
Escaping replaces characters such as < with safe codes, so that text from the database or a form does not turn into HTML tags.
| Helper | Where to use it |
|---|---|
escapeHtml($text) | Text between tags |
escapeHtmlAttr($value) | An attribute value: title, alt, value |
escapeJs($value) | A value inside JavaScript |
escapeUrl($value) | A part of an address in a link |
A different view script
If an action needs a view script with another name, set it explicitly: $view = new ViewModel(); $view->setTemplate('blog/post/list');. The name is written without the extension and without the view folder.
Common mistake
Writing <?= $this->heading ?> without escapeHtml() outputs the value as is: a <script> tag from a post title runs in the visitor's browser. Laminas does not escape output for you — wrap every value that came from a user or the database in escapeHtml().