Fluid - Next Generation Templating

May 07, 2010

Fluid is the next generation templating engine, that will be used in TYPO3 v5 (Phoenix). It was backported to TYPO3 v4 so everyone can enjoy the advantages of a full templating engine. But what are those advantages?   First of all, it is easily possible with fluid to separate view logic from other parts of the application. With traditional templating you often see functions fetching data, then looping over it, putting everything in a classic subpart whilst doing the complete logic in the same step. Of course this is bad coding style and a good coder would separate it more, but you'll always have some functions that are doing "view stuff". Let's have a look at a small example:

Conclusion

Fluid is a new approach to TYPO3 extension templating. Fluid makes keeping view logic in the view as easy as breathing. Additionally it has some very neat features that help everyone involved to get fast results with a minimum of fuss. It doesn't matter whether you are a frontend developer or a backend programmer, fluid is for you. The only requirement is having approximately two days of time and be willing to learn. But well, if you don't wanna learn new things you probably have the wrong job anyway ;-)

Layouts and partials

If you have ever built a big extension with lots of different widgets in the frontend (think shop or blog) you'll have faced this problem already.  

We want to have a shop with the following layouts: 

Layout 1:

Layout 2: 

Now in fluid we can add two layouts: 

<FLUID>

<div class="layout1"> 

Some Header Content here</header>

<f:render section="main" /></div>

<f:render partial="sidebar" /></div>

</div> 

</FLUID> 

Layout2: 

<FLUID> 

<div class="layout2"> 

Some Header Content here</header>

<f:render section="main" /></div>

<f:render partial="sidebar" /></div>

</div>

</FLUID> 

You can see that layouts are easy to create. To use them in our templates we just add "<f:layout name="default" />" to the template. If you want to make it dependent on some setting, you can just enclose it with an if.

Partials are another neat thing. They allow you to group stuff together so you can use it easily in multiple places and ways. As you can see above the sidebar is a partial. In a real shop you'd probably use it in different templates, for example in the main shopping template, the products single view, the cart view ... it's easily shared between templates. 

For more information and examples have a look at the blog example.

View helpers

View helpers are meant to make templating life easier. They can be used for all kinds of standard situations related to the view. This includes e.g. link creation, forms, cycling through elements or string translations. By default fluid contains the viewhelpers listed on http://flow.typo3.org/documentation/guide/partv/fluidviewhelperreference.html. But the real power of viewhelpers is that you can define your own.

A classical example for your own view helper would be a page browser. A page browser is strictly related to the view of an extension and has nothing to do with the business logic. However, in many cases the code producing the pagebrowser can be found at the same place as the business logic. With an own page browser view helper and fluid you are now able to put it where it belongs. Additionally if you wrote a generic view helper you can use it in any of your extensions, because the logic behind it doesn't change.  

View helpers can be any kinds of widgets from the more complicated pagebrowser to something as simple as a view helper that adds a <br /> after an element if it is not empty (remember our example from the beginning?). Once written they actually give the frontend developers even more power - if you look at the default view helpers it's for example possible to easily add classes to generated links, format dates or numbers or crop a text to a certain count of chars. Especially the last one is usefull as if you are generating teasers for news articles, you most likely want them cropped to a length matching design. In most cases it's the frontend developer that decides which length that is. With fluid he doesn't have to ask the programmer to change the setting, he can do it himself.

Example:

We want to output a little address book. We have records of addresses containing default address data like name, street, city, email and homepage.  

<PHP> 

$addressesArray = [fetch data];
foreach ($addressesArray as $address) {
    if ($address['email']) {
        $email = $this->localCObj->typoLink(
            $address['email'],
            array('parameter' =>  $address['email'])
        );
    } else {
        $email = '';
    }
    if($address['homepage']) {
        $homepage = $this->localCObj->typoLink(
            $address['homepage'],
            array('parameter' =>  $address['homepage'])
        );
    } else {
        $homepage = '';
    }
    $marker['###NAME###'] = $address['name'];
    $marker['###STREET###'] = $address['street'];
    $marker['###CITY###'] = $address['city'];
    $marker['###EMAIL###'] =
    $marker['###HOMEPAGE###'] = $address['name'];
    [marker substitution]
}
</PHP>
<HTML>
<div class="address">
    ###NAME### <br />
    ###STREET### <br />
    ###CITY### <br />
    ###EMAIL### <br />
    ###HOMEPAGE###
