8.8 KiB
8.8 KiB
Scape Templates — Product Specification
Project Name
Scape Templates
Project Description
A lightweight, standalone PHP template engine designed for simplicity, security, and performance. Scape is built as an Output Engine first, focusing on marrying pre-processed data with design rather than performing additional business logic or data manipulation.
Project Purpose
To provide a modern, framework-agnostic alternative for template rendering that maintains a strict separation of concerns. Scape enforces a "logic-light" philosophy to ensure templates remain readable and focused purely on presentation.
Project Installation Instructions
Scape can be installed via Composer:
composer require getphred/scape
Project Features
1. File Handling & Configuration
- Template Extensions:
- All templates, layouts, and partials must use the
.scape.phpextension.
- All templates, layouts, and partials must use the
- Filter Extensions:
- Custom filters must use the standard
.phpextension. - All custom filters must implement the
Scape\Interfaces\FilterInterfaceto ensure they provide the necessary transformation methods.
- Custom filters must use the standard
- Directory Configuration: Template locations are managed via environment variables:
SCAPE_TEMPLATES_DIR: Main directory for application templates.SCAPE_LAYOUTS_DIR: Directory for base layouts and parent templates.SCAPE_PARTIALS_DIR: Directory for reusable snippets/partials.SCAPE_FILTERS_DIR: Directory for user-defined filters.
- Dot Notation Pathing: All internal paths (extends, includes) use dot notation (e.g.,
sidebar.login_form) relative to their respective directories, omitting the file extension.
2. Syntax & White-space
- All opening and closing tags are white-space independent (e.g.,
{{var}}is equivalent to{{ var }}). - Variable Interpolation:
{{ var }}: Automatically HTML-escaped output (usesENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5).{{{ var }}}: Raw, unescaped output.- Data Access:
- Use dot-notation for accessing class properties/attributes (e.g.,
user.name). - Use bracket notation for accessing array elements (e.g.,
items['title']orusers[0]).
- Use dot-notation for accessing class properties/attributes (e.g.,
3. Logic & Control Flow
- Syntax: Uses
{( ... )}for logic tags. - White-space Management: Logic tags
{( ... )}and block/inheritance tags{[ ... ]}automatically consume one trailing newline immediately following their closing)}or]}to prevent unintended vertical spacing in the rendered output. - "Logic-Light" Constraints:
- No generic programming or complex expressions.
- No
ifstatements or conditional branching (by design). - No manual variable assignment within templates.
- Loops:
- Only bounded iteration is supported:
foreach. - Grammar:
{( foreach item in collection )} ... {( endforeach )}{( foreach key, item in collection )} ... {( endforeach )}
- Every loop provides access to two local integer variables:
index: The current iteration index, 0-indexed (0, 1, 2...).pos: The current human-readable position, 1-indexed (1, 2, 3...).
- Positional Rendering: Special tags are available within loops to handle presentation based on position:
{( first )} ... {( endfirst )}: Renders only on the first iteration.{( inner )} ... {( endinner )}: Renders on all iterations except the first and last.{( last )} ... {( endlast )}: Renders only on the last iteration.
- Only bounded iteration is supported:
4. Inheritance & Reusability
- Syntax: Uses
{[ ... ]}for block and inheritance tags. - Layouts & Inheritance:
- Templates can extend layouts from
SCAPE_LAYOUTS_DIRusing{[ extends 'path' ]}. - The
extendstag must be the very first thing in a template.
- Templates can extend layouts from
- Blocks:
- Placeholder: Layouts define placeholders using
{[ block 'name' ]} ... {[ endblock ]}. - Override: Child templates provide content for these placeholders by defining a block with the same name.
- Parent Content: Within an override block, the child can render the layout's default content using the
{[ parent ]}tag. - Default Content: If a child template does not provide a block, the content within the layout's
blocktags is rendered as a default. - Nested Blocks: Blocks can be nested within other blocks.
- Placeholder: Layouts define placeholders using
- Partials:
- Reusable snippets from
SCAPE_PARTIALS_DIRcan be included using{[ include 'path' ]}. - Encapsulation: Partials are siloed by default and do not inherit the parent template's variables.
- Passing Data:
- Data can be passed as an array:
{[ include 'path' with data_source ]}. - The
data_sourcecan be a local variable, a nested array element (items['meta']), a class attribute (user.profile), or an inline array declaration (e.g.,['user' => user, 'id' => 1]). - The array keys from the source are expanded into individual local variables within the partial.
- The full parent context can be passed explicitly:
{[ include 'path' with context ]}.
- Data can be passed as an array:
- Nesting: Partials can include other partials. To prevent infinite recursion, the engine enforces a maximum nesting depth (default: 20).
- Reusable snippets from
5. Extensibility
- Filters:
- Used with variable interpolation to transform data.
- Piping: Supports chaining multiple filters:
{{ var | lower | ucfirst }}. - Arguments: Supports passing simple arguments (strings, numbers, or other variables):
{{ price | currency('USD') }}. - The
FilterInterface: All filters must implementScape\Interfaces\FilterInterface:public function transform(mixed $value, array $args = []): mixed; - Loading: Filters must be pre-loaded at the top of the template.
- Internal Libraries: Engine-provided filters are loaded using the
useskeyword:- Syntax:
{( uses namespace:library )}(e.g.,{( uses filters:string )}).
- Syntax:
- Custom Filters: User-defined filters are loaded from
SCAPE_FILTERS_DIRusingload_filter.- Syntax:
{( load_filter('path') )}where path is dot-notated.
- Syntax:
6. Security & Error Handling
- Contextual Escaping: Standard
{{ }}interpolation ensures XSS protection. - Missing Assets: If a layout or partial is missing, the engine looks for a user-provided
404.scape.phpinSCAPE_TEMPLATES_DIR. If not found, it renders a built-in "Template 404" placeholder. - Exceptions: The engine throws specific exceptions within the
Scape\Exceptionsnamespace:TemplateNotFoundException: Main template, layout, or partial missing.SyntaxException: Malformed tags or disallowed logic (e.g.if).FilterNotFoundException: Target ofusesorload_filtermissing.PropertyNotFoundException: (Debug only) Accessing undefined key/property.RecursionLimitException: Partials exceed nesting limit (default 20).
- Variable Access:
- Debug Mode: Accessing a non-existent object property or array key throws a
PropertyNotFoundException. - Production Mode: Accessing a non-existent property or key fails silently and renders an empty string.
- Debug Mode: Accessing a non-existent object property or array key throws a
7. Performance
- AST Caching: The engine caches the parsed Abstract Syntax Tree (AST) of templates to speed up subsequent renders.
- Cache Location: Cache files are stored locally in the project directory under
.scape/cache. - No Compiling: Scape does not compile templates into raw PHP files; it interprets the cached AST directly.
- Cache Modes:
- Development: Engine checks file modification times (
mtime) to invalidate the cache when a template changes. - Production: Engine skips
mtimechecks and serves the cached AST directly for maximum performance.
- Development: Engine checks file modification times (
8. Host Integration (IoC)
- The
hostNamespace: Scape provides a reservedhostnamespace that can be used with theuseskeyword or as a filter/function prefix. - Provider Registration: Host frameworks (e.g., Phred) can register custom providers to handle calls in this namespace.
- Use Cases: Used for framework-level features like feature flags (Flagpole), routing, or translations without creating a hard dependency within the engine.
- Default Behavior: If no provider is registered, calls to the
hostnamespace return the input value unchanged ornull.
9. Runtime API
- The
Scape\EngineClass: The primary entry point for the library. - Configuration Precedence: Programmatic Config > Environment Variables > Defaults.
- Rendering:
- Method:
public function render(string $template, array $data = []): string - The
$templateargument uses dot notation.
- Method:
- Mode Control: The engine operating mode (
debugvsproduction) can be set via theSCAPE_MODEenvironment variable or explicitly during instantiation.
Project Dependencies
- PHP: ^8.2
- PHPUnit: ^10.0 (Development)