Primordyx Framework Documentation

View
in package

Static templating engine with template inheritance, includes, and custom filters

A lightweight yet powerful template engine that provides static-only access to template rendering functionality with comprehensive syntax support. Designed as a single static class for simplicity while offering advanced templating features including layout inheritance, partials, custom filters, and dot notation variable access.

Templating Features

  • Layout inheritance: {{extends}} and {{section}} syntax
  • Variable output: {{variable}} with optional filter chains
  • Control structures: {{if}}, {{elseif}}, {{else}}, {{endif}}
  • Loops: {{each item in array using 'template'}} syntax
  • Includes: {{include 'template'}} for static partials
  • Embeds: {{embed 'template' with [data]}} for dynamic partials
  • Custom filters: Register and use custom data transformations
  • Dot notation: Access nested array data with user.name syntax

Static Architecture

All functionality is accessed through static methods with shared global state. Template data, filters, sections, and configuration are maintained in static properties, making the engine simple to use but requiring careful state management in complex applications.

Template Compilation Process

  1. File Loading: Template files loaded from configured view path
  2. Syntax Compilation: Custom template syntax compiled to PHP code
  3. Variable Extraction: Template data extracted into local scope
  4. Code Execution: Compiled PHP code executed with output buffering
  5. Layout Processing: Section content inserted into layout templates

Usage Patterns

Tags
example

Basic Template Rendering

// Set template directory and shared data
View::path('/app/views');
View::with(['user' => $userData, 'title' => 'Dashboard']);

// Render template to browser
View::output('dashboard.php');
example

Template Inheritance

// layout.php:
// <html><head><title>{{title}}</title></head>
// <body>{{fill 'content'}}</body></html>

// page.php:
// {{extends 'layout.php'}}
// {{section 'content'}}<h1>{{heading}}</h1>{{endsection}}

View::with(['title' => 'My Page', 'heading' => 'Welcome']);
View::output('page.php');
example

Custom Filters

// Register custom filter
View::registerCustomFilter('currency', fn($val) => '$' . number_format($val, 2));

// Use in template: {{price|currency}}
View::with(['price' => 29.99]);
View::output('product.php'); // Outputs: $29.99
since
1.0.0

Table of Contents

Properties

$data  : array<string, mixed>
$filters  : array<string, callable>
$layout  : string|null
$sections  : array<string, string>
$viewPath  : string|null

Methods

applyFilter()  : mixed
Apply a registered filter to a value with optional parameter
output()  : void
Render and output a template to the browser
path()  : string|null
Get or set the view templates directory path
registerCustomFilter()  : void
Register a custom filter function for use in templates
share()  : void
Set a single key-value pair in shared template data
with()  : void
Merge data array into shared template data
compile()  : string
Compile template syntax into executable PHP code
parseExpression()  : string
Parse template expressions with filters into PHP code
render()  : string
Render a template file with data and return compiled content
resolveArray()  : array<string, mixed>
Parse array syntax from template and resolve variables
resolveVar()  : mixed
Resolve a dot notation variable from template data at runtime
varAccess()  : string
Convert dot notation to PHP array access syntax

Properties

$data

protected static array<string, mixed> $data = []

Shared data available to all templates

Global template data storage that persists across template renders. All data added via with() or share() methods is stored here and made available to templates through variable extraction. Supports nested arrays accessible via dot notation in templates.

$filters

protected static array<string, callable> $filters = []

Custom filters registered by the user

Registry of custom filter functions that can be applied to template variables using pipe syntax. Each filter is a callable that receives the value and optional parameter, returning the transformed value.

Built-in 'default' filter is handled specially in parseExpression().

$layout

protected static string|null $layout = null

Current layout template

Stores the layout template filename when a template uses {{extends 'layout'}} syntax. During output(), if a layout is set, the main template content is rendered first to populate sections, then the layout is rendered.

$sections

protected static array<string, string> $sections = []

Template sections for layout inheritance

Storage for template sections captured during compilation. When templates use {{section 'name'}}content{{endsection}} syntax, the content is stored here and can be inserted into layouts using {{fill 'name'}}.

$viewPath

protected static string|null $viewPath = null

Path to view templates directory

Base filesystem path where template files are located. All template filenames passed to render() and output() methods are resolved relative to this path. Must be set before rendering any templates.

Methods

applyFilter()

Apply a registered filter to a value with optional parameter

public static applyFilter(string $filter, mixed $value[, mixed $arg = null ]) : mixed

Executes custom filter functions registered via registerCustomFilter(). Called during template execution when variables use pipe syntax with custom filters. Provides safe execution with fallback for missing filters.

Filter Execution

