View Parser

The View Parser can perform simple text substitution forpseudo-variables contained within your view files.It can parse simple variables or variable tag pairs.

Pseudo-variable names or control constructs are enclosed in braces, like this:

  1. <html>
  2. <head>
  3. <title>{blog_title}</title>
  4. </head>
  5. <body>
  6. <h3>{blog_heading}</h3>
  7.  
  8. {blog_entries}
  9. <h5>{title}</h5>
  10. <p>{body}</p>
  11. {/blog_entries}
  12.  
  13. </body>
  14. </html>

These variables are not actual PHP variables, but rather plain textrepresentations that allow you to eliminate PHP from your templates(view files).

Note

CodeIgniter does not require you to use this class sinceusing pure PHP in your view pages (for instance using theView renderer )lets them run a little faster.However, some developers prefer to use some form of template engine ifthey work with designers who they feel would find someconfusion working with PHP.

Using the View Parser Class

The simplest method to load the parser class is through its service:

  1. $parser = \Config\Services::parser();

Alternately, if you are not using the Parser class as your default renderer, youcan instantiate it directly:

  1. $parser = new \CodeIgniter\View\Parser();

Then you can use any of the three standard rendering methods that it provides:render(viewpath, options, save), setVar(name, value, context) andsetData(data, context). You will also be able to specify delimiters directly,through the setDelimiters(left,right) method.

Using the Parser, your view templates are processed only by the Parseritself, and not like a conventional view PHP script. PHP code in such a scriptis ignored by the parser, and only substitutions are performed.

This is purposeful: view files with no PHP.

What It Does

The Parser class processes “PHP/HTML scripts” stored in the application’s view path.These scripts can not contain any PHP.

Each view parameter (which we refer to as a pseudo-variable) triggers a substitution,based on the type of value you provided for it. Pseudo-variables are notextracted into PHP variables; instead their value is accessed through the pseudo-variablesyntax, where its name is referenced inside braces.

The Parser class uses an associative array internally, to accumulate pseudo-variablesettings until you call its render(). This means that your pseudo-variable namesneed to be unique, or a later parameter setting will over-ride an earlier one.

This also impacts escaping parameter values for different contexts inside yourscript. You will have to give each escaped value a unique parameter name.

Parser templates

You can use the render() method to parse (or render) simple templates,like this:

  1. $data = [
  2. 'blog_title' => 'My Blog Title',
  3. 'blog_heading' => 'My Blog Heading'
  4. ];
  5.  
  6. echo $parser->setData($data)
  7. ->render('blog_template');

View parameters are passed to setData() as an associativearray of data to be replaced in the template. In the above example, thetemplate would contain two variables: {blogtitle} and {blog_heading}The first parameter to render() contains the name of the viewfile, Where _blog_template is the name of your view file.

Important

If the file extension is omitted, then the views are expected to end with the .php extension.

Parser Configuration Options

Several options can be passed to the render() or renderString() methods.

  • cache - the time in seconds, to save a view’s results; ignored for renderString()
    • cache_name - the ID used to save/retrieve a cached view result; defaults to the viewpath;
    • ignored for renderString()
    • saveData - true if the view data parameters should be retained for subsequent calls;
    • default is false
    • cascadeData - true if pseudo-variable settings should be passed on to nested
    • substitutions; default is true
  1. echo $parser->render('blog_template', [
  2. 'cache' => HOUR,
  3. 'cache_name' => 'something_unique',
  4. ]);

Substitution Variations

There are three types of substitution supported: simple, looping, and nested.Substitutions are performed in the same sequence that pseudo-variables were added.

The simple substitution performed by the parser is a one-to-onereplacement of pseudo-variables where the corresponding data parameterhas either a scalar or string value, as in this example:

  1. $template = '<head><title>{blog_title}</title></head>';
  2. $data = ['blog_title' => 'My ramblings'];
  3.  
  4. echo $parser->setData($data)->renderString($template);
  5.  
  6. // Result: <head><title>My ramblings</title></head>

The Parser takes substitution a lot further with “variable pairs”,used for nested substitutions or looping, and with some advancedconstructs for conditional substitution.

