View Parsing
The framework Parser in imspr/system/View/Parser.php transforms view templates using { and } delimiters, conditional tags, plugin tags, data placeholders, paired data blocks, and configured filters. It is separate from PDF document parsing and Kint inspection.
Services::parser() in imspr/system/Config/Services.php provides the construction boundary: the shared branch delegates to getSharedInstance('parser', $viewPath, $config). The non-shared branch supplies a default Config\View and view directory when needed, then constructs Parser with the view configuration, path, locator, CI_DEBUG, and logger.
Source-defined render flow
flowchart TD
r["Parser::render(view, options, saveData)"] --> e["Append .php when view has no extension"]
e --> c{"Cache option present and cache() returns a truthy value?"}
c -->|Yes| cached["Return cached output"]
c -->|No| local{"Local view file exists?"}
local -->|Yes| read["Read resolved file"]
local -->|No| locate["Views locator resolves the file"]
locate --> empty{"Resolved file is empty?"}
empty -->|Yes| invalid["Throw invalid-file ViewException"]
empty -->|No| read
read --> parse["Parser::parse(template, data, options)"]
parse --> clear["Clear parser data when saveData is false"]
clear --> save{"Cache option present?"}
save -->|Yes| cache["Save parsed output"]
save -->|No| result["Return output"]
cache --> result
For a non-empty template, parse() applies transformations in this order:
flowchart LR
p0["Input template"] --> p1["Replace PHP tags"]
p1 --> p2["Remove comments"]
p2 --> p3["Extract no-parse blocks"]
p3 --> p4["Process conditionals"]
p4 --> p5["Process plugins"]
p5 --> p6["Replace data"]
p6 --> p7["Restore no-parse blocks"]
p7 --> p8["Parsed template"]
An empty template returns an empty string before these stages. renderString() uses the same parsing path for a supplied string and also clears stored data when saveData is false.
Template syntax contract
| Construct | Source-defined behavior |
|---|---|
{key} |
Default scalar placeholder syntax. parseSingle() also recognizes optional ! no-escape markers and filter text after the key. |
{variable}...{/variable} |
Paired data syntax. parsePair() repeats the inner template for each row, recursively processes nested arrays, and replaces the complete paired region. |
{# ... #} |
parseComments() removes non-greedy comment regions. |
{noparse}...{/noparse} |
extractNoparse() replaces matching regions with hash-based placeholders before other parsing; insertNoparse() restores them afterward. |
{if ...}, {elseif ...}, {else}, {endif} |
parseConditionals() converts the tags to PHP control syntax and evaluates the generated template with the parser data. |
{+plugin ...+}...{+/plugin+} |
Paired plugin syntax. The registered callback receives the content and parsed parameters. |
{+plugin ...+} |
Unpaired plugin syntax. The registered callback receives the parsed parameters. |
key|filter |
applyFilters() extracts parameters, normalizes the filter name, and invokes only filters present in $this->config->filters. Unknown filter names are skipped. |
The default delimiters are declared as Parser::$leftDelimiter = '{' and Parser::$rightDelimiter = '}'. setDelimiters() can replace both delimiters.
Data and plugin handling
setData() merges supplied values into the parser’s existing data. When a context is supplied, it converts values through objectToArray() where applicable and records that context per key. Array values are handled as paired data during parsing; scalar values use scalar replacement.
Parser::__construct() copies $config->plugins into the parser’s plugin registry, defaulting to an empty array when the configuration property is absent. addPlugin() stores a callback under an alias; when $isPair is true, it stores the callback in a one-element array so parsePlugins() can distinguish paired tags. Plugin parameters support positional values and key=value values.
Replacement preparation splits chained filters on |. When a value is escapable and has no explicit filter, shouldAddEscaping() can add an esc({$context}) filter. A stored non-raw data context is used when present; a stored raw context suppresses automatic escaping; otherwise, when no context is stored, an unfiltered value defaults to HTML escaping. noescape suppresses automatic escaping, and an existing esc filter prevents another escaping filter from being added.
[!WARNING] The source establishes the parser implementation and service factory, but no application caller or observed rendering run proves that a particular application template path reaches it. A truthy result from
cache()in render() returns before file resolution, file reading, or parsing; a falsey result falls through to those steps. If the view lookup remains empty, render() throws the invalid-file view exception instead of falling through to parsing. Conditional tags are an evaluation boundary because generated PHP is passed toeval; a resultingParseErroris translated to the view tag-syntax exception.
Updated