</div>


</HTML> 

First you have fetched some address data via PHP, then looped through it so you have all records in a matching data array, then you substitute them in the template. The first problem is already pretty obvious just looking at the code. You have to check whether or not the email or homepage is set, as those fields are non-required. You might argument that such a simple check is not that bad, but it gets worse if you look at the template. What happens if both email and homepage are not set? You get an output with two superfluous <br /> tags, most likely breaking your layout: 

<HTML> 

<div class="address">
    Some Name <br />
    Some Street <br />
    Some City <br />
    <br />
</div> 

</HTML> 

What can you do to prevent that? Easiest way would be to set the <br /> in your PHP code depending on the availability of the data.  

<PHP> 

    if ($address['email']) {
        $email = $this->localCObj->typoLink(
            $address['email'],
            array('parameter' =>  $address['email'])
        ) . '<br />';

</PHP> 

I hope you agree that this is the ugliest way because you have to hardcode HTML code in your template. Another way would be to make that part configurable via TypoScript as a wrap. That way is nicer but has the disadvantage that no pure HTML / template designer can change it easily and you will find bits and pieces of the rendered output everywhere,  in TS and in the template. The third way - keeping all the HTML in the template - would be to use an additional subpart that is used for displaying the email / homepage data:

<HTML> 

<div class="address">
    ###NAME### <br />
    ###STREET### <br />
    ###CITY### <br />
    <!-- ###EMAILSUBPART### begin -->
        ###EMAIL### <br />
    <!-- ###EMAILSUBPART### end -->
    <!-- ###HOMEPAGESUBPART### begin -->
        ###HOMEPAGE###
    <!-- ###HOMEPAGESUBPART### end -->
</div>

</HTML> 

This works but adds a lot of useless clutter to your template as well as added complexity to your substitution PHP code. It manages to keep every HTML in the template but for the price of additional work on both ends. 

Now let's have a look how fluid would handle this (using extbase for the PHP parts).  

<PHP> 

$addressObjects = [fetch data];
$this->view->assign('addresses', $addressObjects);

</PHP> 

<HTML/FLUID> 

<f:for each="{addresses}" as="address">
    <div class="address">
        {address.name} <br />
        {address.street} <br />
        {address.city}  <br />
<
f:if condition="{address.email}">
<f
:link.email email="{address.email}">{address.email}</f:link><br />
</f
:if>
<f
:if condition="{address.homepage}">
<f
:link.external

"{address.homepage}">{address.homepage}

</f:link.external>
            <br />

</f:if>
</div>
</f
:for>

</HTML/FLUID> 

As you can see no view logic pollutes our PHP code. We just fetch the data and hand it over to the template where we use view helpers to get our desired result. The nice thing about this is that we can have the template related logic in the template without taking away the possibility to work with a normal HTML editor or even with a WYSIWYG tool because the tags will be just hidden. The WYSIWYG editor would display something like: 

{address.name}
{address.street}
{address.city}
{address.email}
{address.homepage} 

If we look at it the other way round we can have our frontend developer (HTML guy) create the full template with any editor he likes and the programmer can add the variables / logic later without problems. They can both work together on the same template without blocking each other. To go one step further: Our frontend developer might get interested in doing some fluid stuff itself. He doesn't need to learn any complex programming language to get basic stuff working.  

Take for example zebra rows. Zebra rows are something that frontend developers decide to have. In the normal flow the frontend developer would go to the programmer and ask him to add the proper css classes. Now with fluid - which has a syntax that he's used to anyway, as it uses tags - he might be able to add those zebra classes himself. It shouldn't take a sophisticated HTML and CSS guy longer to learn fluid than to learn e.g. HTML5.