When the parser executes, it will generally

  • handle any conditional substitutions
  • handle any nested/looping substitutions
  • handle the remaining single substitutions

Loop Substitutions

A loop substitution happens when the value for a pseudo-variable isa sequential array of arrays, like an array of row settings.

The above example code allows simple variables to be replaced. What ifyou would like an entire block of variables to be repeated, with eachiteration containing new values? Consider the template example we showedat the top of the page:

  1. <html>
  2. <head>
  3. <title>{blog_title}</title>
  4. </head>
  5. <body>
  6. <h3>{blog_heading}</h3>
  7.  
  8. {blog_entries}
  9. <h5>{title}</h5>
  10. <p>{body}</p>
  11. {/blog_entries}
  12.  
  13. </body>
  14. </html>

In the above code you’ll notice a pair of variables: {blog_entries}data… {/blog_entries}. In a case like this, the entire chunk of databetween these pairs would be repeated multiple times, corresponding tothe number of rows in the “blog_entries” element of the parameters array.

Parsing variable pairs is done using the identical code shown above toparse single variables, except, you will add a multi-dimensional arraycorresponding to your variable pair data. Consider this example:

  1. $data = [
  2. 'blog_title' => 'My Blog Title',
  3. 'blog_heading' => 'My Blog Heading',
  4. 'blog_entries' => [
  5. ['title' => 'Title 1', 'body' => 'Body 1'],
  6. ['title' => 'Title 2', 'body' => 'Body 2'],
  7. ['title' => 'Title 3', 'body' => 'Body 3'],
  8. ['title' => 'Title 4', 'body' => 'Body 4'],
  9. ['title' => 'Title 5', 'body' => 'Body 5']
  10. ]
  11. ];
  12.  
  13. echo $parser->setData($data)
  14. ->render('blog_template');

The value for the pseudo-variable blog_entries is a sequentialarray of associative arrays. The outer level does not have keys associatedwith each of the nested “rows”.

If your “pair” data is coming from a database result, which is already amulti-dimensional array, you can simply use the database getResultArray()method:

  1. $query = $db->query("SELECT * FROM blog");
  2.  
  3. $data = [
  4. 'blog_title' => 'My Blog Title',
  5. 'blog_heading' => 'My Blog Heading',
  6. 'blog_entries' => $query->getResultArray()
  7. ];
  8.  
  9. echo $parser->setData($data)
  10. ->render('blog_template');

If the array you are trying to loop over contains objects instead of arrays,the parser will first look for an asArray method on the object. If it exists,that method will be called and the resulting array is then looped over just asdescribed above. If no asArray method exists, the object will be cast asan array and its public properties will be made available to the Parser.

This is especially useful with the Entity classes, which has an asArray methodthat returns all public and protected properties (minus the _options property) andmakes them available to the Parser.

Nested Substitutions

A nested substitution happens when the value for a pseudo-variable isan associative array of values, like a record from a database:

  1. $data = [
  2. 'blog_title' => 'My Blog Title',
  3. 'blog_heading' => 'My Blog Heading',
  4. 'blog_entry' => [
  5. 'title' => 'Title 1', 'body' => 'Body 1'
  6. ]
  7. ];
  8.  
  9. echo $parser->setData($data)
  10. ->render('blog_template');

The value for the pseudo-variable blog_entry is an associativearray. The key/value pairs defined inside it will be exposed insidethe variable pair loop for that variable.

A blog_template that might work for the above:

  1. <h1>{blog_title} - {blog_heading}</h1>
  2. {blog_entry}
  3. <div>
  4. <h2>{title}</h2>
  5. <p>{body}{/p}
  6. </div>
  7. {/blog_entry}

If you would like the other pseudo-variables accessible inside the “blog_entry”scope, then make sure that the “cascadeData” option is set to true.

Comments

