-
Notifications
You must be signed in to change notification settings - Fork 0
Blade Templates
Blade templating is a direct adaptation of Laravel's Blade templating. Blade is a simple and powerful templating engine driven by view template inheritance and sections. All Blade templates use the .blade.php
extension. Modern IDEs, such as phpStorm, will recognise them and provide syntax highlighting support. You need to do some overrides in phpStorm; see the last section of this page.
All Blade view templates are parsed at runtime and converted into regular PHP files which are then loaded by your Views like any other regular PHP view template. This means that if Blade doesn't provide a control structure you need you can simply switch to pure PHP in your Blade template. Remember that $this
always has the reference to your View object which is a View
or DataViewInterface
descendant.
A Blade template looks like this:
<!-- Stored in administrator/components/com_foobar/View/something/tmpl/item.blade.php -->
@section('header')
<p>This is the master header</p>
@show
<div class="foobar-item">
@yield('item')
</div>
Naming and location of the files follows the same conventions as any other FOF view template.
<!-- Stored in administrator/components/com_foobar/View/something/tmpl/item_default.blade.php -->
@extends('admin:com_foobar/something/item')
@section('header')
<p>This is the appended to the master header.</p>
@stop
@section('item')
<p>This is the content that goes inside the foobar-item div.</p>
@stop
Blade view templates override sections from the template(s) they are extending. The content of any view template can be included in another view template using the @yield
directive in a section. This allows you to separate your layout into many distinct areas and have each view template override only some of them.
You can to pass default content to the @yield
directive. For example
@yield('item', 'This is my default content')
will display "This is my default content" if the "item" section has not been defined.
Blade has a lot of directives which allow you to define control structures in a way that's understandable by both back-end and front-end developers.
If you want to escape the data you are echoing use triple curly braces. If you want to display the data unescaped use double curly braces.
<h1>{{{ $this->item->title }}}</h1>
<div>
Posted by {{{ $this->item->user->username }}} on {{{ $this->item->created_on }}}
</div>
<div>
{{ $this->item->body }}
</div>
Use of double curly braces (unescaped echo) is a bad idea. You should only use it when displaying HTML data and only after making sure you have sanitised it properly. If unsure, use triple curly braces.
If you need to display a string which begins and ends with curly braces prefix your text with an @
sign. For example:
@{{ This line is not parsed by Blade }}
Blade has a shorthand for displaying a default text when the variable you want to display doesn't exist. For example:
<p>{{{ $this->item->name or 'Anonymous Coward' }}}
You have the complete if-elseif-else-endif structure just like PHP. You also have the shorthand unless-endunless construct which renders if a condition is false.
@if ($this->permissions['editown'] && $this->item->created_by == \JFactory::getUser()->id)
You can edit this item; you own it.
@elseif ($this->permissions['edit'])
You can edit this item; you have edit rights
@else
You can't edit this item
@endif
@unless ($this->permissions['foobar'])
Go away, you don't have the permission to be here!
@endunless
Just like PHP.
@for ($i = 0; $i < 10; $i++)
The value of i is {{ $i }}
@endfor
You can iterate a list just like PHP with the foreach-endforeach construct.
@foreach ($this->items as $item)
This is item {{ $item->foobar_item_id }}
@endforeach
If you want to display a different message if the list is empty use the forelse-empty-endforeach construct.
@forelse ($this->items as $item)
This is item {{ $item->foobar_item_id }}
@empty
<p>No items found</p>
@endforelse
Loop while a condition is true.
@while(true)
<p>Infinite loop</p>
@endwhile
@include('admin:com_foobar/something/item_user')
You can also pass additional data to the subtemplate as an array:
@include('admin:com_foobar/something/item_user', array('foo' => 'bar'))
In this case the subtemplate will have the variable $foo
defined with a value of "bar".
Since FOF 3.1.1 you can do
@jlayout('path.to.your.jlayout', ['option1' => $something, 'option2' => 'something else'])
This equivalent to echo FOF30\Layout\LayoutHelper::render($this->container, 'path.to.your.jlayout', ['option1' => $something, 'option2' => 'something else'])
There is no Blade shortcut. You will have to do an escape to PHP:
<?php Container::getInstance('com_other', array(
'tempInstance' => true,
'input' => array(
'view' => 'something',
'task' => 'whatever',
'other_something_id' => $this->item->other_something_id
)))->dispatcher->dispatch(); ?>
When you have complicated data structures you may want to use a subtemplate (a different view template file) to render each item in your list. You can use the each construct:
@each('admin:com_foobar/something/item_user', $this->item->users, 'user', 'raw|No users found')
The four parameters are:
- The view template URI
- The list to iterate through
- The name of the variable holding each item, passed to the subtemplate.
- What to display when the list is empty. It can be a template URI, a raw string prefixed with
raw|
or (from FOF 3.1.1 and later) a language string prefixed withtext|
.
In the subtemplate use the PHP variables $key
and $something
(where "something" is the third parameter above) to access the key and value of each iterated item.
Do note that this is not the only way. This construct is roughly equivalent to:
@forelse($this->item->users as $key => $value)
@include('admin:com_foobar/something/item_user', array('key' => $key, 'user' => $value)
@empty
No users found
@endforelse
Using @each is simply a bit more elegant.
To overwrite (replace the contents) of a section use the @override
directive to end your section instead of @stop
:
@extends('admin:com_foobar/something/item')
@section('header')
This replaces the header section
@overwrite
IMPORTANT: Repeatable sections only work on PHP 5.4.0 and later.
@repeatable('kot', $lamb)
<p>
@if ($lamb == 1)
Mary had a little lamb.
@else
Mary had {{{ $lamb }}} little lambs.
@endif
</p>
@endRepeatable
@for ($lamb = 1; $lamb < 11; $lamb++)
@yieldRepeatable('kot', $lamb)
@endfor
@repeatable
takes one or more arguments. The first is the name of the repeatable section, the rest of the arguments are the variable names which will be made known to it.
@endRepeatable
closes the repeatable section. You must match the @repeatable
and @endRepeatable
tags.
@yieldRepeatable
parses the repeatable section and yields its contents. The first argument is the repeatable section's name, the rest are the arguments passed to the repeatable section.
Repeatable sections are implemented as anonymous functions. The variable names are passed to the argument list of the anonymous function definition.
@lang('COM_FOOBAR_SOME_LANGUAGE_STRING')
@sprintf('COM_FOOBAR_YOU_HAVE_X_ITEMS', count($this->items))
@plural('COM_FOOBAR_N_ITEMS_SAVED', count($this->items))
Note: @plural is available since FOF 3.1.1 and maps to JText::plural().
Instead of calling JRoute directory you can use the @route
shorthand
<a href="@route('index.php?option=com_foobar&view=items')">Items</a>
@css('media:com_example/css/my.css')
@inlineCss('.foo {display: block}')
@js('media:com_example/js/my.js')
@inlineJs("alert('FOF Rocks!')")
@less('media:com_example/less/my.less', 'media:com_example/css/my.css')
These map to the View's addJavascriptFile
, addJavascriptInline
, addCssFile
, addCssInline
and addLess
methods.
See the View class for more information about the methods' parameters.
@jhtml('calendar', $date, 'myFieldName', 'myFieldId')
This is equivalent to echo JHtml::_('calendar', $date, 'myFieldName', 'myFieldId');
<img src="@media('media:com_example/images/my.png')" />
Media paths go through Template::parsePath
and support media file overrides in the current template.
// Show active modules assigned to the 'myModulePosition' position
@modules('myModulePosition');
// Show named module
@module('mod_example');
{{-- This is like a PHP comment; it will not be present in the HTML output --}}
Just like Laravel's Blade, you can extend FOF's Blade compiler to define your own custom directives. When the Blade compiler is parsing a template it will call all extensions against its output. This lets you do anything from a simple search and replace to complex output manipulation.
There are two methods you can use to register your Blade extensions, createMatcher
and createPlainMatcher
. These generate the expressions to handle your custom directives.
The createPlainMatcher
directive is used to define directives with no arguments, whereas createMatcher
lets you define directives which take arguments.
Example:
$container->blade->extend(function($template, $compiler) {
$pattern = $compiler->createMatcher('datetime'); // Defines an @datetime directive with one argument
return preg_replace($pattern, '$1<?php echo $2->format(\'d/m/Y H:i:s\'); ?>', $template);
});
Just like the classic PHP view templates, you can use loadAnyTemplate
to load subtemplates.
Example
<?php $this->loadAnyTemplate('auto:com_example/Item/default_price'); ?>
You must NOT specify the extension of the view template to load. FOF will automatically look for both classic PHP and Blade templates.
Since FOF 3.0.10 you can insert the CSRF protection form token using a Blade shortcut:
<input type="hidden" name="@token()" value="1"/>
In previous versions of FOF you can do the same with
<input type="hidden" name="{{JFactory::getSession()->getFormToken()}}" value="1"/>
Since FOF 3.0.10 you can render Joomla!'s WYSIWYG editor with
@editor($fieldName, $htmlData, $width, $height, $columns, $rows, $buttons, $ids, $asset, $author, $params)
Internally this does
JEditor::getInstance($this->container->platform->getConfig()->get('editor', 'tinymce'))
->display($fieldName, $htmlData, $width, $height, $columns, $rows, $buttons, $ids, $asset, $author, $params);
Do note that since Joomla! 3.2 you are not supposed to call JFactory::getEditor()
any more as it is deprecated!
phpStorm comes with a default mapping for Blade templates suitable for Laravel. When working with a FOF project you will need to tell phpStorm how our Blade templates work to let it provide correct type hints. Go to Preferences, Languages & Frameworks, PHP, Blade and click on the Directives tab. You need to set up the following directives:
Name | Has Parameter | Prefix | Suffix |
---|---|---|---|
append | No | ||
css | Yes | <?php echo $this->addCssFile( | ); ?> |
each | Yes | <?php echo $this->renderEach( | ); ?> |
else | No | ||
elseif | Yes | <?php elseif( | ); ?> |
empty | Yes | <?php if(empty( | )): ?> |
endfor | No | ||
endforeach | No | ||
endforelse | No | ||
endif | No | ||
endpush | No | ||
endrepeatable | No | ||
endunless | No | ||
endwhile | No | ||
extends | Yes | <?php echo $this->loadAnytemplate( | ); ?> |
fieldtitle | Yes | <?php echo FOF30\Utils\FEFHelper\BrowseView::fieldLabel( | ); ?> |
for | Yes | <?php for( | ); ?>> |
foreach | Yes | <?php foreach( | ); ?> |
forelse | Yes | <?php foreach( | ); ?> |
if | Yes | <?php foreach( | ); ?> |
include | Yes | <?php echo $this->loadAnytemplate( | ); ?> |
inlineCss | Yes | <?php $this->addCssInline( | ); ?> |
inlineJs | Yes | <?php $this->addJavascriptInline( | ); ?> |
jhtml | Yes | <?php echo \JHtml::_( | ); ?> |
jlayout | Yes | <?php echo \FOF30\Layout\LayoutHelper::render($this->container, | ); ?> |
js | Yes | <?php echo $this->addJavascriptFile( | ); ?> |
lang | Yes | <?php echo \JText::_( | ); ?> |
less | Yes | <?php echo $this->addLessFile( | ); ?> |
media | Yes | <?php echo $this->container->template->parsePath( | ); ?> |
modelfilter | Yes | <?php echo \FOF30\Utils\FEFHelper\BrowseView::modelFilter( | ); ?> |
module | Yes | <?php echo $this->container->template->loadModule( | ); ?> |
modules | Yes | <?php echo $this->container->template->loadPosition( | ); ?> |
overwrite | No | ||
plural | Yes | <?php echo \JText::plural( | ); ?> |
push | Yes | <?php $this->startSection( | ); ?> |
repeatable | Yes | <?php // | ?> |
route | Yes | <?php echo $this->container->template->route( | ); ?> |
searchfilter | Yes | <?php echo \FOF30\Utils\FEFHelper\BrowseView::searchFilter( | ); ?> |
section | Yes | <?php $this->startSection( | ); ?> |
selectfilter | Yes | <?php echo \FOF30\Utils\FEFHelper\BrowseView::selectFilter( | ); ?> |
show | No | ||
sortgrid | Yes | <?php echo \FOF30\Utils\FEFHelper\BrowseView::sortGrid( | ); ?> |
sprintf | Yes | <?php echo \JText::sprintf( | ); ?> |
stack | Yes | <?php echo $this->yieldContent( | ); ?> |
stop | No | ||
token | Yes | <?php \JFactory::getSession()->getFormToken(( | ); ?> |
unless | Yes | <?php if ( ! ( | )): ?> |
while | Yes | <?php while ( | ): ?> |
yield | Yes | <?php $this->yieldContent( | ); ?> |
yieldRepeatable | Yes | <?php _fof_blade_repeatable_DUMMY( | ); ?> |
Please note that you should not keep any of the other default directives. They do not apply to FOF.
FOF (Framework on Framework) and its documentation are Copyright © 2010-2020 Nicholas K. Dionysopoulos / Akeeba Ltd.
FOF is Open Source Software, distributed under the GNU General Public License, version 2 of the license, or (at your option) any later version.
The FOF Wiki content is provided under the GNU Free Documentation License, version 1.3 of the license, or (at your option) any later version.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license can be found on the GNU site.