Looks up filter function in the $filters registry and calls it with the value and optional parameter. If filter doesn't exist, returns the original value unchanged to prevent template errors.

Parameter Handling

Second parameter is optional and comes from template syntax like {{variable|filter:'parameter'}} where 'parameter' becomes the second argument to the filter function.

Parameters
$filter : string

Filter name from template syntax

$value : mixed

Value to filter

$arg : mixed = null

Optional parameter for the filter

Tags
example

Filter Application

// Template: {{name|upper}}
// Calls: applyFilter('upper', $nameValue)

// Template: {{text|truncate:'50'}}
// Calls: applyFilter('truncate', $textValue, '50')
see
View::registerCustomFilter()

Filter registration

see
View::parseExpression()

Filter parsing during compilation

since
1.0.0
Return values
mixed

Filtered value or original value if filter not found

output()

Render and output a template to the browser

public static output(string $template) : void

Main template rendering method that compiles and outputs a template directly to the browser. Handles layout inheritance by first rendering the main template to populate sections, then rendering the layout template if one was specified via {{extends}} syntax.

Layout Processing Order

  1. Main Template: Rendered first to capture sections and determine layout
  2. Layout Template: If {{extends}} was used, layout is rendered with populated sections
  3. Direct Output: If no layout, main template output is sent directly to browser

Section Population

During main template rendering, {{section}} blocks are captured into the $sections array. The layout can then insert this content using {{fill}} syntax.

Parameters
$template : string

Template filename relative to view path

Tags
throws
RuntimeException

If template file not found or compilation/execution fails

example

Simple Template Output

View::path('/app/views');
View::with(['title' => 'Home', 'user' => $userData]);
View::output('home.php'); // Renders and outputs directly
example

Layout Inheritance Output

// page.php contains: {{extends 'layout.php'}}
View::output('page.php');
// 1. Renders page.php (captures sections, sets layout)
// 2. Renders layout.php (inserts captured sections)
see
View::render()

Internal rendering logic

see
View::compile()

Template compilation process

since
1.0.0

path()

Get or set the view templates directory path

public static path([string|null $newViewPath = null ]) : string|null

Manages the base filesystem path where template files are located. Can function as both getter and setter depending on whether a parameter is provided. All template filenames in render() and output() calls are resolved relative to this path.

Path Resolution

Template files are loaded using: {$viewPath}/{$template}

Ensure the path exists and is readable before rendering templates, as file not found errors will be thrown during render() if templates can't be located.

Parameters
$newViewPath : string|null = null

New absolute filesystem path to set, or null to just get current value

Tags
example

Setting Template Directory

// Set template directory
View::path('/var/www/myapp/templates');

// Later render templates from that directory
View::output('home.php'); // Loads /var/www/myapp/templates/home.php
example

Temporary Path Change

// Save current path and temporarily change
$oldPath = View::path('/tmp/special-templates');
View::output('email.php'); // From special directory
View::path($oldPath); // Restore original path
see
View::render()

Template file loading process

since
1.0.0
Return values
string|null

The previous path value (useful for temporary path changes)

registerCustomFilter()

Register a custom filter function for use in templates

public static registerCustomFilter(string $name, callable $callback) : void

Adds a custom transformation function that can be applied to template variables using pipe syntax ({{variable|filtername}} or {{variable|filtername:'param'}}). Filters receive the variable value and optional parameter, returning the transformed result.

Filter Function Signature

Filters should accept (mixed $value, mixed $param = null) and return the transformed value. The $param comes from template syntax like |filter:'param'.

Built-in Filters

The 'default' filter is handled specially by the template engine and doesn't need to be registered. It provides fallback values for null/empty variables.

Parameters
$name : string

Filter name to use in template pipe syntax

$callback : callable

Function to execute for this filter

Tags
example

Custom Filter Registration

// Register formatting filters
View::registerCustomFilter('upper', fn($val) => strtoupper($val));
View::registerCustomFilter('currency', fn($val) => '$' . number_format($val, 2));
View::registerCustomFilter('truncate', fn($val, $len) => substr($val, 0, $len) . '...');

// Use in templates:
// {{name|upper}}
// {{price|currency}}
// {{description|truncate:'50'}}
example

Advanced Filter with Parameter

View::registerCustomFilter('pluralize', function($count, $word) {
    return $count . ' ' . ($count == 1 ? $word : $word . 's');
});

// Template: {{itemCount|pluralize:'item'}}
// Output: "1 item" or "5 items"
see
View::applyFilter()

Filter execution during template compilation

see
View::parseExpression()

Template filter syntax parsing

since
1.0.0

share()

Set a single key-value pair in shared template data

public static share(string $key, mixed $value) : void