You can place comments in your templates that will be ignored and removed during parsing by wrapping thecomments in a {# #} symbols.

  1. {# This comment is removed during parsing. #}
  2. {blog_entry}
  3. <div>
  4. <h2>{title}</h2>
  5. <p>{body}{/p}
  6. </div>
  7. {/blog_entry}

Cascading Data

With both a nested and a loop substitution, you have the option of cascadingdata pairs into the inner substitution.

The following example is not impacted by cascading:

  1. $template = '{name} lives in {location}{city} on {planet}{/location}.';
  2.  
  3. $data = [
  4. 'name' => 'George',
  5. 'location' => [ 'city' => 'Red City', 'planet' => 'Mars' ]
  6. ];
  7.  
  8. echo $parser->setData($data)->renderString($template);
  9. // Result: George lives in Red City on Mars.

This example gives different results, depending on cascading:

  1. $template = '{location}{name} lives in {city} on {planet}{/location}.';
  2.  
  3. $data = [
  4. 'name' => 'George',
  5. 'location' => [ 'city' => 'Red City', 'planet' => 'Mars' ]
  6. ];
  7.  
  8. echo $parser->setData($data)->renderString($template, ['cascadeData'=>false]);
  9. // Result: {name} lives in Red City on Mars.
  10.  
  11. echo $parser->setData($data)->renderString($template, ['cascadeData'=>true]);
  12. // Result: George lives in Red City on Mars.

Preventing Parsing

You can specify portions of the page to not be parsed with the {noparse}{/noparse} tag pair. Anything in thissection will stay exactly as it is, with no variable substitution, looping, etc, happening to the markup between the brackets.

  1. {noparse}
  2. <h1>Untouched Code</h1>
  3. {/noparse}

Conditional Logic

The Parser class supports some basic conditionals to handle if, else, and elseif syntax. All ifblocks must be closed with an endif tag:

  1. {if $role=='admin'}
  2. <h1>Welcome, Admin!</h1>
  3. {endif}

This simple block is converted to the following during parsing:

  1. <?php if ($role=='admin'): ?>
  2. <h1>Welcome, Admin!</h1>
  3. <?php endif ?>

All variables used within if statements must have been previously set with the same name. Other than that, it istreated exactly like a standard PHP conditional, and all standard PHP rules would apply here. You can use anyof the comparison operators you would normally, like ==, ===, !==, <, >, etc.

  1. {if $role=='admin'}
  2. <h1>Welcome, Admin</h1>
  3. {elseif $role=='moderator'}
  4. <h1>Welcome, Moderator</h1>
  5. {else}
  6. <h1>Welcome, User</h1>
  7. {endif}

Note

In the background, conditionals are parsed using an eval(), so you must ensure that you takecare with the user data that is used within conditionals, or you could open your application up to security risks.

Escaping Data

By default, all variable substitution is escaped to help prevent XSS attacks on your pages. CodeIgniter’s esc methodsupports several different contexts, like general html, when it’s in an HTML attr*, in css, etc. If nothingelse is specified, the data will be assumed to be in an HTML context. You can specify the context used by using the esc**filter:

  1. { user_styles | esc(css) }
  2. <a href="{ user_link | esc(attr) }">{ title }</a>

There will be times when you absolutely need something to used and NOT escaped. You can do this by adding exclamationmarks to the opening and closing braces:

  1. {! unescaped_var !}

Filters

Any single variable substitution can have one or more filters applied to it to modify the way it is presented. Theseare not intended to drastically change the output, but provide ways to reuse the same variable data but with differentpresentations. The esc filter discussed above is one example. Dates are another common use case, where you mightneed to format the same data differently in several sections on the same page.

Filters are commands that come after the pseudo-variable name, and are separated by the pipe symbol, |:

  1. // -55 is displayed as 55
  2. { value|abs }

If the parameter takes any arguments, they must be separated by commas and enclosed in parentheses:

  1. { created_at|date(Y-m-d) }

Multiple filters can be applied to the value by piping multiple ones together. They are processed in order, fromleft to right:

  1. { created_at|date_modify(+5 days)|date(Y-m-d) }

Provided Filters

The following filters are available when using the parser:

FilterArgumentsDescriptionExample
abs Displays the absolute value of a number.{ v|abs }
capitalize Displays the string in sentence case: all lowercasewith firstletter capitalized.{ v|capitalize}
dateformat (Y-m-d)A PHP date-compatible formatting string.{ v|date(Y-m-d) }
date_modifyvalue to add/ subtractA strtotime compatible string to modify the date,like +5 day or -1 week.{ v|date_modify(+1 day) }
defaultdefault valueDisplays the default value if the variable is empty orundefined.{ v|default(just in case) }
eschtml, attr, css, jsSpecifies the context to escape the data.{ v|esc(attr) }
excerptphrase, radiusReturns the text within a radius of words from a givenphrase. Same as excerpt helper function.{ v|excerpt(green giant, 20) }
highlightphraseHighlights a given phrase within the text using‘<mark></mark>’ tags.{ v|highlight(view parser) }
highlight_code Highlights code samples with HTML/CSS.{ v|highlight_code }
limit_charslimitLimits the number of characters to $limit.{ v|limit_chars(100) }
limit_wordslimitLimits the number of words to $limit.{ v|limit_words(20) }
local_currencycurrency, localeDisplays a localized version of a currency. “currency”valueis any 3-letter ISO 4217 currency code.{ v|local_currency(EUR,en_US) }
local_numbertype, precision,localeDisplays a localized version of a number. “type” can beone of: decimal, currency, percent, scientific, spellout,ordinal, duration.{ v|local_number(decimal,2,en_US) }
lower Converts a string to lowercase.{ v|lower }
nl2br Replaces all newline characters (n) to an HTML <br/> tag.{ v|nl2br }
number_formatplacesWraps PHP number_format function for use within theparser.{ v|number_format(3) }
prose Takes a body of text and uses the auto_typography()method to turn it into prettier, easier-to-read, prose.{ v|prose }
roundplaces, typeRounds a number to the specified places. Types of ceiland floor can be passed to use those functions instead.{ v|round(3) } { v|round(ceil) }
strip_tagsallowed charsWraps PHP strip_tags. Can accept a string of allowedtags.{ v|strip_tags(<br>) }
title Displays a “title case” version of the string, with alllowercase, and each word capitalized.{ v|title }
upper Displays the string in all uppercase.{ v|upper }

See PHP’s NumberFormatter for details relevant to the“local_number” filter.

Custom Filters

You can easily create your own filters by editing app/Config/View.php and adding new entries to the$filters array. Each key is the name of the filter is called by in the view, and its value is any valid PHPcallable:

  1. public $filters = [
  2. 'abs' => '\CodeIgniter\View\Filters::abs',
  3. 'capitalize' => '\CodeIgniter\View\Filters::capitalize',
  4. ];

PHP Native functions as Filters

You can use native php function as filters by editing app/Config/View.php and adding new entries to the$filters array.Each key is the name of the native PHP function is called by in the view, and its value is any valid native PHPfunction prefixed with:

  1. public $filters = [
  2. 'str_repeat' => '\str_repeat',
  3. ];

Parser Plugins

Plugins allow you to extend the parser, adding custom features for each project. They can be any PHP callable, makingthem very simple to implement. Within templates, plugins are specified by {+ +} tags:

  1. {+ foo +} inner content {+ /foo +}

This example shows a plugin named foo. It can manipulate any of the content between its opening and closing tags.In this example, it could work with the text ” inner content “. Plugins are processed before any pseudo-variablereplacements happen.

While plugins will often consist of tag pairs, like shown above, they can also be a single tag, with no closing tag:

  1. {+ foo +}

Opening tags can also contain parameters that can customize how the plugin works. The parameters are represented askey/value pairs:

  1. {+ foo bar=2 baz="x y" }

Parameters can also be single values:

  1. {+ include somefile.php +}

Provided Plugins

The following plugins are available when using the parser:

PluginArgumentsDescriptionExample
current_url Alias for the current_url helper function.{+ current_url +}
previous_url Alias for the previous_url helper function.{+ previous_url +}
siteURL Alias for the site_url helper function.{+ siteURL “login” +}
mailtoemail, title, attributesAlias for the mailto helper function.{+ mailto email=foo@example.com title=”Stranger Things” +}
safe_mailtoemail, title, attributesAlias for the safe_mailto helper function.{+ safe_mailto email=foo@example.com title=”Stranger Things” +}
langlanguage stringAlias for the lang helper function.{+ lang number.terabyteAbbr +}
validation_errorsfieldname(optional)Returns either error string for the field (if specified) or all validation errors.{+ validation_errors +} , {+ validation_errors field=”email” +}
routeroute nameAlias for the route_to helper function.{+ route “login” +}

Registering a Plugin

At its simplest, all you need to do to register a new plugin and make it ready for use is to add it to theapp/Config/View.php, under the $plugins array. The key is the name of the plugin that isused within the template file. The value is any valid PHP callable, including static class methods, and closures:

  1. public $plugins = [
  2. 'foo' => '\Some\Class::methodName',
  3. 'bar' => function($str, array $params=[]) {
  4. return $str;
  5. },
  6. ];

Any closures that are being used must be defined in the config file’s constructor:

  1. class View extends \CodeIgniter\Config\View
  2. {
  3. public $plugins = [];
  4.  
  5. public function __construct()
  6. {
  7. $this->plugins['bar'] = function(array $params=[]) {
  8. return $params[0] ?? '';
  9. };
  10.  
  11. parent::__construct();
  12. }
  13. }

If the callable is on its own, it is treated as a single tag, not a open/close one. It will be replaced bythe return value from the plugin:

  1. public $plugins = [
  2. 'foo' => '\Some\Class::methodName'
  3. ];
  4.  
  5. // Tag is replaced by the return value of Some\Class::methodName static function.
  6. {+ foo +}

If the callable is wrapped in an array, it is treated as an open/close tag pair that can operate on any ofthe content between its tags:

  1. public $plugins = [
  2. 'foo' => ['\Some\Class::methodName']
  3. ];
  4.  
  5. {+ foo +} inner content {+ /foo +}

Usage Notes

If you include substitution parameters that are not referenced in yourtemplate, they are ignored:

  1. $template = 'Hello, {firstname} {lastname}';
  2. $data = [
  3. 'title' => 'Mr',
  4. 'firstname' => 'John',
  5. 'lastname' => 'Doe'
  6. ];
  7. echo $parser->setData($data)
  8. ->renderString($template);
  9.  
  10. // Result: Hello, John Doe

If you do not include a substitution parameter that is referenced in yourtemplate, the original pseudo-variable is shown in the result:

  1. $template = 'Hello, {firstname} {initials} {lastname}';
  2. $data = [
  3. 'title' => 'Mr',
  4. 'firstname' => 'John',
  5. 'lastname' => 'Doe'
  6. ];
  7. echo $parser->setData($data)
  8. ->renderString($template);
  9.  
  10. // Result: Hello, John {initials} Doe

If you provide a string substitution parameter when an array is expected,i.e. for a variable pair, the substitution is done for the opening variablepair tag, but the closing variable pair tag is not rendered properly:

  1. $template = 'Hello, {firstname} {lastname} ({degrees}{degree} {/degrees})';
  2. $data = [
  3. 'degrees' => 'Mr',
  4. 'firstname' => 'John',
  5. 'lastname' => 'Doe',
  6. 'titles' => [
  7. ['degree' => 'BSc'],
  8. ['degree' => 'PhD']
  9. ]
  10. ];
  11. echo $parser->setData($data)
  12. ->renderString($template);
  13.  
  14. // Result: Hello, John Doe (Mr{degree} {/degrees})

View Fragments

You do not have to use variable pairs to get the effect of iteration inyour views. It is possible to use a view fragment for what would be insidea variable pair, and to control the iteration in your controller insteadof in the view.

An example with the iteration controlled in the view:

  1. $template = '<ul>{menuitems}
  2. <li><a href="{link}">{title}</a></li>
  3. {/menuitems}</ul>';
  4.  
  5. $data = [
  6. 'menuitems' => [
  7. ['title' => 'First Link', 'link' => '/first'],
  8. ['title' => 'Second Link', 'link' => '/second'],
  9. ]
  10. ];
  11. echo $parser->setData($data)
  12. ->renderString($template);

Result:

  1. <ul>
  2. <li><a href="/first">First Link</a></li>
  3. <li><a href="/second">Second Link</a></li>
  4. </ul>

An example with the iteration controlled in the controller,using a view fragment:

  1. $temp = '';
  2. $template1 = '<li><a href="{link}">{title}</a></li>';
  3. $data1 = [
  4. ['title' => 'First Link', 'link' => '/first'],
  5. ['title' => 'Second Link', 'link' => '/second'],
  6. ];
  7.  
  8. foreach ($data1 as $menuitem)
  9. {
  10. $temp .= $parser->setData($menuItem)->renderString();
  11. }
  12.  
  13. $template = '<ul>{menuitems}</ul>';
  14. $data = [
  15. 'menuitems' => $temp
  16. ];
  17. echo $parser->setData($data)
  18. ->renderString($template);

Result:

  1. <ul>
  2. <li><a href="/first">First Link</a></li>
  3. <li><a href="/second">Second Link</a></li>
  4. </ul>

Class Reference

  • CodeIgniter\View\Parser
    • render($view[, $options[, $saveData=false]]])

Parameters:

  1. - **$view** (_string_) File name of the view source
  2. - **$options** (_array_) Array of options, as key/value pairs
  3. - **$saveData** (_boolean_) If true, will save data for use with any other calls, if false, will clean the data after rendering the view.Returns:

The rendered text for the chosen viewReturn type:string

Builds the output based upon a file name and any data that has already been set:

  1. echo $parser->render('myview');

Options supported:

  • cache - the time in seconds, to save a view’s results
  • cache_name - the ID used to save/retrieve a cached view result; defaults to the viewpath
  • cascadeData - true if the data pairs in effect when a nested or loop substitution occurs should be propagated
  • saveData - true if the view data parameter should be retained for subsequent calls
  • leftDelimiter - the left delimiter to use in pseudo-variable syntax
  • rightDelimiter - the right delimiter to use in pseudo-variable syntax

Any conditional substitutions are performed first, then remainingsubstitutions are performed for each data pair.

  • renderString($template[, $options[, $saveData=false]]])

