SkillAgentSearch skills...

Flow

Fast PHP templating engine

Install / Use

/learn @nramenta/Flow
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Flow - Fast PHP Templating Engine

Introduction

Flow began life as a major fork of the original Twig templating engine by Armin Ronacher, which he made for [Chyrp], a now-defunct blogging engine. Flow features template inheritance, includes, macros, custom helpers, whitespace control and many little features that make writing templates enjoyable. Flow tries to give a consistent and coherent experience in writing clean templates. Flow compiles each template into its own PHP class; used in conjunction with PHP's OPcache, this makes Flow a very fast and efficient templating engine. Templates can be read from files, loaded from string arrays, or even from databases with relative ease.

Installation

The easiest way to install is by using [Composer]; the minimum composer.json configuration is:

{
    "require": {
        "flow/flow": "0.7.*"
    }
}

Flow requires PHP 7 or newer.

Usage

Using Flow in your code is straight forward:

<?php
require 'path/to/vendor/autoload.php';

use Flow\Loader;
use Flow\Adapter\FileAdapter;

$flow = new Loader(
    Loader::RECOMPILE_NORMAL,
    new FileAdapter('path/to/templates'),
    new FileAdapter('path/to/cache')
);

try {
    $template = $flow->load('home.html');
    $template->display([
        'data_1' => 'My first data',
        'data_2' => 'My second data',
    ]);
} catch (\Exception $e) {
    // something went wrong!
    die($e->getMessage());
}

The Loader constructor arguments are as follows:

  • mode: Recompilation mode.
  • source: Flow\Adapter object. See the section on loading templates from other sources near the bottom of this document.
  • target: Flow\Adapter object. See the section on loading templates from other sources near the bottom of this document.
  • helpers : Array of custom helpers.

The mode option can be one of the following:

  • Loader::RECOMPILE_NEVER: Never recompile an already compiled template.
  • Loader::RECOMPILE_NORMAL: Only recompile if the compiled template is older than the source file due to modifications.
  • Loader::RECOMPILE_ALWAYS: Always recompile whenever possible.

The default mode is Loader::RECOMPILE_NORMAL. If a template has never been compiled, or the compiled PHP file is missing, the Loader will compile it once regardless of what the current mode is.

In a typical development environment, the Loader::RECOMPILE_NORMAL mode should be used, while the Loader::RECOMPILE_NEVER mode should be used for production whenever possible. The Loader::RECOMPILE_ALWAYS mode is used only for internal debugging and testing purposes by the developers and should generally be avoided.

Two kinds of exceptions are thrown by Flow: SyntaxError for syntax errors, and RuntimeException for everything else.

Any reference to template files outside the source directory is considered to be an error.

Basic concepts

Flow uses {% and %} to delimit block tags. Block tags are used mainly for block declarations in template inheritance and control structures. Examples of block tags are block, for, and if. Some block tags may have a body segment. They're usually enclosed by a corresponding end<tag> tag. Flow uses {{ and }} to delimit output tags, {! and !} to delimit raw output tags, and {# and #} to delimit comments. Keywords and identifiers are case-sensitive.

Comments

