lekoala / kaly-tpl
Lightweight native PHP template renderer with explicit escaping, isolated includes and native IDE-friendly view helpers.
Requires
- php: ^8.3
Requires (Dev)
- carthage-software/mago: ^1
- composer/ca-bundle: ^1.5
- phpstan/phpstan: ^2.2
- phpunit/phpunit: ^11
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-11 13:45:49 UTC
README
Lightweight native PHP templates for PHP 8.3+
Kaly Tpl stays close to PHP while adding the small amount of structure usually missing from raw includes:
- native
.phtmltemplates with isolated scopes; - one typed
$vruntime instead of global helper functions; - explicit escaping for HTML, attributes, URLs, JSON and attribute bags;
- layouts, blocks and stacks, with explicit layout data;
- namespaced template paths;
each()with useful loop metadata, including generator lookahead;- injectable escaping and value formatting;
- native IDE completion without a template-language plugin, with optional development-time PHPDoc generation;
- template include chains attached to render failures.
There is no template language, parser, compiler or runtime dependency. Kaly Tpl is intended for trusted application views. It is not a sandbox and must not be used to execute user-authored templates.
Installation
composer require lekoala/kaly-tpl
Quick start
use Kaly\Tpl\ViewEngine; $view = (new ViewEngine(__DIR__ . '/views')) ->locale('fr_BE', currency: 'EUR', timezone: 'Europe/Brussels') ->addGlobal('appName', 'My App'); echo $view->render( 'appointments/index', ['appointments' => $appointments], layout: 'layouts/app', );
Templates use .phtml by default:
views/
layouts/app.phtml
appointments/index.phtml
appointments/card.phtml
A different extension can be configured when constructing the engine:
$view = new ViewEngine(__DIR__ . '/views', extension: 'php');
Template runtime
Every template receives a reserved $v variable implementing Kaly\Tpl\HtmlView:
<h1><?= $v->e($title) ?></h1> <article<?= $v->attrs(['class' => ['card', 'active' => $active]]) ?>> <?= $v->datetime($appointment->startsAt) ?> <?= $v->money($appointment->amount) ?> </article> <?= $v->inc('partials/card', ['card' => $card]) ?> <?= $v->each($cards, 'partials/card', as: 'card', empty: 'partials/empty') ?>
$v and the internal __kaly* prefix are reserved and cannot be supplied through render data or globals. Includes are
isolated: a partial receives only its explicit data, configured globals and $v, never arbitrary parent locals.
Documentation
- Templates and runtime —
$v, isolated scopes, reserved names, engine options. - Escaping —
e,attr,url,json,attrs, and how to compose them safely. - Formatting — dates, numbers, money, and custom escaper/formatter strategies.
- Includes and loops —
inc(),each(), loop metadata and recursion. - Layouts, blocks and stacks — layout selection, passing data to layouts, captures.
- Namespaced paths — multiple view roots and existence checks.
- Errors — the template include chain exposed by
ViewException. - Template PHPDoc DX — development-time managed docblocks.
- Recipes — typed application helpers, component/slot patterns, engine lifetime.
Development
The project follows the same quality baseline as the other Kaly packages:
composer test
This runs PHPUnit, PHPStan at max level with bleeding edge enabled, Mago linting and Mago format checks.
Individual commands are also available:
composer phpunit composer phpstan composer mago:lint composer mago:format composer fmt composer demo
CI tests PHP 8.3, 8.4 and 8.5. Tagged releases automatically create a GitHub release.
License
MIT.