Parameters:

  1. - **$template** (_string_) View source provided as a string
  2. - **$options** (_array_) Array of options, as key/value pairs
  3. - **$saveData** (_boolean_) If true, will save data for use with any other calls, if false, will clean the data after rendering the view.Returns:

The rendered text for the chosen viewReturn type:string

Builds the output based upon a provided template source and any data that has already been set:

  1. echo $parser->render('myview');

Options supported, and behavior, as above.

  • setData([$data[, $context=null]])

Parameters:

  1. - **$data** (_array_) Array of view data strings, as key/value pairs
  2. - **$context** (_string_) The context to use for data escaping.Returns:

The Renderer, for method chainingReturn type:CodeIgniter\View\RendererInterface.

Sets several pieces of view data at once:

  1. $renderer->setData(['name'=>'George', 'position'=>'Boss']);
  • Supported escape contexts: html, css, js, url, or attr or raw.
  • If ‘raw’, no escaping will happen.
  • setVar($name[, $value=null[, $context=null]])

Parameters:

  1. - **$name** (_string_) Name of the view data variable
  2. - **$value** (_mixed_) The value of this view data
  3. - **$context** (_string_) The context to use for data escaping.Returns:

The Renderer, for method chainingReturn type:CodeIgniter\View\RendererInterface.

Sets a single piece of view data:

  1. $renderer->setVar('name','Joe','html');
  • Supported escape contexts: html, css, js, url, attr or raw.
  • If ‘raw’, no escaping will happen.
  • setDelimiters($leftDelimiter = '{', $rightDelimiter = '}')

Parameters:

  1. - **$leftDelimiter** (_string_) Left delimiter for substitution fields
  2. - **$rightDelimiter** (_string_) right delimiter for substitution fieldsReturns:

The Renderer, for method chainingReturn type:CodeIgniter\View\RendererInterface.

Over-ride the substitution field delimiters:

  1. $renderer->setDelimiters('[',']');