Adds or updates a single variable in the global template data storage. More convenient than with() when setting individual values, especially in conditional logic or loops where you need to set data incrementally.

Direct Assignment

Uses direct array assignment rather than merging, so it's slightly more efficient for single values than with(['key' => 'value']).

Parameters
$key : string

The variable name to use in templates

$value : mixed

The value to assign (any type supported)

Tags
example

Conditional Data Setting

// Set data conditionally
View::share('userRole', $user->isAdmin() ? 'admin' : 'user');
View::share('debugMode', APP_DEBUG);

// Use in templates: {{userRole}}, {{debugMode}}
example

Incremental Data Building

View::share('pageTitle', 'Products');

if ($category) {
    View::share('categoryName', $category->name);
    View::share('breadcrumbs', $category->getBreadcrumbs());
}

View::output('products.php');
see
View::with()

For setting multiple values at once

see
View::$data

Global template data storage

since
1.0.0

with()

Merge data array into shared template data

public static with(array<string, mixed> $data) : void

Adds multiple key-value pairs to the global template data storage using array_merge(). New data is merged with existing data, with new values overriding existing keys. All merged data becomes available in templates as variables and via dot notation access.

Data Persistence

Data added via with() persists across all subsequent template renders until explicitly overridden or the request ends. This makes it ideal for setting common data like user information, site configuration, or shared variables.

Array Merging Behavior

Uses array_merge() so numeric keys are reindexed, but string keys preserve their associations. Nested arrays are not recursively merged.

Parameters
$data : array<string, mixed>

Associative array of data to merge into template context

Tags
example

Basic Data Sharing

// Set common template data
View::with([
    'siteName' => 'My Website',
    'user' => ['name' => 'John', 'role' => 'admin'],
    'navigation' => $menuItems
]);

// All templates now have access to these variables:
// {{siteName}}, {{user.name}}, {{user.role}}
example

Controller Data Pattern

// In controller, set page-specific data
View::with([
    'pageTitle' => 'User Dashboard',
    'userData' => $user->getData(),
    'stats' => $analytics->getStats()
]);
View::output('dashboard.php');
see
View::share()

For setting single key-value pairs

see
View::$data

Global template data storage

since
1.0.0

compile()

Compile template syntax into executable PHP code

protected static compile(string $template) : string

Transforms custom template syntax into PHP code through a series of regex replacements. Handles all template features including inheritance, control structures, loops, includes, embeds, and variable output with filters.

Compilation Order

Template syntax is processed in specific order to handle dependencies:

  1. Layout inheritance: {{extends}} and {{section}} blocks
  2. Section insertion: {{fill}} syntax for layout content
  3. Control structures: {{if}}/{{else}}/{{endif}} blocks
  4. Loop syntax: {{each}} constructs with template rendering
  5. Include/Embed: Static and dynamic partial rendering
  6. Variable output: {{variable}} with optional filter chains

Each Loop Processing

The {{each item in array using 'template'}} syntax supports dot notation for nested arrays and renders the specified template for each item with the item data merged into template context.

Filter Chain Support

Variable output supports filter chains like {{variable|filter1|filter2:'param'}} which are converted to nested function calls during compilation.

Parameters
$template : string

Raw template content from file

Tags
example

Template Syntax Compilation

// Input template syntax:
// {{extends 'layout.php'}}
// {{if user.isAdmin}}{{name|upper}}{{endif}}

// Compiled PHP output:
// <?php if ($user['isAdmin']): ?>
// <?php echo strtoupper($name); ?>
// <?php endif; ?>
see
View::parseExpression()

Variable and filter parsing

see
View::resolveVar()

Dot notation resolution

since
1.0.0
Return values
string

Compiled PHP code ready for execution

parseExpression()

Parse template expressions with filters into PHP code

protected static parseExpression(string $expr) : string

Converts template variable expressions with optional filter chains into executable PHP code. Handles pipe syntax for chaining multiple filters and the special 'default' filter for fallback values.

Filter Chain Processing

Processes filters left-to-right, with each filter receiving the output of the previous step. The special 'default' filter uses PHP null coalescing rather than a registered function for better performance.

Variable Resolution

Variables are resolved through varAccess() to handle dot notation like user.profile.name becoming $user['profile']['name'].

Parameters
$expr : string

Template expression like "name|upper|default:'Anonymous'"

Tags
example

Filter Chain Parsing

// Input: "user.name|upper|default:'Guest'"
// Output: "\\Primordyx\\View::applyFilter('upper', ($user['name']) ?? 'Guest')"
example

Default Filter Handling

// Input: "title|default:'Untitled'"
// Output: "($title) ?? 'Untitled'"
see
View::varAccess()

Dot notation to PHP array access conversion

