millancore / pesto
PHP View Engine
Requires
- php: ^8.4
- ext-dom: *
- ext-libxml: *
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.86
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.3
- symfony/var-dumper: ^7.3
README
Modern PHP template engine that provides an intuitive and expressive way to build web application views. It offers a clean syntax using custom HTML attributes and supports advanced templating features like view composition, slots, conditional rendering, loops, and built-in security measures.
Pesto understands the context of {{ variables }}
and escapes them according to their scope to avoid
Cross-Site Scripting (XSS) issues.
<ul> <li php-foreach="range(1, 10) as $number" php-if="$number > 7">Item {{ $number }}</li> </ul>
Or, for greater clarity, use <template>
, which will not be included in the final render.
<ul> <template php-foreach="range(1, 10) as $number"> <li php-if="$number > 7">Item {{ $number }}</li> </template> </ul>
Pesto templates support files with the .html
or .php
extension,
allowing you to integrate PHP code if needed.
Installation & Usage
- PHP ^8.4
Pesto is available via Composer and is free of third-party dependencies
composer require millancore/pesto
use MillanCore\Pesto\PestoFactory; $pesto = PestoFactory::create([ templatesPath: __DIR__ . '/views', cachePath: __DIR__ . '/cache', // [ New CustomFilters(), ... ] ]); $pesto->make('view.php', ['user' => $user]);
View Composition
Pesto makes it easy to reuse parts of your views
Template Tag
The <template>
tag allows you to define php-* attributes
that will be evaluated but not the tag included in the final render.
<p php-if="$user->isAdmin()">Admin</p>
--><p>Admin</p>
<template php-if="$user->isAdmin()">Admin</template>
-->Admin
Partials & Slots
When working with views that are composed of other views, you can use partials and slots to avoid repetition.
Layout
<!--- layouts/app.php --> <!DOCTYPE html> <html lang="en"> <head> <title>{{ $title }}</title> </head> <body> <header>{{ $header | slot }}</header> <main>{{ $main | slot }}</main> </body> </html>
View:
<!--- views/home.php --> <template php-partial="layouts/app.php" php-with="['title' => 'Home']"> <!-- Named slot --> <nav php-slot="header"> <a href="/">Home</a> <a href="/about">About</a> </nav> <!--Main Slot --> <section> <h1>Home</h1> <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quae.</p> <section> </template
Nested Views
Pesto allows you to nest views, allowing you to reuse the same layout for multiple times in the same view.
<template php-partial="list.php"> <li>Item</li> <li> <ul php-partial="list.php"> <li>nested item</li> .... </ul> </li> </template>
Control Flow
Pesto provides two control flow directives: foreach
and if
, enough to build any kind of view.
If Attribute
The only rule importance for use php-elseif
and php-else
is the tag must be a sibling of the php-if
tag.
php-if
php-elseif
php-else
php-if
allows you to conditionally render a block of code.
<p php-if="$user->isAdmin()">Admin</p> <p php-elseif="$user->isModerator()">Moderator</p> <p php-else>Guest</p>
Loops
Pesto provides a simple way to loop over arrays or objects.
<li php-foreach="$list as $item">{{ $item }}</li>
Inline
Pesto also allows you to use inline control flow directives.
<ul> <template php-foreach="$users as $user" php-if="$user->isAdmin()"> <li>{{ $user->name | title }} - {{ $user->email }}</li> </template> </ul>
Filters
Pesto provides a simple way to apply filters to variables using the pipe operator, you can define your own filters.
<p>{{ $text | upper }}</p>
List of Filters
raw
Prevents escaping of the variable.
String Filters
upper
lower
capitalize
title
trim
nl2br
strip_tags
slug
join
Chain Filters
You can chain multiple filters together.
<p>{{ $text | capitalize | truncate:50,... }}</p>
Filters with Arguments
To pass arguments to a filter, you can use the :
operator.
<p>{{ $createAt | date:'m-d-Y' }}</p>
Add Filters
Add filter to Pesto is very simple, you can create a class with public methods and add the AsFilter Attribute.
// CustomFilter.php #[AsFilter(name: 'truncate')] public function truncate(string $value, int $length, string $end = '...') : string { //... }
on Pesto factory pass the class to the filters
option.
$pesto = PestoFactory::create([ templatesPath: __DIR__ . '/views', cachePath: __DIR__ . '/cache', [ New CustomFilter(), ] ]);