5. Views

So far we only have our “Hello world!” output hardcoded in our PHP Code. That’s not helpful, so let’s introduce Views with Fluid.

5.1. Fluid

Fluid is the TYPO3 Template engine. Nowadays it’s standalone, but was developed for and by TYPO3.

It follows XML / HTML which should make it easier to get started.

Fluid templates are valid HTML and custom tags, called ViewHelpers, are introduced to bring in logic.

5.2. Convention over configuration

Extbase follows the principle “Convention over configuration”, which we already saw with our Controller. We didn’t configure the path or class name, it just follows a convention.

Same is true for the output of plugins. If “something” is returned, this will be the output. If nothing is returned, Extbase will call Fluid to render a Fluid template.

5.3. Paths

The path to the template of an controller action is example_extension/Resources/Private/Templates/ControllerName/ActionName.html, which in our example would be: example_extension/Resources/Private/Templates/Example/Example.html,

Task

Move the output to a fluid template, following Extbase conventions.

So let’s create the file and move the “Hello world!” to this file. We should make a small change, otherwise we will not see whether our change has worked. E.g. make the “w” uppercase “W”.

Do not forget to remote the return 'Hello world!'; from our controller.

We should now see our “Hello World!”.

5.4. Configuration

Awesome, we now do no longer need to touch PHP code to change the output, we can use Fluid and an Integrator is able to change something.

But they should be able to change templates in their own extension, e.g. a “sitepackage”. We will see how to do this in next chapter Configuration, especially Adjusting view paths.

5.5. Sections

If templates grow in size, we need to add some structure. One way is to use sections inside a single template. A section is like a PHP method or function and can be called with arguments:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Normal output

{f:render(
   section: 'FirstSection',
   arguments: {
      arg1: var1,
      arg2: var2,
      arg3: 'string'
   }
)}

<f:section name="FirstSection">
   Some output + {arg1}.
</f:section>

We have our default output “Normal output” and call a ViewHelper f:render with some arguments to render a specific section with some arguments. The ViewHelper will be replaced with the rendered result of the section.

This way it’s possible to structure templates like Controllers. They control the output flow and call different sections with arguments where more specific logic happens.

5.6. Variables

Variables are assigned via PHP:

1
2
3
4
5
6
7
8
9
// Inside a controller action do:
$this->view->assign('var1', $variable1);
$this->view->assign('var2', $variable2);

// Or to assign multiple variables at once:
$this->view->assignMultiple([
    'var1' => $variable1
    'var2' => $variable2
]);

Assigned variables can be accessed inside Fluid with curly braces:

1
Hello {userInput}!

5.7. ViewHelper

To make templates more flexible, ViewHelpers are available. They are custom HTML-Tags available inside the template engine. TYPO3 and Fluid already ship some ViewHelpers, but you can provide own ViewHelpers.

ViewHelpers always live in a Namespace, e.g. \TYPO3\CMS\Fluid\ViewHelpers or \Workshop\ExampleExtension\ViewHelpers.

You can either register these namespaces globally, or inside the templates via {namespace wee=Workshop\ExampleExtension\ViewHelpers}. The f namespace for Fluid is always registered globally.

Once ViewHelpers are available available, you can use them:

<f:format.crop maxCharacters="5">Hello World!</f:format.crop>

The above should output “Hello ...”, as the string is cropped to 5 characters, the ”...” can be configured via another argument of the ViewHelper:

<f:format.crop maxCharacters="5" append="">Hello World!</f:format.crop>

Beside the tag based kind of inserting ViewHelpers, you can also use the “inline notation”:

1
{f:format.date(date: 'midnight')}

It’s also possible to chain ViewHelpers in both ways:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{f:format.date(date: 'midnight') -> f:format.raw()}

<f:format.raw>
   {f:format.date(date: 'midnight')}
</f:format.raw>

<f:format.raw>
   <f:format.date date="midnight" />
</f:format.raw>

<f:format.raw>
   <f:format.date>midnight</f:format.date>
</f:format.raw>

5.8. Partials and Layouts

We already saw sections to make a single template easier to manage. For re-using parts between multiple templates there are Partials.

Partials are like templates and can be rendered via:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Normal output

{f:render(
   partial: 'Path/To/Partial',
   arguments: {
      arg1: var1,
      arg2: var2,
      arg3: 'string'
   }
)}

Also each template can be embedded into a Layout via:

1
<f:layout name="Layout/Path/AndName" />

This way wrapping code, e.g. for HTML E-Mails or content elements can be moved to a layout and all templates can inherit this layout.

5.9. Further resources

Hint

Use ViewHelpers for output logic, not to get data into your View.

Use Controller and DataProcessing to prepare data.