see
View::applyFilter()

Filter execution wrapper

since
1.0.0
Return values
string

PHP code for the expression

render()

Render a template file with data and return compiled content

protected static render(string $template, array<string, mixed> $vars) : string

Core template processing method that handles file loading, compilation, variable extraction, and PHP code execution. Used internally by output() and recursively by include/embed template syntax. Returns the rendered content as a string rather than outputting directly.

Processing Pipeline

  1. Path Resolution: Builds full filesystem path from view path and template name
  2. File Validation: Checks file exists and provides helpful error with available files
  3. Compilation: Converts template syntax to executable PHP code
  4. Variable Extraction: Makes template data available as local PHP variables
  5. Code Execution: Executes compiled PHP with output buffering
  6. Error Handling: Wraps execution in try-catch with detailed error information

Variable Scope

Template data is extracted into local scope, so $data['user'] becomes $user within the template. This allows natural PHP variable access alongside template syntax.

Error Reporting

Provides detailed error messages including:

  • Full filesystem path attempted
  • List of available files in view directory
  • Compiled PHP code when execution fails
Parameters
$template : string

Template filename relative to view path

$vars : array<string, mixed>

Data to make available in template scope

Tags
throws
RuntimeException

If template file not found or compilation/execution fails

example

Internal Template Rendering

// Used by include syntax: {{include 'header.php'}}
$content = self::render('header.php', self::$data);
example

Partial Rendering with Custom Data

// Used by embed syntax: {{embed 'item.php' with ['item' => $product]}}
$customData = array_merge(self::$data, ['item' => $product]);
$content = self::render('item.php', $customData);
see
View::compile()

Template compilation process

see
View::output()

Public template output method

since
1.0.0
Return values
string

Rendered template content

resolveArray()

Parse array syntax from template and resolve variables

protected static resolveArray(string $input) : array<string, mixed>

Processes array syntax used in {{embed}} directives to create data arrays with resolved variables. Parses template syntax like ['key' => variable] and resolves variable references to actual values from template data.

Array Syntax Support

Handles template syntax where array values are variable references rather than literal values. The variable references are resolved using resolveVar() to get actual values from the template data context.

Merge Behavior

Returns merged array of template data and resolved array values, allowing embedded templates to access both global data and specific passed values.

Parameters
$input : string

Array syntax from template like "['item' => product.name]"

Tags
example

Array Syntax Parsing

// Template: {{embed 'item.php' with ['product' => item.name, 'price' => item.cost]}}
// Input: "['product' => item.name, 'price' => item.cost]"
// Returns merged array with resolved item.name and item.cost values
see
View::resolveVar()

Variable resolution used for array values

since
1.0.0
Return values
array<string, mixed>

Merged data array with resolved variables

resolveVar()

Resolve a dot notation variable from template data at runtime

protected static resolveVar(string $expr) : mixed

Walks through template data array using dot notation path to extract nested values. Used by template compilation for dynamic operations like {{each}} loops where variable paths need to be resolved at runtime rather than compile time.

Resolution Process

Starting with the full template data array, walks through each dot-separated segment as an array key. Returns null if any segment in the path doesn't exist or if a non-array is encountered where an array is expected.

Safe Navigation

Provides safe navigation through nested structures - missing keys or type mismatches return null rather than throwing errors.

Parameters
$expr : string

Dot notation expression to resolve

Tags
example

Simple Variable Resolution

// Template data: ['title' => 'My Page']
// resolveVar('title') returns 'My Page'
example

Nested Array Resolution

// Template data: ['user' => ['profile' => ['name' => 'John']]]
// resolveVar('user.profile.name') returns 'John'
// resolveVar('user.missing.name') returns null
see
View::varAccess()

Compile-time equivalent for PHP code generation

since
1.0.0
Return values
mixed

The resolved value or null if path not found

varAccess()

Convert dot notation to PHP array access syntax

protected static varAccess(string $expr) : string

Transforms template dot notation like 'user.profile.name' into PHP array access syntax like "$user['profile']['name']". Supports arbitrary nesting depth and handles variable names with underscores and alphanumeric characters.

Syntax Transformation

  • First segment becomes PHP variable: user → $user
  • Additional segments become array keys: .name → ['name']
  • Chained access: user.profile.name → $user['profile']['name']
Parameters
$expr : string

Dot notation expression from template

Tags
example

Basic Variable Access

// Input: "title"
// Output: "$title"
example

Nested Array Access

// Input: "user.profile.email"
// Output: "$user['profile']['email']"
see
View::parseExpression()

Expression parsing that uses this method

see
View::resolveVar()

Runtime variable resolution

since
1.0.0
Return values
string

PHP variable access code


        
On this page

Search results