- Introduction
- Usage
- Configuration for Bow
- Displaying data
- The %verbatim directive
- The
%if
directives - The
%loop
/%for
/%while
directives - Conditional Classes and Styles
- Include subviews
- Raw PHP
- Flash session
- Service injection
- Authentication Directives
- Environment Guidelines
- Field CSRF
- Method Field
- Inheritance with %extends, %block and %inject
- The
%macro
directive
Tintin is a PHP template that is meant to be very simple and extensible. It can be used in any PHP project.
To install the package it will be better to use composer
which is a php
package manager.
composer require bowphp/tintin
You can use the package simply, like this. But except that this way of doing things does not allow you to exploit the inheritance system optimally. Use this way of doing things, only if you want to test the package or for small applications.
require 'vendor/autoload.php';
$tintin = new Tintin\Tintin;
echo $tintin->render('Hello, world {{ strtoupper($name) }}', ['name' => 'tintin']);
// -> Hello, world TINTIN
To use the package properly, you should follow the following configuration:
require 'vendor/autoload.php';
$loader = new Tintin\Loader\Filesystem([
'path' => '/path/to/the/views/source',
'extension' => 'tintin.php',
'cache' => '/path/to/the/cache/directory'
]);
$tintin = new Tintin\Tintin($loader);
parameter | Description |
---|---|
php | The path to the views folder of your application |
extension | the extension of the template files. By default, the value is tintin.php |
cache | The cache folder. This is where tintin will create the cache. If it is not set, tintin will cache the compiled files in the temporary directory of php . |
// Configuration done beforehand
$tintin = new Tintin\Tintin($loader);
$tintin->render('filename', ['name' => 'data']);
// Or
$tintin->render('folder/filename', ['name' => 'data']);
// Or
$tintin->render('folder.filename', ['name' => 'data']);
Note that the source of the files is always the path to
path
.
To allow Bow to use Tintin as the default template engine, you will need to do some small configuration.
Add this configuration in the app/Kernel.php
file:
public function configurations() {
return [
...
\Tintin\Bow\TintinConfiguration::class,
...
];
}
And again in the views configuration file located in config/view.php
.
Bow framework currently uses tintin as the default template
return [
// Set the engine to use
'engine' => 'tintin',
// File extension
'extension' => '.tintin.php'
];
And that's it, now your default template engine is tintin
👍
You can display the content of the name variable in the following way:
Hello, {{ $name }}.
Of course, you are not limited to displaying the contents of variables passed to the view. You can also echo the results of any PHP function. In fact, you can insert any PHP code into an echo Tintin statement:
Hello, {{ strtoupper($name) }}.
Tintin
{{ }}
statements are automatically sent through the PHPhtmlspecialchars
function to prevent XSS attacks.
By default, Tintin {{ }}
statements are automatically sent through the PHP htmlspecialchars
function to prevent XSS attacks. If you do not want your data to be protected, you can use the following syntax:
Hello, {{{ $name }}}.
This clause {## ##}
allows you to add a comment to your tintin
code.
{## This comment will not be present in the rendered HTML ##}
If you display JavaScript variables in a large part of your template, you can wrap the HTML code in the %verbatim
directive so that you don't have to prefix each Tintin echo statement with a %
symbol:
%verbatim
<div class="container">
Hello, {{ name }}.
</div>
%endverbatim
These are the clauses that allow you to establish conditional branching as in most programming languages.
You can build if statements using the %if
, %elseif
, %elif
, %else
, and %endif
directives. These directives work the same way as their PHP counterparts:
%if ($name == 'tintin')
{{ $name }}
%elseif ($name == 'template')
{{ $name }}
%else
{{ $name }}
%endif
You can use
%elif
instead of%elseif
.
A small specificity, the %unless
allows to make a condition inverse to the %if
.
To make it simple, here is an example:
%unless ($user->isAdmin())
// do something else
$endunless
In addition to the conditional directives already discussed, the %isset
, %empty
, %notempty
directives can be used as convenient shortcuts for their respective PHP functions:
%isset($records)
// $records is defined and is not null...
%endisset
%empty($records)
// $records is "empty"...
%endempty
%notempty($records)
// $records is not "empty"...
%notendempty
You can add
%esle
to perform an opposite action
Often you may need to make lists or repetitions on elements. For example, display all users of your platform.
This clause does exactly the action of foreach
.
%loop($names as $name)
Hello {{ $name }}
%endloop
This clause can also be coupled with any other clause such as %if
.
A quick example.
%loop($names as $name)
%if($name == 'tintin')
Hello {{ $name }}
%stop
%endif
%endloop
You may have noticed the %stop
it allows to stop the execution of the loop. There is also its spouse the %jump
, it on the other hand allows to stop the execution at its level and to launch the execution of the next turn of the loop.
Often the developer is led to make conditions to stop the loop %loop
like this:
%loop($names as $name)
%if($name == 'tintin')
%stop
// Or
%jump
%endif
%endloop
With syntactic sugars, we can reduce the code like this:
%loop($names as $name)
%stop($name == 'tintin')
// Or
%jump($name == 'tintin')
%endloop
This clause does exactly the action of for
.
%for($i = 0; $i < 10; $i++)
//..
%endfor
This clause does exactly the action of while
.
%while($name != 'tintin')
//..
%endwhile
The %class
directive conditionally compiles a CSS class string. The directive accepts an array of classes where the array key contains the class(es) you want to add, while the value is a boolean expression. If the array element has a numeric key, it will always be included in the rendered class list:
%php
$isActive = false;
$hasError = true;
%endphp
<span %class([
'p-4',
'font-bold' => $isActive,
'text-gray-500' => ! $isActive,
'bg-red' => $hasError,
])></span>
<span class="p-4 text-gray-500 bg-red"></span>
Similarly, the %style
directive can be used to conditionally add inline CSS styles to an HTML element:
%php
$isActive = true;
%endphp
<span %style([
'background-color: red',
'font-weight: bold' => $isActive,
])></span>
<span style="background-color: red; font-weight: bold;"></span>
Often when you develop your code, you are led to subdivide the views of your application to be more flexible and write less code.
%include
allows you to include another template file in another.
<div id="container">
%include('filename', %data)
</div>
If you try to include a view that does not exist, Tintin will throw an error. If you want to include a view that may or may not be present, you should use the %includeIf
directive:
%includeIf("filename", ["name" => "Tintin"])
If you want to %include
a view if a given boolean expression evaluates to true or false, you can use the %includeWhen
and %includeUnless
directives:
%includeWhen($user->isAdmin(), "include-file-name", ["name" => "Tintin"])
In some situations, it is useful to embed PHP code in your views. You can use the Tintin %php
or %raw
directive to execute a simple block of PHP in your template:
%php
$counter = 1;
%endphp
%raw
$counter = 1;
%endraw
In case you want to display a flash message directly on view you can use %flash
. And to check if a flash message exists %hasflash
and %endhasflash
:
%hasflash("error")
<div class="alert alert-danger">
%flash("error")
</div>
%endhasflash
The %service
directive can be used to retrieve a service from the container. The first argument passed to %service
is the name of the variable in which the service will be placed, while the second argument is the name of the class or interface of the service you want to resolve:
%service('user_service', 'App\Services\UserService')
<div>
%loop($user_service->all() as $user)
<p>{{ $user->name }}</p>
%endloop
</div>
The %auth
and %guest
directives can be used to quickly determine whether the current user is authenticated or a guest:
%auth
// The user is authenticated...
%endauth
%guest
// The user is not authenticated...
%endguest
If needed, you can specify the authentication guard that should be checked when using the directives %auth
and %guest
:
%auth('admin')
// The user is authenticated...
%endauth
%guest('admin')
// The user is not authenticated...
%endguest
You can check if the application is running in the production environment using the %production
directive:
%production
// Production specific content...
%endproduction
Or, you can determine if the application is running in a specific environment using the %env
directive:
%env('staging')
// The application is running in "staging"...
%endenv
%env(['staging', 'production'])
// The application is running in "staging" or "production"...
%endenv
Whenever you define an HTML form in your application, you must include a hidden CSRF token field in the form so that the CSRF protection middleware can validate the request. You can use the Tintin %csrf
directive to generate the token field:
<form method="POST" action="/profile">
%csrf
</form>
Since HTML forms cannot perform PUT
, PATCH
or DELETE
requests, you will need to add a hidden _method field to spoof these HTTP verbs. Tintin's %method
directive can create this field for you:
<form action="/foo/bar" method="POST">
%method('PUT')
</form>
Like any good template system tintin supports sharing code between files. This makes your code flexible and maintainable.
Consider the following tintin code:
# the `layout.tintin.php` file
<!DOCTYPE html>
<html>
<head>
<title>Hello, world</title>
</head>
<body>
<h1>Page header</h1>
<div>
%inject('content')
</div>
<p>Page footer</p>
</body>
</html>
And also, we have another file that inherits the code from the layout.tintin.php
file
# the file is called `content.tintin.php`
%extends('layout')
%block('content')
<p>This is the page content</p>
%endblock
The content.tintin.php
file will inherit the code from layout.tintin.php
and if you notice, in the file layout.tintin.php
we have the clause %inject
which has as parameter the name of the %block
of content.tintin.php
which is content
. Which means that the content of the %block
content
will be replaced by %inject
. Which will give at the end this:
<!DOCTYPE html>
<html>
<head>
<title>Hello, world</title>
</head>
<body>
<h1>Page header</h1>
<div>
<p>This is the page content</p>
</div>
<p>Page footer</p>
</body>
</html>
Tintin can be extended with its custom directive system, to do this use the directive
method
Let's create directives to manage a form:
$tintin->directive('input', function (string $type, string $name, ?string $value) {
return '<input type="'.$type.'" name="'.$name.'" value="'.$value.'" />';
});
$tintin->directive('button', function (string $type, string $label) {
return '<button type="'.$type.'">'.$label.'"</button>';
});
$tintin->directive('form', function (string $action, string $method, string $enctype = "multipart/form-data") {
return '<form action="'.$action.'" method="'.$method.'" enctype="'.$enctype.'">';
});
$tintin->directive('endform', function () {
return '</form>';
});
To use these directives, nothing could be simpler. Write the name of the directive preceded by %
. Then if this directive takes parameters, launch the directive as you launch the functions in your program.
<div class="container">
%form("/posts", "post", "multipart/form-data")
%input("text", "name")
%button('submit', 'Add')
%endform
</div>
Compilation is done as usual, for more information on compilation.
echo $tintin->render('form');
Output after compilation:
<form action="/posts" method="post" enctype="multipart/form-data">
<input type="text" name="name" value="" />
<button type="submit">Add</button>
</form>
In case you are using the Tintin configuration for Bow Framework.
Change your configuration in the ApplicationController::class
in the app/Configurations
folder.
namespace App\Configurations;
use Bow\Configuration\Loader as Config;
class ApplicationConfiguration extends Configuration
{
/**
* Launch configuration
*
* @param Config $config
* @return void
*/
public function create(Config $config): void
{
$tintin = app('view')->getEngine();
$tintin->directive('super', function () {
return "Super !";
});
}
}
Now the %super
directive is available and you can use it.
return $tintin->render('%super');
// => Super !
Often, you will be led to use or reuse a template block to optimize the writing of your application. So macros are there for that.
Macros must be defined in a separate file.
To use the %macro
you must pass first the macro name and then the macro parameters.
Consider the file user-macro.tintin.php
.
%macro('users', array $users)
%loop($users as $user)
<div>{{ $user }}</div>
%endloop
%endmacro
To use the macro you must import it into another file with %import
. We will call the file app.tintin.php
containing the following template:
%import('user-macro')
%extends('layout')
%block('content')
<div class="container">
{{ users($users) }}
</div>
%endblock
For the compilation we will pass the following list of users:
$users = ["franck", "lucien", "brice"];
$tintin->render('app', compact('users'));
After compiling the file
<div>franck</div>
<div>lucien</div>
<div>brice</div>