FoilPHP/Foil

$engine->renderSection()?

Closed this issue · 5 comments

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!

Hi @ducktype thanks again for your interest.

This is a very nice idea, I've never thought to implement this, but surely is something that would make Foil better.

I'll surely consider this for next minor release (0.6). I'm trying to have one minor release per month, and the next should be at the end of June, but I'll be very busy in those days, so it's possible it will happen a bit later.

I'll update this issue to keep you updated. Thanks again.

PS: I've added syntax hightlight to your comment, to improve readability, I hope you don't mind...

Thank you for considering this feature!

By the way for now i've tried to create my own minimal template engine that supports named blocks overrides, template inheritance, spaceless blocks and also getting a single block output by name from a template file with multiple blocks.

I've been quite excited about how simple and concise the result was!

I want to share that with you to see, eventually if you have a bit of time, what advices you can give or if i'm missing something orrible in the design of it:

it's only ~90 lines of code:
https://gist.github.com/ducktype/f05b4feb4501cbbf7a36

PS: surely i don't mind, i'm a bit lazy sometimes :)

Some consideration on your code:

  • Do you really need to support PHP 5.3? As of today the only stable release of PHP 5.6. In a code that uses so much closures, being forced to $self = $this is not something that make much sense IMO
  • I like very much the idea of using closures to do things in template. My only concern is that using different global variables there might be cases of conflicts. E.g. a model that contains a variable named 'block' or 'prev_level', once extracted it would destroy your templates. That is probably not a big concern on a simple engine that is used in your own project, where you have control on all variables, but becomes a problem in a more generic tool that can be used in different projects, like Foil want to be.
  • Simplicity of code is not measured in lines of code. Try to keep your code as more readable as possible. Use all the spaces and blank lines you need. Use doc blocks. Embrace a code style (PSR-2?).
    I'm sure that if you open that Gist in two monts you'll not be able to read it like you do now.
  • A class that does all the things (find templates, renders them, setup filters...) is simple at first approach, but becomes pretty hard to maintain if you want to extend it adding more features.
  • Use type hints when you can. It makes your code much stronger. What append if I pass a string as 2nd argument to PTpl constructor? You expect an array, but there is no check nor constraint.
  • What happen if I pass a non existent path as 1st argument to PTpl constructor? Check the variables you use. And while here, if a variables is a base path, call the variable $base_path, not $bp.
  • Try to always use strict identity checks, i.e. === instead of ==

I applyed all this suggestions and your code looks like this https://gist.github.com/Giuseppe-Mazzapica/c7f8c719d9d0deb703b9 (I surely broken something in the process, I did not test it)

What do you think? Is it more readable? Assume you don't look at your code for two monts, which version will make you more comfortable? And assume to send the code to another developer, which version they would find more readable?

Finally, last suggestion I want to give is that when you find yourself in the need of using a lot of & probably you should start to think about using objects, instead of array. Things like Iterators, Splstack, SplQueue... sometimes are a good replacement for array (not always), because being objects they are passed by reference, so no need to use &.

Besides this criticism I think you did a nice work, surely something that would work pretty well in a specific project.

Thank you for taking the time to analyze the code.

Was only a proof of concept, not very polished :) but all your points make sense i'll try to follow your suggestions.

About closures name conflicts was surely something i'm concerned about but at the end of the day i prefer that approach anyway. Also given i'm used to pass a root model to templates like anything is under $model.

@ducktype This feature has been introduced in version 0.6. See docs http://www.foilphp.it/docs/TEMPLATES/SECTIONS-RENDERING.html.

Pleae note that 0.6 introduced some backward compatibility breaks. Please review release notes before update.