inanepain / view
View layer with models for the most common content types.
Requires
- php: >=8.1
- inanepain/stdlib: * || dev-master || dev-develop
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-13 00:01:11 UTC
README
Table of Contents
inanepain/view
View layer with models for the most common content types.
.1. Install
composercomposer require inanepain/view
.2. Nested and Iterative Views
.2.1. Renderer Partials
PhpRenderer and StringRenderer provide renderPartial for a named template and renderEach for a collection of variable arrays. Partials use the renderer’s existing template stack. The existing render and static renderTemplate entry points remain available; StringRenderer::render still treats its template as a literal string unless useStack is enabled.
renderEach accepts arrays and traversable collections, including generators, and concatenates output in iteration order. Its optional shared variables are overridden by each item’s variables. Item variables do not leak into subsequent iterations. An empty collection produces an empty string; a non-array item throws Inane\View\Exception\RuntimeException.
PHP templates rendered without an explicit context object have the renderer available as $this, including renderPartial and renderEach. Supplying a context object retains that object binding instead. Static file rendering only binds an object when one is supplied. PHP templates are trusted executable code, not a sandbox. The internal variable names templateFile, variables and bufferLevel are reserved during file rendering.
String templates retain the {$name} placeholder syntax. Values may be scalar, null or stringable. Inserted output is literal: backslashes, dollar signs and placeholders within child output are not interpreted again. Unknown placeholders are retained. Render child partials first and pass their output as parent variables. Output is not automatically HTML-escaped.
PHP Partials and Collections
Create these templates in a templates directory beside the calling script. Escape text values in the templates; rendered child markup is inserted directly.
<?php declare(strict_types=1);?> <li><?= htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') ?></li>templates/list.phtml
<?php declare(strict_types=1); ?> <ul><?= $this->renderEach('item', $items) ?></ul>Calling script (after loading the Composer autoloader)
<?php declare(strict_types=1); use Inane\View\Renderer\PhpRenderer; $renderer = new PhpRenderer(__DIR__ . '/templates'); echo $renderer->renderPartial('item', ['name' => 'Ada']); echo $renderer->render('list', [ 'items' => [ ['name' => 'Ada'], ['name' => 'Grace'], ], ]);
The first call produces <li>Ada</li>. The second produces <ul><li>Ada</li><li>Grace</li></ul> (apart from template line endings). Inside list.phtml, $this is the renderer because no explicit context object was supplied. Each call to renderEach renders item.phtml with a separate variable array.
String Partials and Shared Defaults
String partials resolve names from the template stack. Render the collection first, then pass its markup into the parent placeholder. Escape user-provided values before passing them to the renderer.
<?php declare(strict_types=1); use Inane\View\Renderer\StringRenderer; $renderer = new StringRenderer([ 'item' => '<li>{$name}: {$role}</li>', 'list' => '<ul>{$content}</ul>', ]); $content = $renderer->renderEach( template: 'item', items: [ ['name' => 'Ada'], ['name' => 'Grace', 'role' => 'editor'], ['name' => 'Linus'], ], data: ['role' => 'reader'], ); echo $renderer->renderPartial('list', ['content' => $content]);Output
<ul><li>Ada: reader</li><li>Grace: editor</li><li>Linus: reader</li></ul>
Grace’s item overrides the shared role, but Linus still receives the shared default. To render the named parent with render instead, use $renderer→render(template: 'list', data: ['content' ⇒ $content], useStack: true); without useStack, render('list') returns the literal string list.
.2.2. Model Trees
HttpModel::addChild attaches a named child model. HttpModel::render renders children recursively before rendering the parent with a configured PhpRenderer. Alternatively, initialise ViewManager with that renderer and pass the root model to its render method.
Child output is available both as a variable bearing the child’s name and through $this on the bound model context. Rendered children override parent variables with the same name. Children inherit parent variables, including iteration variables, but explicitly supplied child variables take precedence. Child-property access outside a rendering context throws Inane\View\Exception\RuntimeException.
IterativeModel extends HttpModel and accepts items, shared variables and model options. Each item is an array of template variables; its values override shared defaults. Every item renders the model’s template and child tree, and the resulting strings are concatenated. Iterables are materialised at construction so even generator-backed models can be rendered repeatedly. An empty model produces an empty string.
Models retain their original variables and child models after rendering. Circular model trees throw Inane\View\Exception\RuntimeException. Rendering exceptions propagate, output buffers are cleaned, and models can be retried after correcting the failure. Layout and HTTP response handling are not performed by these rendering methods.
A Nested Iterative Model
This example attaches an IterativeModel to a parent HttpModel and gives each repeated row its own child view. Create the following templates in the same templates directory.
<?php declare(strict_types=1); ?> <h1><?= htmlspecialchars($title, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') ?></h1> <ul><?= $rows ?></ul>templates/row.phtml
<?php declare(strict_types=1); ?> <li><?= $this->label ?></li>templates/label.phtml
<?php declare(strict_types=1); ?> <?= htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') ?>: <?= htmlspecialchars($role, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') ?>Calling script (after loading the Composer autoloader)
<?php declare(strict_types=1); use Inane\View\Model\HttpModel; use Inane\View\Model\IterativeModel; use Inane\View\Renderer\PhpRenderer; use Inane\View\ViewManager; $renderer = new PhpRenderer(__DIR__ . '/templates'); $page = new HttpModel( variables: ['title' => 'Team'], options: ['template' => 'page'], ); $rows = new IterativeModel( items: [ ['name' => 'Ada'], ['name' => 'Grace', 'role' => 'editor'], ], variables: ['role' => 'reader'], options: ['template' => 'row'], ); $rows->addChild('label', new HttpModel(options: ['template' => 'label'])); $page->addChild('rows', $rows); $manager = new ViewManager($renderer); echo $manager->render($page);Output (apart from template line endings)
<h1>Team</h1> <ul> <li>Ada: reader</li> <li>Grace: editor</li> </ul>
The label child inherits each row’s name and role. Its rendered output is available as $this→label in row.phtml; $label would produce the same output. Likewise, page.phtml can use either $rows or $this→rows for its rendered child. Here $this is the bound model context, not the renderer.
Calling $page→render($renderer) directly produces the same result as the manager. Explicit variables on the label child would override inherited row values. The same model tree can be rendered again, including when the items constructor argument is a generator.