It's been a while
I have been using my own templating engine for a while now as I wasn't happy with how blade & co handle certain things. Additionally, any kind of logic within the view is a violation of separation of concerns in my view.
However, after living with a few issues for a while, I finally decided to rewrite it completely:
sroehrl / neoan3-template
neoan3 minimal template engine
neoan3-apps/template
PHP template engine
As of version 2, we dropped PHP 7.4 support You require at least PHP 8.0 or use v1.2.0 of this package.
Installation / Quick start
composer require neoan3-apps/template
use Neoan3\Apps\Template\Constants;
use Neoan3\Apps\Template\Template;
require_once 'vendor/autoload.php';
// optional, if set, path defines the relative starting point to templates
Constants::setPath(__DIR__ . '/templates');
echo Template::embrace('<h1>{{test}}</h1>',['test'=>'Hello World']);
Contents
Templating
neoan3-template is not a full blown template engine, but rather what a template engine should be: With modern JavaScript solutions creating a dynamic approach, neoan3-template focuses on the necessities of static rendering.
profile.html
<h1>{{user}}</h1>
<p>{{profile.name}}</p>
<p n-for="items as
…Happy accidents
I have had a way of adding project-specific functionality to the engine and wanted to keep it open for special needs.
By simplifying the hook-process, I noticed something interesting:
In theory, one can now use this package to create specific behavior utilizing two capabilities:
customFunctions
We are usually under full control of the data we are sending to the rendering mechanism when dealing with SSR sites, but sometimes we want to leave e.g. a model as is. So let's build a salutation template function:
Template\Constants::addCustomFunction('salutation', function($gender)
{
$salutation = 'Mrs.';
if($gender === 1){
$salutation = 'Mr.';
} elseif($gender > 1){
$salutation = 'Mx.';
}
});
In our template, we can now use this function:
<!-- profile.html -->
<div>
<p>Hello, {{salutation(user.gender)}} {{user.lastName}}</p>
</div>
$user = [
'gender' => 0,
'firstName' => 'Samantha',
'lastName' => 'Smith',
'birthDay' => '1990-06-06',
'website' => 'https://sam-smith-1990.com'
];
echo Template\Template::embraceFromFile('/profile.html', ['user' =>$user]);
output
<div>
<p>Hello, Mrs. Smith</p>
</div>
This is, of course, a very constructed example, but you get the idea. Another way of implementing additional functionality is via the method
customAttributes
With this we can hook into attribute-interpretation of the template engine. Let's have a look:
Template\Constants::addCustomAttribute('secure-link', function($attr)
{
$href = $attr->parentNode->getAttribute('href')->nodeValue;
// external?
if(
!str_contains($href, $_SERVER['HTTP_HOST'] &&
str_starts_with($href, 'http'))
)
{
$attr->parentNode->setAttribute('target', '_blank');
$attr->parentNode->setAttribute('rel', 'noopener noreferrer');
}
});
<!-- profile.html -->
<div>
<p>Hello, {{salutation(user.gender)}} {{user.lastName}}</p>
<a href="{{user.website}}" secure-link>{{user.website}}</a>
</div>
output
<div>
<p>Hello, Mrs. Smith</p>
<a href="https://sam-smith-1990.com" target="_blank" rel="noopener noreferrer">https://sam-smith-1990.com</a>
</div>
I know these examples are rather strange, but due to the reusability one could easily build together a templating mechanism suited to personal needs.
As usual, leaving a star when playing around with the repo is appreciated.
Discussion
Now to the fun part: What has always bothered you when having to deal with passing data to your templating mechanism? What do you wish was less of a hassle?
Top comments (0)