Download the PHP package stempler/stempler without Composer
On this page you can find all versions of the php package stempler/stempler. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download stempler/stempler
More information about stempler/stempler
Files in stempler/stempler
Package stempler
Short Description Stempler, HTML markup processor and template engine framework
License MIT
Homepage https://github.com/stempler-php/stempler/
Informations about the package stempler
Stempler
Stempler is a standalone PHP template engine and HTML markup processor with support for Blade-like directives, context-aware escaping, inheritance, stacks, component imports, and AST visitors.
This project is a standalone fork of spiral/stempler without coupling to the Spiral Framework.
Installation
Requirements:
- PHP
>=8.1 ext-json
Quick Start
Render a file-based template
Create views/hello.dark.php:
Render it with DirectoryLoader:
Output:
DirectoryLoader resolves hello to views/hello.dark.php by default.
Enable filesystem cache
Cache is used only for filesystem-backed templates. Drop a single cached template with:
Render an in-memory template
Core API
Stempler::create(LoaderInterface $loader, iterable $directives = [], array $visitors = [], ?StemplerCache $cache = null): Stemplerrender(string $path, array $data = []): stringcompile(string $path): Resultload(string $path): TemplatemakeSourceMap(Result|string $source): ?SourceMapreset(string $path): void
Stempler templates also support raw PHP syntax:
Danger
{{ $name }}applies automatic escaping and is the safe default.<?= $name ?>does not escape output, so values must be escaped manually when needed.
Context-Aware escaping
The escape strategy changes depending on where you echo your value. You can safely embed values inside script tags:
It will be rendered differently depending on the value type:
:::: tabs
::: tab String
:::
::: tab Number
:::
::: tab Null
:::
::: tab List
:::
::: tab Array
:::
::::
Disable Escaping
To output a value without automatic escaping, use:
Example:
Template:
Output with disabled escaping:
Output with {{ $html }}:
Directives
In addition to the classic echo constructions, Stempler supports many Blade-like directives to control the business logic of your templates.
Unlike Blade or Twig, Stempler directives are only responsible for managing business logic.
Note See Inheritance to check how to extend your templates and implement virtual components.
Loop Directives
Stempler provides several loop directives to help you manage the rendering of repetitive elements in your templates. These directives make it easy to incorporate dynamic content into your templates.
Note The directive declaration is similar to native PHP syntax.
Foreach
Use the directive @foreach and @endforeach to render the loop:
For
Use the directive @for and @endfor to render the loop:
While
Use the directive @while and @endwhile to render while loop:
Break and Continue
Use the @break and @continue directives to interrupt your loops:
Note
@break(2)is equivalent tobreak 2. Read more aboutifdirectives below.
Conditional Directives
Stempler provides several directives for creating conditional statements in your templates. These directives are transcribed into native PHP code and offer a more readable and efficient way to handle conditions in your templates.
The examples are given with the following variables:
If and Else
To create a simple conditional statement, use the @if and @endif directives.
To add an else condition, use the @else directive.
For more complex conditions, use the @elseif directive.
Unless
The @unless directive allows you to create a negative condition, and can be used with @else and @elseif like
the @if directive.
Note You can use
@elseand@elseifwith the@unlessdirective.
Empty and Isset
Use the @empty and @isset conditions to check if a variable is empty or set, respectively.
:::: tabs
::: tab Empty
:::
::: tab Isset
:::
::::
Switch case
For more complex conditions, you can use the @switch, @case and @break statements.
Json Directive
The @json directive allows you to render JSON data within a page. To use it, simply pass a variable to the directive,
like this:
Note The
@jsondirective is equivalent tojson_encode($value).
And setting a variable:
And the output will be:
:::: tabs
::: tab String
In case of a string value ['value' => 'Hello world']:
:::
::: tab Number
In case of a number value ['value' => 123]:
:::
::: tab Null
In case of null value ['value' => null]:
:::
::: tab List
In case of an array ['value' => ['John']] value:
:::
::: tab Array
In case of an associative array ['value' => ['first' => 'John', 'last' => 'Doe']] value:
::: ::::
Embedding JSON data
It can be useful to embed JSON data inside JavaScript statements:
Here is an example of a view template with value ['value' => ['key' => 'value']]:
The generated view will then look like this:
Built-in directives
The standalone core includes these directive groups by default:
- conditional directives such as
@if,@elseif,@else,@unless,@isset,@empty, and@switch - loop directives such as
@foreach,@for,@while,@break, and@continue @json(...)- raw PHP via
@php ... @endphp
Framework-specific helpers such as routing or container access are intentionally out of scope for this package. Add them as custom directives in your application or use a framework integration package.
Raw PHP
To embed PHP logic in your template, use the classic ` tags or alternative@phpand@endphp`:
Escaping control '@' letter
Just double 'at' letter like
Custom Directives
Stempler provides a way to extend its functionality through custom directives. A custom directive is a class that
extends the Stempler\Directive\AbstractDirective class and implements a render method that accepts
a Stempler\Node\Dynamic\Directive parameter.
To create a custom directive, follow these steps:
Create a directive class
Create a class that extends Stempler\Directive\AbstractDirective and implements the render method with the
desired functionality.
Note It's also possible to implement the
Stempler\Directive\DirectiveRendererInterfacefor lower-level access to the rendering process.
Register the directive
Pass the custom directive to Stempler::create(). You can pass either a class name or an instance.
Use the directive
The custom directive can be used in the template by invoking it with the appropriate syntax.
Here is the template code:
And this is the final PHP code generated by the directive:
By using the custom directive, you can add custom functionality to the template engine and reuse it across different templates.
Passing values
You can pass values to a custom directive by using the body and values properties of the Directive object. These
properties can be used to access the values passed to the directive. This allows you to pass dynamic values to the
directive, making it more flexible and reusable.
Here is an example of using the body property:
Example:
:::: tabs
::: tab String
This directive will generate the following PHP code:
:::
::: tab Variable
This directive will generate the following PHP code:
:::
::: tab Constant
This directive will generate the following PHP code:
:::
::::
To access specific values passed to the directive separated by a comma:
Example:
This directive will generate the following PHP code:
Warning The values are not automatically escaped, so you must escape them manually before using them.
Accessing Directive Context
To get information about where a directive is invoked from, use the $directive->getContext()->getPath() method:
When this directive is processed, it will generate the following PHP code:
Inheritance and Stacks
As your views get more complex, it's crucial to separate pages and layout specific content between templates properly. Stempler provides several control statements to achieve this.
Extend Layout
Firts, let's create a standard HTML template for our page:
Most likely, your application will contain more than a one-page template. To avoid code duplication, Stempler provides an ability to inherit the parent layout.
Note Stempler will compile the template and parent layout into an optimized PHP code. You can exclude as many layouts as you want without a performance penalty.
Create a layout:
Now, we can extend this layout using the home.dark.php via extends:path tag:
Note Use the separator
.to include the directory name into your template.
Alternatively, use the syntax:
Note You can use view namespaces in such a declaration, for example:
<extends path="default:layout/base"/>.
Replace Blocks
Extending the parent layout does not make much sense unless we can redefine some of its content. To define a
replaceable block, use the tag <block:name>. Change the layout/base.dark.php accordingly:
Note You can include the default block content inside the
<block:name></block:name>tag pair.
To redefine the block values, use block:name or similar tags in the home.dark.php template:
Short Syntax
In cases when your block define a short string or operates as a tag argument, use the alternative
syntaxt ${name|default}. Change the layout to:
Short syntax values can be supplied to the parent layout via <block:name>value</block:name> tags.
You can pass some block values using the extends tag attributes to avoid large child templates,
change app/views/home.dark.php accordingly:
In both cases, the produced HTML will look like this:
Invoke Parent Content
To leave the parent block content, use <block:parent/> in any place of the redefined block:
The produced HTML:
Use ${parent}, to achieve the same goal in short block definitions:
The output:
Nested Layouts
It is possible to create layouts based on other layouts, create app/views/layout/page.dark.php:
Note Extend tags always require full path specification, make sure to include the
layoutdirectory.
You can extend this layout instead of base in app/views/home.dark.php:
The produced HTML:
Note You can nest as many templates as you need, it will only affect the compilation speed.
Stacks
Stempler includes the ability to aggregate multiple blocks defined within the template.
Classic Approach
You would often need to add a custom JS or CSS resource to your layout. To achieve it, use the block directives,
wrap the necessary resources in a block and append content to it in your child template.
Modify app/views/layout/base.dark.php as:
To add a custom style resource in your page template:
The produced HTML:
Create Stack
To demonstrate how the following can be achieved using stacks, we should start with a simple example
in app/views/home.dark.php. Create a stack placeholder using <stack:collect name="name"/>:
To append a value to stack:
The resulted HTML:
To prepend a value to stack:
The output:
You can locate stack definition before or after the push and prepend tags:
Deep Stacks
The stack tag will only aggregate push and prepend values if it's located on the same tag tree level.
For example, this will work:
While this example won't work:
Note This limitation is caused by the AST nature of stack collectors.
To bypass this limitation without moving the placeholder level higher, use thestack:collect attribute level:
The attribute level configures the stack to be multiple active levels higher. For example, this
example won't work:
But this one will:
Stacks in Layouts
You can push values to stacks defined in parent layouts. Modify app/views/layout/base.dark.php accordingly:
Now you can push the value from app/views/home.dark.php:
Note You have to make sure that
stack:pushis located in one of the extended blocks. See how to bypass it below.
Context and Hidden content
As you can see in the previous example, it's not convenient to use both the stack and blocks at the same time. This is
because that stack collection happens after the extension of the parent layout. Keeping the stack outside of any block
will leave it out of the template.
All the stempler blocks that are defined in the child template outside of the block tag will appear in the system
block context. We can modify the parent layout app/views/layout/base.dark.php like this:
Now we can define the stack in app/views/home.dark.php like this:
To understand how context works, take a look at the generated HTML:
Notice that some random string is added instead of block:context, this content was declared
by app/views/home.dark.php. You will most likely use the areas between block definitions of your templates for
comments and other control directives.
To hide such content from end use, use the <hidden></hidden> tag in app/views/layout/base.dark.php:
Now, stacking will work as before. However, some random string won't appear on a page.
Note Combine stacks with inheritance and components to create domain specific rendering DSL.
Components and Props
Stempler provides an ability to create developer-driven template components as virtual tags.
Simple Component
In many cases, your templates will not only reuse the parent layout, but also template partials, for example:
We can move the article div into a separate template app/views/partial/article.dark.php:
To use this partial on your page, first import it using the <use:element path=""/> control tag:
See more Read more about mass-importing partials below.
Props
It's is not very useful to create partials without the ability to configure their content. Use the block:name
or ${name|default} syntax (similar to the one described here) to define replaceable
parts:
In our partial app/views/partial/article.dark.php:
You can pass values similar way as in the extend control tag:
Note You can include the original block content using the
block:parenttag. Component expansion is also allowed.
The resulted HTML:
Note Components do not cause any performance penalty, use as many components as you need.
Import Components
Stempler provides several options for importing components into your template.
Import Element
To import a single component, use <use:element path=""/> before component invocation.
The component will be available using the filename, in this case it's article. To define a custom import alias, use
the tag attribute as:
Import Directory
To import all the partials from a given directory, use <use:dir dir="" ns=""/>. You must specify a namespace prefix to
avoid collisions with other components and default HTML tags:
Inline Import
To define a component specific to a given template without creating a physical view file,
use the <use:inline name=""></use:inline> control tag. In app/views/home.dark.php:
Bundle Import
Import multiple directories, components and/or inline components using bundled import via <use:bundle path="">.
Create a view file app/views/my-bundle.dark.php to define your bundle:
You can use any of the defined components in your app/views/home.dark.php template:
To isolate an imported bundle via the prefix, use the ns attribute of the use:bundle tag:
Props
The ability to pass values into components makes it possible to create complex elements that are condensed into simple tags. You are allowed to pass PHP values and echoes to your components.
Modify your controller to invoke the template like this:
Create app/views/partial/input.dark.php:
You can invoke this component in your template with a user supplied value:
The generated PHP:
PHP in Components
Not only can you inject values into plain HTML, but you can also inject source code into a PHP component. It can be
achieved using an AST modification of the underlying template via the macro function inject("name", default).
Note The injection will automatically extract the variable or statement from the passed
{{ echo }},` or<?=$variable?>` attributes.
To demonstrate it, modify app/views/partial/input.dark.php:
Now the generated code will look like this:
You can pass PHP values in combination with string prefixes, in app/views/home.dark.php:
The compiled template:
Complex Props
You can inject your props not only in echo statements, but also in any PHP code of your component. Let's create
the select component app/views/partial/select.dark.php:
Modify your controller to pass an array:
You can use this component in your template:
The generated template:
You are allowed to inject PHP blocks into default PHP tags. app/views/partial/select.dark.php can be changed like
this:
The generated template:
Note Attention, make sure to escape your values properly!
Dynamic Attributes
In some cases, you might want to bypass some attributes into elements directly. For example, to a allow user-driven
style attribute for select, we have to do the following:
Use attr:aggregate to scale this approach:
Now we can pass arbitrary attributes to our component from app/views/home.dark.php:
The resulted HTML:
Advancing DSL
Combine Stempler features such as props, AST code injections, stacks, and inheritance to develop a feature-rich domain language for page definitions.
Note Make sure to learn all the other aspects of Stempler before jumping into this section. You will also need a good cup of coffee.
The approach described in this article is possible because stacks can be defined within imported components.
Grid
Let's create a grid component to describe how to use stacks in combination with partials. The grid will consist of multiple view files.
Table
Create a root element for the component app/views/grid/table.dark.php:
Note Note
<hidden>${context}</hidden>, it allows the component to handle the content declared between the open and close tags without the need forblocktags.
Cell
Create an element app/views/grid/cell.dark.php to declare a single table cell with its header and value:
Note the
${context}.
Bundle
We can pack our elements into the bundle app/views/grid/bundle.dark.php:
Example
To render the grid in our template:
You can directly pass values into the cell context:
In both cases, the produced HTML is:
UI Assembly
Another example is related to the ability to assemble complex UI interfaces using custom DSL.
Base Layout
To demonstrate complex UI assembly, we are going to create an interface with the ability to easily push CSS, JS resources, and define context using multiple tabs instead of a single content block.
Create app/views/tabs/layout.dark.php:
Style and Script elements
To simplify registration of style and script elements, create the components app/views/tabs/script.dark.php
and app/views/tabs/style.dark.php:
Style:
Tab Element
Create the tab element similar to grid:cell in app/views/tabs/tab.dark.php:
Bundle
Create a bundle to represent the DSL for your UI framework app/views/tabs/bundle.dark.php:
Example
To render complex UI, modify app/views/home.dark.php.
Note You can import more than one bundle.
The generated HTML:
AST Modifications
The Stempler template engine fully exposes template AST (DOM) and provides an API for modifications similar to https://github.com/nikic/PHP-Parser.
You can create magical (in both ways) workflows and helpers by implementing your Node Visitors.
See more You can read more about how traversing
works here.
Create Visitor
To create an AST visitor, you must implement the interface provided by the Stempler engine
Stempler\VisitorInterface.
We will try to create a visitor that automatically adds an alt attribute to all img tags found in your templates:
Note You can inject other tags or even PHP into your templates.
Register Visitor
Pass visitors to Stempler::create() and group them by Builder stage:
Note If you use
StemplerCache, callreset()or clear the cache directory after changing visitors that affect the rendered output.
Now all the img tags will always include the alt attribute.
Low-level Usage
For most applications, Stempler::create() is the right entry point. If you need lower-level control over parsing,
AST traversal, or compilation, you can work with the building blocks directly.
Configuration
Use Stempler::create() to customize directives, visitors, and filesystem cache:
By default, the standalone core already registers:
PHPDirective,LoopDirective,JsonDirective, andConditionalDirective- prepare-stage visitors:
DefineBlocks,DefineAttributes,DefineHidden - finalize-stage visitors:
DefineStacks,StackCollector
Pretty Printing
Pretty printing is available from the core visitors. Register FlattenNodes and FormatHTML at the compile stage: