PHP template engine for native PHP templates

Overview

FOIL

PHP template engine, for PHP templates.


travis-ci status codecov.io license release


Foil brings all the flexibility and power of modern template engines to native PHP templates. Write simple, clean and concise templates with nothing more than PHP.

Key Features

  • Templates inheritance (you'll never miss Twig or Blade)
  • Clean, concise and DRY templates
  • Dozen of ready-made helper functions and filters
  • Easily extensible and customizable
  • Multiple template folders with file auto-discover or custom picking
  • Auto or manual data escape
  • Powerful context API (preassign data to templates using conditions)
  • Framework agnostic, centralized API for very easy integration
  • Composer ready, fully unit and functional tested, PSR-1/2/4 compliant

...and many more

Why?

Templates engines like Twig, or Blade are a great thing, really.

However, to use them one needs to learn another language with its own syntax and rules.

Moreover, using compiled engines to use even a simple PHP function one needs to write engine extension.

On its side, PHP is already a templating language, but honestly it's not a good one, because it's missing pivotal features of modern template engines, like template inheritance.


Requirements

Foil is framework agnostic, only thing needed is PHP 5.4+ and Composer to add Foil to you PHP project.


License

Foil is open source and released under MIT license. See LICENSE file for more info.

Question? Issues?

Foil is hosted on GitHub. Feel free to open issues there for suggestions, questions and real issues.

Who's Behind Foil

I'm Giuseppe, I deal with PHP since 2005. For questions, rants or chat ping me on Twitter (@gmazzap) or on "The Loop" (Stack Exchange) chat. Well, it's possible I'll ignore rants.

Issues
  • 0.6.4 is now repeating content sections within a loop

    0.6.4 is now repeating content sections within a loop

    0.6.3 was running perfectly for my code. The item in the loop were iterated properly. 0.6.4 is now just dumping the same first item for every iteration. all my code stayed the same. I just updated composer.

    File: project_item.foil

    <?php $this->section('itemsection')?>
    <div class="job clearfix pitem" style="page-break-inside: avoid" id="<?=$this->v('project.htmlid','')?>">
        <div class="<?=$this->col1_css ?>">
                <?= $this->insert($this->v('itemlogosectionview','partials/itemlogo_psup')); ?>
    
               <?php $this->section('projectyearsection')?>
                    <div class="year">
                    <?=$this->v('project.year','')?>
                    </div>
                <?php $this->replace()?>
    
                <?php $this->section('projectfeessection')?>
                    <div class="year">
                    <?=$this->v('project.fees')?>
                    </div>
                <?php $this->replace()?>
            </div>
        </div>
    <?php $this->replace() ?>
    

    The foil above was called from File: body.foil

    <?php foreach($this->majorProjects as $project):?>
        <?=$this->insert('partials/project_item',['project' => $project]) ?>
    <?php endforeach; ?>
    

    I suspect this change could be the reason, src/Section/Section.php [https://github.com/FoilPHP/Foil/compare/0.6.3...0.6.4]

    if (empty($this->mode)) {
                 $this->mode = self::MODE_REPLACE;
             }
    -        $this->content = ob_get_clean();
    +        $buffer = ob_get_clean();
    +        $this->content or $this->content = $buffer;
    +        $this->content = ($this->mode & self::MODE_APPEND) ? $buffer.$this->content : $this->content;
             if ($this->mode & self::MODE_OUTPUT) {
                 echo $this->content();
             }
    

    Please suggest. Thanks.

    bug 
    opened by thevikas 8
  • `supply()` template method does not work when same engine instance is used to render more templates

    `supply()` template method does not work when same engine instance is used to render more templates

    As per the title, here is my use case.

    /views/layouts/master.php

    <!DOCTYPE html>
    <html>
        <head>
            <title><?= $T->v('title', 'Foo Bar') ?></title>
        </head>
        <body>
            <main><?= $T->supply('main') ?></main>
        </body>
    </html>
    

    /views/default.php

    <?php $T->layout('layouts/master') ?>
    
    <?php $T->section('main') ?>
    
        <h1>Something</h1>
    
    <?php $T->stop() ?>
    

    This next bit is overly simplified, I am running a PHP-DI container inside a Wordpress theme with a PSR-7 router. But none of that should matter (I don't think).

    $engine = Foil::boot(['folders' => ['/views'], 'alias'   => 'T'])->engine();
    $html = $engine->render('default');
    

    The Result:

    <!DOCTYPE html>
    <html>
        <head>
            <title>Foo Bar</title>
        </head>
        <body>
            <main></main>
        </body>
    </html>
    

    Expected Result:

    <!DOCTYPE html>
    <html>
        <head>
            <title>Foo Bar</title>
        </head>
        <body>
            <main><h1>Something</h1></main>
        </body>
    </html>
    

    If I modify the master layout to look like this, I get the expected result:

    <!DOCTYPE html>
    <html>
        <head>
            <title><?= $T->v('title', 'Foo Bar') ?></title>
        </head>
        <body>
            <main>
                <?php $T->section('main') ?>
                <?php $T->stop() ?>
            </main>
        </body>
    </html>
    

    The issue appears to be here: https://github.com/FoilPHP/Foil/blob/master/src/Template/Template.php#L172

    $this->sections is empty. I have tried to follow how the sections are defined and added to the stack but between dependency injection, events, magic methods & the fact it's now 20mins past midnight. I got confused rather quickly. I will have another look in the morning with fresh eyes.

    All the same the supply method certainly doesn't appear to work or at least it doesn't work exactly like the Laravel Blade @yield syntax. Maybe I am missing something obvious??? I'll probably discover my error the second I hit the "Submit new issue" button.

    bug 
    opened by brad-jones 8
  • Prepend directories in the finder

    Prepend directories in the finder

    In some situations would be nice to have a method to "prepend" a folder to the current list of search folders. Example, let's say you have this 2 folders where to search for templates:

    $engine->addFolder('/templates/main_folder');
    $engine->addFolder('/templates/sub_folder');
    

    templates will be search firts in the folder 'main' and then, if not found, in "sub". what about if you want to add a folder in the beginning AFTER the initialization? That will be a nice improvements to add flexibility.

    Something like:

    $engine->prependFolder('/templates/plugin_folder');
    

    By the way, outstanding work in this project! thanks a lot!

    feature-request 
    opened by microstudi 8
  • Double render issue

    Double render issue

    Hi, I found a strange bug when the ->render() function is executed twice (or more) in the same script. Let's say you have this directory structure:

    index.php
    templates/base.php
    templates/page.php
    

    With this content in each file: index.php

    <?php
    
    require 'vendor/autoload.php';
    
    $engine = Foil\engine([
      'folders' => ['templates']
    ]);
    
    $page1 = $engine->render('page');
    
    $page2 = $engine->render('page');
    
    echo $page2;
    

    templates/base.php

    <?php $this->section('content') ?>
    BASE CONTENT
    <?php $this->stop() ?>
    

    templates/page.php

    <?php
    $this->layout('base');
    

    if you execute the index.php script, for instance, by command line: php index.php, this is the output obtained:

    BASE CONTENT
    
    BASE CONTENT`
    

    I.e. the 'content' section appears twice! When it should be only one line, isn't it? This is accumulative, if you have 3 ->render() calls, you can expect 3 repetitions of the section.

    Do you have a clue of why is this happening? Thanks

    bug 
    opened by microstudi 6
  • Trimming output?

    Trimming output?

    Hi!

    Thanks for creating Foil. It solves a big issue I had with Plates: lack of multi-folder support and so creating skinnable templates with Plates was not possible.

    One thing with Foil that keeps biting me is this line which is:

        private function doRender($path, array $data = [], $class = null)
        {
            // ...
            $output = trim($template->render($data));
            // ...
            return $output;
        }
    

    Why trim()? Can this not be left up to the developer as desired? E.g. me! Or made an option? One of things we use foil for (as well as HTML templates) is building plain text configuration files and whitespace is important here.

    Thanks, Barry.

    enhancement 
    opened by barryo 5
  • $engine->renderSection()?

    $engine->renderSection()?

    Hi, Foil seems great, i'm evaluating it for a project instead of Plates, but i can't find a way to render specific sections programmatically, also Plates does not support this, but Twig does.

    It's useful for email templates where you can have a template with 3 different sections:

    • subject
    • body_html
    • body_text

    is possible to add a function like:

    $subject = $engine->renderSection('email-template','subject-section', $some_data);
    $body_html = $engine->renderSection('email-template','body-html-section', $some_data);
    $body_text = $engine->renderSection('email-template','body-text-section', $some_data);
    

    and/or have something like:

    $tpl = $engine->getTemplate('email-template');
    $tpl->setData($some_data);
    $subject = $tpl->renderSection('subject-section');
    $body_html = $tpl->renderSection('body-html-section');
    $text_html = $tpl->renderSection('body-text-section');
    

    email-template.php:

    <?php
    $this->section('subject-section') ?>
    TEST SUBJECT
    <?php $this->stop() ?>
    <?php $this->section('body-html-section') ?>
    TEST HTML BODY
    <?php $this->stop() ?>
    <?php $this->section('body-text-section') ?>
    TEST TEXT BODY
    <?php $this->stop() ?>
    

    eventually if the requested section does not exists renderSection() will simply return null

    what do you think?

    thanks in advice!

    feature-request 
    opened by ducktype 5
  • PHP Warning:  htmlspecialchars()

    PHP Warning: htmlspecialchars()

    I see a lot of warnings after upgrading to Foil 0.4.1 :

    [Fri Apr 24 20:59:07.155292 2015] [:error] [pid 5704] [client 127.0.0.1:49545] PHP Warning: htmlspecialchars() expects parameter 1 to be string, array given in /home/bronx/www/clubman/vendor/aura/html/src/Escaper/HtmlEscaper.php on line 77

    bug 
    opened by fbraem 5
  • Can't render double extension templates without postfix

    Can't render double extension templates without postfix

            $engine = Foil\engine([
                'ext'     => ['tpl.php'],
                'folders' => ['path/to/templates']
            ]);
            // trying to render path/to/templates/home.tpl.php
            $engine->render('home'); 
    

    this produces

    Uncaught exception 'RuntimeException': home is not a valid template name

    Do I miss something or this is currently not possible with Foil ?

    bug 
    opened by skyosev 5
  • Question about template variables

    Question about template variables

    Hi again!

    I'm curious about the need to use $this->my_var while accessing data in templates. Is there any particular reason (performance, escaping etc.) for not using locally scoped variables like $my_var ? Plates does allow it AFAIK.

    I didn't dig into Foil that much, so my question could sound improper.

    Regards, Stoyan

    question 
    opened by skyosev 5
  • spaceless blocks?

    spaceless blocks?

    Is feasible to add a feature like {%spaceless%} blocks as in Twig?

    http://twig.sensiolabs.org/doc/tags/spaceless.html

    feature-request 
    opened by ducktype 4
  • Post calls not working on PHP 7.1

    Post calls not working on PHP 7.1

    I Get 404 not found error when calling post functions as below

    PHP Deprecated: Non-static method ------ should not be called statically

    Did this packages work on PHP 7.1

    Did any updates to overcome the issue?

    opened by midhunraj 3
  • Multiple section replace don't work

    Multiple section replace don't work

    Hi Giuseppe, I've created a simple demo for, apparently, a bug I have found.

    I have a base template called: baseTemplate

    <!DOCTYPE HTML>
    <html>
    	<head>
    	</head>
        <body>
    	<? $this->section('body') ?>aaa<? $this->stop() ?>
        </body>
    </html>
    

    I have a second template called: templateA

    <? $this->layout('_layout/baseTemplate') ?>
    <? $this->section('body') ?>bbb<? $this->replace() ?>
    

    I have a third template called: templateB

    <? $this->layout('_layout/templateA') ?>
    <? $this->section('body') ?>ccc<? $this->replace() ?>
    

    While the result is supposed to be: ccc, in fact, it shows bbb

    If I change the the section ending in templateA from replace() to stop(), I get ccc.

    I would we very thankful if you could take a look at it, and fix it. :) Yoshi.

    opened by yoshkinawa 2
  • Documentation website not working

    Documentation website not working

    https://foilphp.github.io/Foil/ cannot navigate through menu, here the errors in chrome console

    Mixed Content: The page at 'https://foilphp.github.io/Foil/' was loaded over HTTPS, but requested an insecure script 'http://yandex.st/highlightjs/7.5/highlight.min.js'. This request has been blocked; the content must be served over HTTPS. theme.min.js:5 Uncaught ReferenceError: hljs is not defined at theme.min.js:5

    opened by r3verser 3
  • Development roadmap

    Development roadmap

    Hey @gmazzap. I mentioned you in another WP framework project and in connection was wondering what the status of this templating project is. Feature complete? 0.7 coming some time or too busy? Did someone else produce something even better?

    question 
    opened by lkraav 1
  • Link to blog post has no content

    Link to blog post has no content

    I got an DNS error from gm.zoomlab.it

    I suggest use this url that works: http://web.archive.org/web/20170227180224/http://gm.zoomlab.it/2015/template-engines-i-moved-from-love-to-meh-for-plates/

    opened by SlavaAurim 2
  • Duplicate code with nested sections

    Duplicate code with nested sections

    I have the following setup: The layout defines sections:

    <!DOCTYPE html>
    <html>
    <head>
        <title><?= $this->e('title') ?></title>
        <?php $this->section('head'); $this->stop(); ?>
    </head>
    <body>
    
    <?php $this->section('content');$this->stop(); ?>
    
    <?php $this->section('end-body');$this->stop(); ?>
    </body>
    </html>
    

    Then there is the template appending some content to the content section of the layout. Some of the content is loaded by including a partial:

    <?php $this->layout('layout::page', ['title' => 'Page title']) ?>
    
    <?php $this->section('content') ?>
    <h1>Test</h1>
    
    <?= $this->insert('partials::date-input'); ?>
    <?php $this->append() ?>
    

    The partial references a JS file (which should be appended to the "end-body" section of the layout) and some HTML which should be inserted whereever $this->insert('partial-name') is called.

    <?php $this->section('end-body') ?>
    <script src="/jquery.min.js"></script>
    <script src="/intercooler.js"></script>
    <?php $this->append() ?>
    
    <div ic-get-from="<url>" ic-trigger-on="scrolled-into-view"></div>
    

    The result is:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Page title</title>
        </head>
    <body>
    
    <h1>Test</h1>
    
    <script src="/jquery.min.js"></script>
    <script src="/intercooler.js"></script>
    
    <div ic-get-from="<url>" ic-trigger-on="scrolled-into-view"></div>
    
    <script src="/jquery.min.js"></script>
    <script src="/intercooler.js"></script>
    </body>
    </html>
    

    So the JS files get embedded twice. I am quite sure that I did something wrong but perhaps this really is a bug.

    bug 
    opened by janwalther 3
  • Markdown Block

    Markdown Block

    About to start work on a custom block that parses Markdown. A little surprised no one has not done this yet???

    question 
    opened by brad-jones 2
  • Arraization(?) is turning my Eloquent collections into strings (not arrays)

    Arraization(?) is turning my Eloquent collections into strings (not arrays)

    I'm passing in Eloquent Collections like so:

    $engine->render('index/index', [
        'questions' => $questions,
    );
    

    If I var_export in the my controller class, the variable is set as an instance of Collection, but if I var_export within the template it's not an object, it's not an array even, but is a json_encoded string! I guess I could json_decode but is this the desired behaviour?

    Also, how do I turn off Arraization for all templates? I might not wish to have this feature for now. Thanks

    opened by martynbiz 1
  • Option to not arraize some data

    Option to not arraize some data

    Would you consider adding the option to keep some objects as they are? Because when having a complex nested array of data where everything except some certain type of data needs to be arraized this would be really handy.

    My first idea would be to just use the existing transformer parameter. If the value is false just skip the arraization and keep the object:

    $arraized = $Foil\arraize($products, true, ['My\App\Product'=> false]);
    

    I wouldn't be surprised though if you said wontfix as this breaks the basic assumption that

    whatever data you pass to the function at the end of the process, you get an array that contains no objects

    Just asking... :wink:

    opened by kraftner 1
  • Retrieve Data Inside Templates: loops

    Retrieve Data Inside Templates: loops

    Can you use helpers for echoing variables while iterating through an array? All I have been able to do is something like this:

    <?php foreach ($this->news_stories as $story): ?>
      <li><?= $story['title'] ?></li>
    <?php endforeach ?>
    

    Are there any other options for doing this?I'm not sure whether this is providing an escaping or other benefits of helpers.

    enhancement feature-request 
    opened by plweil 14
Releases(0.6.7)
  • 0.6.7(May 4, 2017)

  • 0.6.6(May 26, 2016)

  • 0.6.5(Mar 8, 2016)

    Added

    Nothing

    Changed

    Nothing

    Fixed

    • Issue with nested blocks having callbacks that receives arguments - See #32
    • Issue when same section in replace mode is present more than once in same template - See #34
    Source code(tar.gz)
    Source code(zip)
  • 0.6.4(Feb 22, 2016)

    Added

    Nothing

    Changed

    • Template object has dependency to section factory and not to sections. No API change.

    Fixed

    • supply() issue when same engine instance is used more than once (see #31)
    • SectionInterface::MODE_REPLACE causes template inheritance to fail (see #30)
    Source code(tar.gz)
    Source code(zip)
  • 0.6.3(Nov 1, 2015)

  • 0.6.2(Jul 6, 2015)

  • 0.6.1(Jul 4, 2015)

  • 0.6.0(Jul 3, 2015)

    New Features, Issues Solved

    • Introduced Blocks and Custom Blocks feature
    • Introduced "alias" feature that shorten syntax to access variables and functions inside templates
    • Introduced Section Rendering feature
    • Better control on registered folders, see docs.
    • Engine::render(), Engine::find() and Finder::find() now also accepts an array of template names to be searched in registered folders. The first found is returned.
    • Introduced Foil\Foil class
    • Fixed issue on arraization of objects
    • Clean up & code style improvements

    Backward Compatibility Breaks

    • Foil\API class has been removed
    • Foil\Contracts\APIAwareInterface has been removed
    • Foil\Traits\APIAwareTrait has been removed
    • Foil\Bootstrapper class has been removed
    • Most of the API functions have been removed. See docs.
    • Foil\engine() functions now always returns a "fresh" instance of Foil\Engine class, whereas in older versions always returned same instance when called more times.
    Source code(tar.gz)
    Source code(zip)
  • 0.5.1(May 25, 2015)

  • 0.5.0(May 25, 2015)

    Easing the process of using custom template classes.

    • private methods in Template class have been changed to protected
    • introduced 'template_class' engine option
    • add a third argument, $class, for the Engine::renderTemplate() method
    Source code(tar.gz)
    Source code(zip)
  • 0.4.3(May 22, 2015)

  • 0.4.2(Apr 24, 2015)

  • 0.4.0(Apr 22, 2015)

    • Introducing support for Aura.HTML for escape (and autoescape)
    • Added Aura.HTML extension for HTML and Form helpers
    • Added docs for new features
    • Added new Escaper class (and interface) that makes use of Aura.HTML escaper
    • New options 'default_charset' and 'html_tags_functions'
    • Improved phpDoc
    • Minor bug & CS fix
    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(Mar 18, 2015)

    • supply() template method now supports a callback as default value
    • added support for 'strict_variables' engine option to throw an exception or a notice when using undefined vars
    • updated documentation
    • various typo and CS fixes
    Source code(tar.gz)
    Source code(zip)
  • 0.2.0(Feb 18, 2015)

    • Added insertIf() template tag to insert partial conditionally
    • layout() now accepts also full path of layout
    • some minor internal improvements
    • updated docs (and site) for new feaures
    Source code(tar.gz)
    Source code(zip)
  • 0.1.4(Jan 25, 2015)

  • 0.1.3(Jan 21, 2015)

  • 0.1.2(Jan 21, 2015)

Owner
Foil PHP
A PHP Template Engine, for PHP templates.
Foil PHP
Native PHP template system

Plates Plates is a native PHP template system that's fast, easy to use and easy to extend. It's inspired by the excellent Twig template engine and str

The League of Extraordinary Packages 1.3k Nov 19, 2021
Document templates Laravel package is intended for creating/managing user editable document template

Document Templates Introduction Document templates Laravel package is intended for creating/managing user editable document templates, with ability to

42coders 99 Nov 14, 2021
Smarty is a template engine for PHP, facilitating the separation of presentation (HTML/CSS) from application logic.

Smarty 3 template engine smarty.net Documentation For documentation see www.smarty.net/docs/en/ Requirements Smarty can be run with PHP 5.2 to PHP 7.4

Smarty PHP Template Engine 1.9k Nov 23, 2021
☕ Latte: the intuitive and fast template engine for those who want the most secure PHP sites.

Latte: amazing template engine for PHP Introduction Latte is a template engine for PHP which eases your work and ensures the output is protected again

Nette Foundation 731 Nov 27, 2021
View template engine of PHP extracted from Laravel

Blade 【简体中文】 This is a view templating engine which is extracted from Laravel. It's independent without relying on Laravel's Container or any others.

刘小乐 145 Aug 13, 2021
⚡️ Simple and fastly template engine for PHP

EasyTpl ⚡️ Simple and fastly template engine for PHP Features It's simple, lightweight and fastly. No learning costs, syntax like PHP template It is s

PHPPkg 9 Nov 26, 2021
Qiq templates for PHP 8.

Qiq Templates for PHP 8 This package provides a PHP 8.0 implementation of the TemplateView and TwoStepView patterns using PHP itself as the templating

null 10 Nov 9, 2021
Contao extension to provide content templates for pages.

Contao Content Templates In Contao, the regular content of a page can be made up of different articles, each assigned to different sections of a page

inspiredminds 3 Aug 29, 2021
Renders Mithril components to HTML for use in blade templates

Flarum Mithril2Html Uses Chrome Puppeteer via Spatie Browsershot to render Mithril components as static HTML. Follow Browsershot instructions to setup

Clark Winkelmann 3 Aug 27, 2021
Laravel Live Templates for PhpStorm

Laravel Live Templates for PhpStorm How to: Go to Preferences | Tools | Settings Repository Add Read-only Source https://github.com/koomai/phpstorm-la

Sid 1.2k Nov 18, 2021
Standalone Skeltch templating engine for PHP

SkeltchGo is a standalone version of Glowie Skeltch templating engine for PHP, intented to use from outside the framework.

glowie 1 Nov 5, 2021
SwitchBlade: Custom Directives for the Laravel Blade templating engine

SwitchBlade: Custom Directives for the Laravel Blade templating engine

Awkward Ideas 9 Sep 2, 2021
Twig, the flexible, fast, and secure template language for PHP

Twig, the flexible, fast, and secure template language for PHP Twig is a template language for PHP, released under the new BSD license (code and docum

Twig 7.3k Nov 24, 2021
A complete and fully-functional implementation of the Jade template language for PHP

Tale Jade for PHP Finally a fully-functional, complete and clean port of the Jade language to PHP — Abraham Lincoln The Tale Jade Template Engine brin

Talesoft 93 May 4, 2021
A ready-to-use Model View Controller template in PHP

PHP-MVC-Template A ready-to-use Model View Controller template in PHP Use this repo as a template! (Or clone it) Start to configure your MVC file Afte

Loule | Louis 6 Nov 19, 2021
Provides a GitHub repository template for a PHP package, using GitHub actions.

php-package-template Installation ?? This is a great place for showing how to install the package, see below: Run $ composer require ergebnis/php-pack

null 260 Nov 24, 2021
The free-to-use template for your Imagehost-website made with PHP, HTML and CSS!

The free-to-use template for your Imagehost-website made with PHP, HTML and CSS! Some information before we start This repo is only code related, to a

Ilian 5 Nov 3, 2021
The free-to-use template for your Imagehost-website made with PHP, HTML and CSS!

The free-to-use template for your Imagehost-website made with PHP, HTML and CSS! Some information before we start This repo is only code related, to a

Ilian 5 Nov 3, 2021
A lightweight template parser used by PyroCMS.

Lex Lex is a lightweight template parser. Lex is released under the MIT License and is Copyrighted 2011 - 2014 PyroCMS Team. Change Log 2.3.2 Convert

PyroCMS 103 Nov 15, 2021