Template system
The new template system in Goteo uses FOIL which is a powerful php-native template system.
However, there's still a lot of the legacy views in use. They will coexist until we can fully get rid of the old system.
This document compares the old and new template system and highlights the main differences:
Old class system:
\Goteo\Core\View::get('template.html.php', array( 'obj' => ... ));
New Foil base templates:
\Goteo\Application\View::render('template', [ 'obj' => ... ]);
Or, inside a Controller which extends \Goteo\Core\Controller
just do:
$this->viewResponse('template', ['obj' => ...]);
Main differences
Before:
Variables were located inside the array $vars[]
(or event for even older behaviour inside the $this
ArrayObject instance);
File template.html.php
<?php
// Object
$obj = $this['obj'];
$obj->doSomething();
echo htmlspecialchars($this['obj']->doMore()); // Strings needed to be manually escaped
// Scalar
echo htmlspecialchars($this['variable']); // escaped
echo $this['variable']; // non-escaped
?>
After:
Variables are instantiated by default as properties of the object $this
(that's Foil's behaviour).
NOTE: For compatibility reasons an automatic array $this->vars
is created with all variables copied inside. New views (or completely refactored) must not use this array.
File template.php
<?php
// Object
$obj->doSomething();
echo $this->e($this->raw('obj')->doMore()); // Escaped with $this->e() function
// Scalar
echo $this->variable; // HTML escaped by default (strings & arrays)
echo $this->raw('variable'); // Non escaped
// Compatibility with old views needing and array
echo $this->vars['variable']; // HTML escaped if it's a string or a simple array
?>
New features
FOIL supports inheritance, custom functions & a great variables manipulation capabilities between templates.
Basic operation:
It starts with a basic layout used as the base by the other templates. Please refer to the official documentation of Foil to know more about this.
File layout.php
<html>
<head>
<title><?= $this->title ?></title>
</head>
<body>
<?php $this->section('content') ?>
<?php $this->stop() ?>
</body>
</html>
Let's override some vars in a final template extending layout.php
, in this case the title variable and the section content:
profile.php
<?php $this->layout('template', ['title' => 'User Profile']) ?>
<?php $this->section('content') ?>
<h1>User Profile</h1>
<p>Hello, <?=$this->name?></p>
<?php $this->stop() ?>
More info:
https://foilphp.github.io/Foil/docs/TEMPLATES/INHERITANCE.html https://foilphp.github.io/Foil/docs/DATA/PASS-DATA.html
Template inheritance:
The new Goteo views can have themes, currently there are 2, default
& responsive
(which will be the future theme). Located under the folder Resources/templates/
. There's another sub-folder legacy
which contains the old view system (which will disappear someday).
Plugins can override any view by recreating the same structure and placing a new view with the same name:
Resources/templates <- Main template folder
Resources/templates/legacy <- Default deprecated theme (old system)
Resources/templates/default <- Default non-responsive theme (migrated)
Resources/templates/responsive <- New responsive theme (brand new)
extend/{plugin}/Resources/templates <- Main view plugin template overrider
Any view here will be processed before the default one
Example:
Having this default view and the plugin substitute:
Resources/templates/devault/discover/index.php
extend/my-plugin/Resources/templates/devault/discover/index.php
When a controller calls the view, the second one will be used if the plugin is activated. If the plugin is not activated, then the first one will be used:
Controller
<?php
// src/Goteo/Controller/DiscoverController.php
namespace Goteo\Controller;
class DiscoverController extends \Goteo\Core\Controller {
public function index () {
// This will render the discover/index.php file
// from my-plugin if activated
return $this->viewResponse('discover/index',
[ 'test' => 'automatic html escaped text' ]
);
}
}
?>
Default view:
<?php
// Resources/templates/default/discover/index.php
$this->layout("layout", ['bodyClass' => 'discover']);
?>
<?php $this->section('content') ?>
Show me the test var: <?=$this->test?>
<?php $this->replace() ?>
Plugin view:
<?php
// extend/my-plugin/Resources/templates/default/discover/index.php
$this->layout("layout", ['bodyClass' => 'discover']);
?>
<?php $this->section('content') ?>
I am the plugin view,
Show me the test var: <?=$this->test?>
<?php $this->replace() ?>
Plugin views can also extend from a default view instead of the default layout:
<?php
// extend/my-plugin/Resources/templates/default/discover/index.php
$this->layout("default:discover/index");
?>
<?php $this->section('content') ?>
I am the plugin view
<?php $this->replace() ?>
Views can have partials, same principle applies to it.
Better check the Foil's documentation for more information.
Resources/templates/default/partials/ <- Partials views better placed
in a specific folder
Partial include example (Resources/templates/default/layout.php
):
<html>
<head>
<?=$this->insert("partials/header/metas")?>
</head>
<body>
<?php $this->section('content') ?>
<?php $this->stop() ?>
</body>
</html>
The partial Resources/templates/defaul/partials/header/metas.php
will inherit all variables from layout.php
Template extensions:
Views can make use of many built-in functions in order to avoid calling Classes or main functions directly. This classes provides additional functionality to views in Goteo:
src/Goteo/Util/Foil/GoteoCore.php
src/Goteo/Util/Foil/LangUtils.php
src/Goteo/Util/Foil/Pages.php
src/Goteo/Util/Foil/TextUtils.php
Some useful functions
$this->text('id-text')
=> Get the copy of theid-text
in the current language$this->get_session('foo')
=> Gets the session var "foo"$this->get_cookie('foo')
=> Gets the cookie var "foo"$this->is_logged()
=> Return "true" if user is logged in- ...
Custom functions can be called like this:
<a href="#"><?= $this->text('view-project') ?></a>
Guidelines
Ideally, templates must be kept as simple as possible, we will try to follow these guidelines for the new views using Foil (extracted from the Plates templates system):
- Always use HTML with inline PHP. Never use blocks of PHP.
- Always escape potentially dangerous variables prior to outputting using the built-in escape functions. More on escaping here.
- Always use the short echo syntax (
<?=
) when outputting variables. For all other inline PHP code, use full the<?php
tag. Do not use short tags. - Always use the alternative syntax for control structures, which are designed to make templates more legible.
- Never use PHP curly brackets.
- Only ever have one statement in each PHP tag.
- Avoid using semicolons. They are not needed when there is only one statement per PHP tag.
- Never use the
use
operator. Templates should not be interacting with classes in this way. Use custom extensions for that. - Never use the
for
,while
orswitch
control structures. Instead useif
andforeach
. Additionally you can take a look at the built-in loop and array Foil structures - Avoid variable assignment.