KoniKode · Software built with intention

KNOWLEDGE BASE

Documentation

DOCUMENTATION
CURRENT APPLICATIONClean Framework
DocumentationClean Framework

Clean Framework · DOCUMENTATION

Native PHP views

Native PHP views

Bounded candidate reference — 2026-10-20: 0.2.0-rc.1 is committed locally through 84f415b3098af5653577b2c65eea31fca21df79c, unpublished and not production-approved; stable PHP >=8.5.11 <8.6.0 is required. This is documentation, not adoption: this knowledge base retains its installed 0.1.0-rc.1 dependency and PHP 8.2.11 local profile. Dated PHP 8.2 evidence is historical; earlier dirty-source reports retain their original test provenance, not retroactive clean-commit proof. Candidate examples are illustrative: API signatures were reviewed, but candidate code was not executed by this editorial update. See current checkpoint, open criteria and adoption boundary.

Renderer executes ordinary PHP templates beneath one real filesystem root. It accepts only .php names, rejects null bytes/backslashes, resolves the real path, and verifies the result remains below the configured root. Symlink and ../ escapes therefore fail.

$html = $views->render('pages/show.php', [
    'title' => 'Example',
    'record' => $record,
]);

Valid array keys become local variables. Invalid PHP variable names are rejected. The renderer provides:

  • $render('partial.php', ['value' => $value]) for contained nested views;
  • through ViewFactory, $e($value) for HTML-text/attribute escaping.

Templates must escape at the output context. $e handles normal HTML text/attributes; JavaScript, URL, CSS, and JSON contexts require their proper encoder. A thrown exception cleans every buffer opened by the renderer and is re-thrown to the central exception boundary.

Next-candidate helpers: Escaper::url($url) accepts reviewed HTTP(S) or root-relative/query/fragment links, rejects executable/protocol-relative URLs and returns the HTML-escaped attribute value. It is not an outbound/redirect origin policy. Escaper::json($data) emits JSON with HTML-sensitive characters hex-encoded and throws on invalid JSON input. Do not wrap it in extra quotes or use it as a substitute for HTML escaping. Avoid dynamic CSS; choose trusted classes/closed allowlists instead of interpolating untrusted style values.

<a href="<?= \Clean\Framework\View\Escaper::url('/records?sort=new&limit=20') ?>">
    <?= $e($title) ?>
</a>

AuthenticationMiddleware now forces private, no-store, max-age=0 after an authenticated handler, overriding accidental public cache headers. Use separate non-personalized public endpoints for cacheable content. SecurityHeadersMiddleware now adds a same-origin CSP by default, without unsafe-inline. Explicit custom policies remain application-owned and must be reviewed; no static nonce is safe.

The skeleton includes a keyboard skip link, visible focus, reduced-motion rules and optional partials/form-errors.php. Pass validated field IDs/messages; controllers still own CSRF/validation and input aria-invalid/aria-describedby. The small external JS enhances summary focus only; no-JS links/HTML continue working. No AJAX/SPA implementation was enabled by these changes.

ViewFactory::share() supplies explicit application-wide presentation data. composer() can enrich selected views, but composers must remain read-oriented and must not perform provider calls or hidden writes. There is no eval, compiled source generation, global route state, or data-URI compatibility helper in the extracted runtime.

Template compilation/cacheability beyond PHP's normal OPcache is deferred. Use HTTP/cache headers and OPcache today; approve a separately tested design before adding compiled-template behavior.

Editorial provenance

Source: docs/VIEWS.md. Source SHA-256: ff62a0b997570c972c5666346c697f1cb62d6303c0e4c29b720d495f874e16f6.

Framework candidate reference; editorial checkpoint 2026-10-20. See candidate status and adoption boundary.

EXPLORE FURTHER

Drag a divider or use Left and Right Arrow keys to resize. Hold Shift for larger steps. Enter hides or restores the sidebar; Home and End select its minimum or maximum width. Double-click resets the width.

Install KoniKode