Use {# and #} to delimit comments:

{# This is a comment. It will be ignored. #}

Comments may span multiple lines but cannot be nested; they will be completely removed from the resulting output.

Expression output

To output a literal, variable, or any kind of expression, use the opening {{ and the closing }} tags:

Hello, {{ username }}

{{ "Welcome back, " ~ username }}

{{ "Two plus two equals " ~ 2 + 2 }}

Raw expression output

To output a raw expression without doing any output escaping, use the opening {! and the closing !} tags:

The following will be HTML bold: {! "<b>bold text</b>" !}

Literals

There are several types of literals: numbers, strings, booleans, arrays, and null.

Numbers

Numbers can be integers or floats:

{{ 42 }} and {{ 3.14 }}

Large numbers can be separated by underscores to make it more readable:

Price: {{ 12_000 | number_format }} USD

The exact placing of _ is insignificant, although the first character must be a digit; any _ character inside numbers will be removed. Numbers are translated into PHP numbers and thus are limited by how PHP handles numbers with regards to upper/lower limits and precision. Complex numeric and monetary operations should be done in PHP using the GMP extension or the bcmath extension instead.

Strings

Strings can either be double quoted or single quoted; both recognize escape sequence characters. There are no support for variable extrapolation. Use string concatenation instead:

{{ "This is a string " ~ 'This is also a string' }}

You can also join two or more strings or scalars using the join operator:

{{ "Welcome," .. user.name }}

The join operator uses a single space character to join strings together.

Booleans

{{ true }} or {{ false }}

When printed or concatenated, true will be converted to 1 while false will be converted to an empty string. This behavior is consistent with the way PHP treats booleans in a string context.

Arrays

{{ ["this", "is", "an", "array"][0] }}

Arrays are also hash tables just like in PHP:

{{ ["foo" => "bar", 'oof' => 'rab']['foo'] }}

Printing arrays will cause a PHP notice to be thrown; use the join helper:

{{ [1,2,3] | join(', ') }}

Nulls

{{ null }}

When printed or concatenated, null will be converted to an empty string. This behavior is consistent with the way PHP treats nulls in a string context.

Operators

In addition to short-circuiting, boolean operators or and and returns one of their operands. This means you can, for example, do the following:

Status: {{ user.status or "default value" }}

Note that the strings '0' and '' are considered to be false. See the section on branching for more information. This behavior is consistent with the way PHP treats strings in a boolean context.

Comparison operators can take multiple operands:

{% if 1 <= x <= 10 %}
<p>x is between 1 and 10 inclusive.</p>
{% endif %}

Which is equivalent to:

{% if 1 <= x and x <= 10 %}
<p>x is between 1 and 10 inclusive.</p>
{% endif %}

The in operator works with arrays, iterators and plain objects:

{% if 1 in [1,2,3] %}
1 is definitely in 1,2,3
{% endif %}

{% if 1 not in [4,5,6] %}
1 is definitely not in 4,5,6
{% endif %}

For iterators and plain objects, the in operator first converts them using a simple (array) type conversion.

Use ~ (tilde) to concatenate between two or more scalars as strings:

{{ "Hello," ~ " World!" }}

String concatenation has a lower precedence than arithmetic operators:

{{ "1 + 1 = " ~ 1 + 1 ~ " and everything is OK again!" }}

Will yield

1 + 1 = 2 and everything is OK again!

Use .. (a double dot) to join two or more scalars as string using a single space character:

{{ "Welcome," .. user.name }}

String output, concatenations and joins coerce scalar values into strings.

Operator precedence

Below is a list of all operators in Flow sorted and listed according to their precedence in descending order:

  • Attribute access: . and [] for objects and arrays
  • Filter chaining: |
  • Arithmetic: unary - and +, %, /, *, -, +
  • Concatenation: .., ~
  • Comparison: !==, ===, ==, !=, <>, <, >, >=, <=
  • Conditional: in, not, and, or, xor
  • Ternary: ? :

You can group subexpressions in parentheses to override the precedence rule.

Attribute access

Objects

You can access an object's member variables or methods using the . operator:

{{ user.name }}

{{ user.get_full_name() }}

When calling an object's method, the parentheses are optional when there are no arguments passed. The full semantics of object attribute access are as follows:

For attribute access without parentheses, in order of priority:

  1. If the attribute is an accessible member variable, return its value.
  2. If the object implements __get, invoke and return its value.
  3. If the attribute is a callable method, call and return its value.
  4. If the object implements __call, invoke and return its value.
  5. Return null.

For attribute access with parentheses, in order of priority:

  1. If the attribute is a callable method, call and return its value.
  2. If the object implements __call, invoke and return its value.
  3. Return null.

You can always force a method call by using parentheses.

Arrays

You can return an element of an array using either the . operator or the [ and ] operator:

{{ user.name }} is the same as {{ user['name'] }}

{{ users[0] }}

The . operator is more restrictive: only tokens of name type can be used as the attribute. Tokens of name type begins with an alphabet or an underscore and can only contain alphanumeric and underscore characters, just like PHP variables and function names.

One special attribute access rule for arrays is the ability to invoke closure functions stored in arrays:

<?php
$template = $flow->load('my_template.html');
$template->display([
    'user' => [
        'firstname' => 'Rasmus',
        'lastname'  => 'Lerdorf',
        'fullname'  => function($self) {
            return $self['firstname'] . ' ' .  $self['lastname'];
        },
    ],
]);

And call the fullname "method" in the template as follows:

{{ user.fullname }}

When invoked this way, the closure function will implicitly be passed the array it's in as the first argument. Extra arguments will be passed on to the closure function as the second and consecutive arguments. This rule lets you have arrays that behave not unlike

View on GitHub
GitHub Stars62
CategoryDevelopment
Updated1y ago
Forks5

Languages

PHP

Security Score

80/100

Audited on Dec 18, 2024

No findings