[TASK] Allow multiple extractor services with the same priority
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Documentation / Changelog / 8.0 / Feature-69863-UseNewStandaloneFluidAsComposerDependency.rst
1
2 .. include:: ../../Includes.txt
3
4 =================================================================
5 Feature: #69863 - Use new standalone Fluid as composer dependency
6 =================================================================
7
8 See :issue:`69863`
9
10 Description
11 ===========
12
13 The Fluid rendering engine of TYPO3 CMS is replaced by the standalone capable Fluid which is now included as composer dependency.
14 The old Fluid extension is converted to a so-called Fluid adapter which allows TYPO3 CMS to use standalone Fluid with the many
15 new features this facilitates.
16
17
18 Impact
19 ======
20
21 New features/capabilities have been added in nearly all areas of Fluid. Most importantly: several of the Fluid components which
22 in the past were completely internal and impossible to replace, are now easy to replace and have been fitted with a public API.
23 Unless noted otherwise each feature below is part of such a new API component which you can replace. This gives you unprecedented
24 control over almost all of Fluid's behaviours in a way that can be controlled via each View instance, for example from within a
25 controller's initializeView method.
26
27 Developers working with just the template side of Fluid will not notice many differences. Those that they will notice are, for
28 the most part, hidden away beneath a compatibility flag that is set via the View, allowing each extension to opt-in to the
29 extended capabilities or to stick with the legacy behaviour of Fluid. The new features that relate to these new behaviours are:
30
31 RenderingContext
32 ----------------
33
34 The most important new piece of public API is the RenderingContext. The previously internal-only RenderingContext used by Fluid
35 has been expanded to be responsible for a vital new Fluid feature: implementation provisioning. This enables a developer to
36 change a range of classes Fluid uses for parsing, resolving, caching etc. by either including a custom RenderingContext or
37 manipulating the default RenderingContext by public methods, a developer is able to change a range of classes Fluid uses for
38 parsing, resolving, caching etc.
39
40 Each component which can be replaced this way is described in further detail below.
41
42 Impact for template developers
43 ==============================
44
45 The following behaviours can all be controlled by manipulating the RenderingContext. By default, none of them are enabled - but
46 calling a simple method (via your View instance) allows you to enable them:
47
48 .. code-block:: php
49
50         $view->getRenderingContext()->setLegacyMode(false);
51
52 Doing so causes the RenderingContext to deliver different implementations, which simply means that in addition to what you
53 already know Fluid to be capable of (variable access, inline syntax etc.) you gain access to the following features:
54
55 ExpressionNodes
56 ---------------
57
58 Expression Nodes are a new type of Fluid syntax structures which all share a common trait: they only work inside the curly braces
59 previously only used by variable accessing and inline syntax of ViewHelpers. You can define the exact collection of
60 ExpressionNodes that are active for your rendering process, via the View instance:
61
62 .. code-block:: php
63
64         $view->getRenderingContext()->setExpressionNodeTypes(array(
65                 'Class\Number\One',
66                 'Class\Number\Two'
67         ));
68
69 When added to this collection these Expression Node types allow new syntaxes such as `{myVariable + 1}` or
70 `{myArrayLikeObject as array}`. When the legacy mode toggle is set to `false` this will enable the following
71 expression types:
72
73 1. CastingExpressionNode - this type allows casting a variable to certain types, for example to guarantee an integer or a
74    boolean. It is used simply with an `as` keyword: `{myStringVariable as boolean}`, `{myBooleanVariable as integer}` and
75    so on. Attempting to cast a variable to an incompatible type causes a standard Fluid error.
76 2. MathExpressionNode - this type allows basic mathematical operations on variables, for example `{myNumber + 1}`,
77    `{myPercent / 100}`, `{myNumber * 100}` and so on. An impossible expression returns an empty output.
78 3. TernaryExpressionNode - this type allows an inline ternary condition which only operates on variables. The use case is "if
79    this variable then use that variable else use another variable". It is used as
80    `{myToggleVariable ? myThenVariable : myElseVariable}`. Note that it does not support any nested expressions, inline
81    ViewHelper syntaxes or similar inside it - it must be used only with standard variables as input.
82
83 Developers can add their own additional ExpressionNodeTypes. Each one consists of a pattern to be matched and methods dictated
84 by an interface to process the matches - any existing ExpressionNode type can be used as reference.
85
86 Namespaces are extensible
87 -------------------------
88
89 Fluid now allows each namespace alias (for example `f:`) to be extended by adding to it additional PHP namespaces that are
90 also checked for the presence of ViewHelper classes. This is what allows TYPO3 CMS to transparently add just the ViewHelpers that
91 are unique to TYPO3 CMS and let Fluid add the rest. It also means that developers can override individual ViewHelpers with custom
92 versions and have their ViewHelpers called when the `f:` namespace is used.
93
94 This change also implies that namespaces are no longer monadic - any time you use `{namespace f=My\Extension\ViewHelpers}` you
95 will no longer receive an error with "namespace already registered". Fluid will instead add this PHP namespace and look for
96 ViewHelpers there as well. Additional namespaces are checked from the bottom up, allowing the additional namespaces to override
97 ViewHelper classes by placing them in the same scope (e.g. `f:format.nl2br` can be overridden with
98 `My\Extension\ViewHelpers\Format\Nl2brViewHelper` given the namespace registration example above.
99
100 The behaviour is used both for legacy namespace registration in curly braces and the modern `xmlns` approach using a
101 container HTML tag.
102
103 Rendering using f:render
104 ------------------------
105
106 This specific ViewHelper is fundamentally different in the standalone Fluid version - in the default (current) usage scenarios
107 it behaves completely like you are used to, but has been fitted with some major impact features that you can use whenever you
108 want to, in any template.
109
110 There are two specific changes both documented in their respective commits:
111
112 1. Default content (when section/partial is missing) now possible - https://github.com/TYPO3Fluid/Fluid/commit/cd67f9d974bc489058bde1c4272b480eb349da09
113 2. Tag content of `f:render` can now be passed as a variable to the section/partial being rendered (essentially becoming a
114    wrapping/block strategy) - https://github.com/TYPO3Fluid/Fluid/commit/454121cba81baed4e3fe526412ff3e14f7c499a9
115
116 All TagBasedViewHelpers natively support data- prefixed attributes
117 ------------------------------------------------------------------
118
119 Simply put - any TagBasedViewHelper can now receive `data-` prefixed attributes without requiring those attributes to be
120 declared by the ViewHelper. Any suffix can be used as long as the prefix is `data-`.
121
122 Complex conditional statements
123 ------------------------------
124
125 As a forced new feature - which is backwards compatible - Fluid now supports any degree of complex conditional statements with
126 nesting and grouping:
127
128 .. code-block:: xml
129
130         <f:if condition="({variableOne} && {variableTwo}) || {variableThree} || {variableFour}">
131                 // Done if both variable one and two evaluate to true, or if either variable three or four do.
132         </f:if>
133
134 In addition, `f:else` has been fitted with an "elseif"-like behavior:
135
136 .. code-block:: xml
137
138         <f:if condition="{variableOne}">
139                 <f:then>Do this</f:then>
140                 <f:else if="{variableTwo}">Do this instead if variable two evals true</f:else>
141                 <f:else if="{variableThree}">Or do this if variable three evals true</f:else>
142                 <f:else>Or do this if nothing above is true</f:else>
143         </f:if>
144
145 Dynamic variable name parts
146 ---------------------------
147
148 Another forced new feature, likewise backwards compatible, is the added ability to use sub-variable references when accessing
149 your variables. Consider the following Fluid template variables array:
150
151 .. code-block:: php
152
153         $mykey = 'foo'; // or 'bar', set by any source
154         $view->assign('data', ['foo' => 1, 'bar' => 2]);
155         $view->assign('key', $mykey);
156
157 With the following Fluid template:
158
159 .. code-block:: xml
160
161         You chose: {data.{key}}.
162         (output: "1" if key is "foo" or "2" if key is "bar")
163
164 The same approach can also be used to generate dynamic parts of a string variable name:
165
166 .. code-block:: php
167
168         $mydynamicpart = 'First'; // or 'Second', set by any source
169         $view->assign('myFirstVariable', 1);
170         $view->assign('mySecondVariable', 2);
171         $view->assign('which', $mydynamicpart);
172
173 With the following Fluid template:
174
175 .. code-block:: xml
176
177         You chose: {my{which}Variable}.
178         (output: "1" if which is "First" or "2" if which is "Second")
179
180 This syntax can be used anywhere a variable is referenced, with one exception: variables passed as pure variable accessors cannot
181 contain dynamic parts, e.g. the following will **NOT** work:
182
183 .. code-block:: xml
184
185         {f:if(condition: my{which}Variable, then: 'this', else: 'that')}
186
187 Whereas the following **will** work because the variables are accessed wrapped in a text node:
188
189 .. code-block:: xml
190
191         {f:if(condition: '{my{which}Variable}', then: 'this', else: 'that')}
192
193 In other words: unless your outer variable reference is enclosed with curly braces, Fluid does not detect that you are
194 referencing a dynamic variable and will instead assume you meant a variable actually named `my{which}Variable` which was added
195 as `$view->assign('my{which}Variable', 'value')`.
196
197 New ViewHelpers
198 ---------------
199
200 A few new ViewHelpers have been added to the collection as part of standalone Fluid and as such are also available in TYPO3 from now on:
201
202 * `f:or` which is a shorter way to write (chained) conditions. It supports syntax like
203   `{variableOne -> f:or(alternative: variableTwo) -> f:or(alternative: variableThree)}` which checks each variable and outputs
204   the first one that's not empty.
205 * `f:spaceless` which can be used in tag-mode around template code to eliminate redundant whitespace and blank lines for
206   example caused by indenting ViewHelper usages.
207
208 Improved error reporting
209 ------------------------
210
211 Syntax errors or problems with required arguments or incorrect argument types will now be reported with line number and template
212 code example from the line that fails. Any ViewHelper Exception is turned into this improved error type by converting it to a
213 special syntax error and attaching the original Exception to it.
214
215 An example error could be:
216
217 ``TYPO3Fluid\Fluid\Core\Parser\Exception: Fluid parse error in template Default_action_Default_1cb8dc11e29962882f629f79c0b9113ff33d6219,
218 line 11 at character 3. Error: The ViewHelper "<f:serender>" could not be resolved. Based on your spelling, the system would load
219 the class "TYPO3Fluid\Fluid\ViewHelpers\SerenderViewHelper", however this class does not exist. (1407060572). Template code:
220 <f:serender section="Foo" optional="1">``. A stack trace is still included if TYPO3 does not run in Production context.
221
222 Impact for extension developers
223 ===============================
224
225 Extension developers are affected mainly by gaining access to a range of new APIs that control Fluid's behavior. These new APIs
226 can all be accessed via the RenderingContext which is available in Views and ViewHelpers (also when compiled). Developers can
227 provide custom implementations or manipulate the standard implementations by retrieving each API through the RenderingContext
228 and using methods of those.
229
230 There are no significant changes to best practices and the ViewHelper API (which you use when creating custom ViewHelpers)
231 remains largely untouched. The most notable change is that `$this->renderingContext` in ViewHelpers and Views now allows direct
232 access to on-the-fly changes in Fluid's behavior.
233
234 RenderingContext as implementation API
235 --------------------------------------
236
237 Rather than just being a simple context which hangs on to variables, the RenderingContext has been given a completely new and
238 even more vital role in Fluid - it is now the API for delivering custom implementations for a range of features that until now
239 were only possible to achieve via means like XCLASSing. A RenderingContext now delivers the following components:
240
241 * The VariableProvider (previously known as TemplateVariableContainer, see below) used in rendering
242 * The ViewHelperVariableContainer (already known) used in rendering
243 * The ViewHelperResolver (new pattern) responsible for handling namespaces and resolving/creating ViewHelper instances
244   and arguments
245 * The ViewHelperInvoker (new pattern) responsible for calling ViewHelpers (circumvented when ViewHelpers implement a custom
246   `compile()` method)
247 * The TemplatePaths (new pattern) which is a template file resolving class that now contains resolving methods previously found
248   on the View itself
249 * The TemplateParser (already known) which is responsible for parsing the template and creating a ParsedTemplate
250 * The TemplateCompiler (already known) which is responsible for converting a ParsedTemplate to a native PHP class
251 * The FluidCache (new pattern) which is a custom caching implementation compatible with TYPO3 caching frontends/backends
252   storing PHP files
253 * An array of ExpressionNodeTypes (class names, new pattern) - see description of those above
254 * An array of TemplateProcessors (instances, new pattern) which pre-process template source code before it gets handed off to the
255   TemplateParser, allowing things like extracting registered namespaces in custom ways.
256 * The controller name, if one applies to the context
257 * The controller action name, if one applies to the context
258 * And for TYPO3 CMS only, the Extbase ControllerContext (which is as it has always been; contains a Request etc.).
259
260 All (!) of which can be replaced with custom implementations and all of which are accessible through View and ViewHelpers alike.
261 Just a few of the capabilities you gain:
262
263 * You can create custom VariableProvider implementations which retrieve variables in new ways from new sources - Fluid itself now
264   includes a JSON-based VariableProvider as well as a ChainedVariableProvider which allows "plugging" multiple variable sources.
265 * You can create a custom ViewHelperResolver implementation which can do things like automatically register namespaces that are
266   always available or change the way ViewHelper classes are detected, instantiated, how arguments are detected, and more.
267 * You can create a custom ViewHelperInvoker implementation which calls ViewHelpers in new ways - combined with a custom
268   ViewHelperResolver this can for example allow non-ViewHelper classes to be used as if they actually were ViewHelpers.
269 * You can create custom TemplatePaths implementations which for example read template sources not from the local file system but
270   from database, remote storage, zip files, whatever you desire.
271 * You can replace the TemplateParser itself (but be careful if you do, obviously). There are no current use cases for this, but
272   the possibility exists.
273 * You can replace the TemplateCompiler (be careful here too). No use case exists but this could be used to compile Fluid
274   templates to other things than PHP.
275 * You can replace the Cache implementation - for example to cache compiled Fluid templates in memcache or a distributed cache
276   accessible by PHP opcache.
277 * You can change which Expression Node types are possible to use in templates rendered with your context, for example disabling
278   ternary expressions or adding a custom type of expression of your own.
279 * You can change which TemplateProcessors will be used to process templates when rendered with your context, to do whatever you
280   like - transform, analyze and so on the template source.
281
282 All of these parts are possible to replace via the provided RenderingContext - you don't necessarily have to create your own -
283 but when creating multiple implementations it is often easier to combine those in a custom RenderingContext and just provide
284 that for your View.
285
286 But perhaps most importantly, because all of these components are contained in the RenderingContext which is available to Views
287 and ViewHelpers alike (also once compiled!), it becomes possible for your View or ViewHelpers to actually interact with the Fluid
288 environment in powerful ways. To illustrate how powerful, you could create a single ViewHelper which: manipulates the Expression
289 Node types usable in its tag content, changes the paths used to resolve Partials, registers a number of other ViewHelper
290 namespaces, changes the variable source to be a JSON file or URL and adds a pre-processing class that triggers on every template
291 source read from within the ViewHelper's tag contents, to strip some undesired namespace from third party Partials. And it could
292 restore the context afterwards so that all of this only applies inside that ViewHelper's tag content.
293
294 ViewHelper namespaces can be extended also from PHP
295 ---------------------------------------------------
296
297 By accessing the ViewHelperResolver of the RenderingContext, developers can change the ViewHelper namespace inclusions on a
298 global (read: per View instance) basis:
299
300 .. code-block:: php
301
302         $resolver = $view->getRenderingContext()->getViewHelperResolver();
303         // equivalent of registering namespace in template(s):
304         $resolver->registerNamespace('news', 'GeorgRinger\News\ViewHelpers');
305         // adding additional PHP namespaces to check when resolving ViewHelpers:
306         $resolver->extendNamespace('f', 'My\Extension\ViewHelpers');
307         // setting all namespaces in advance, globally, before template parsing:
308         $resolver->setNamespaces(array(
309                 'f' => array(
310                         'TYPO3Fluid\\Fluid\\ViewHelpers',
311                         'TYPO3\\CMS\\Fluid\\ViewHelpers',
312                         'My\\Extension\\ViewHelpers'
313                 ),
314                 'vhs' => array(
315                     'FluidTYPO3\\Vhs\\ViewHelpers',
316                     'My\\Extension\\ViewHelpers'
317                 ),
318                 'news' => array(
319                         'GeorgRinger\\News\\ViewHelpers',
320                 );
321         ));
322
323 By "extending" a namespace Fluid adds additional lookup namespaces when detecting ViewHelper classes and uses the last added path first, allowing you to replace ViewHelpers by placing a class with the same sub-name in your own ViewHelpers namespace that extends Fluid's. Doing so also allows you to change the arguments the ViewHelper accepts/requires.
324
325 ViewHelpers can accept arbitrary arguments
326 ------------------------------------------
327
328 This feature allows your ViewHelper class to receive any number of additional arguments using any names you desire. It works by
329 separating the arguments that are passed to each ViewHelper into two groups: those that are declared using `registerArgument`
330 (or render method arguments), and those that are not. Those that are not declared are then passed to a special function -
331 `handleAdditionalArguments` - on the ViewHelper class, which in the default implementation throws an error if additional
332 arguments exist. So by overriding this method in your ViewHelper you can change if and when the ViewHelper should throw an
333 error on receiving unregistered arguments.
334
335 This feature is also the one allowing TagBasedViewHelpers to freely accept arbitrary `data-` prefixed arguments without
336 failing - on TagBased ViewHelpers, the `handleAdditionalArguments` method simply adds new attributes to the tag that gets
337 generated and throws an error if any additional arguments which are neither registered nor prefixed with `data-` are given.
338
339 ViewHelpers automatically compilable
340 ------------------------------------
341
342 All ViewHelpers, including those you write yourself, are now automatically compilable. This means you no longer have to care
343 about implementing the CompilableInterface or a custom `compile()` function, and that every Fluid template can now be cached
344 to a compiled PHP script regardless of ViewHelpers.
345
346 ViewHelpers still are able to define a custom `compile()` function but are no longer required to do so. When they don't define
347 such a method, an execution is chosen which is identical in performance to calling the ViewHelper from a template that before
348 this could not be compiled. The ViewHelpers that do define a custom compiling method can further increase performance.
349
350 When you explicitly require a ViewHelper of yours to prevent template caching it is possible to implement a custom `compile()`
351 method which calls `$templateParser->disable();` and nothing else. Doing this disables the compiling inside the scope (template,
352 partial or section) currently being rendered.
353
354 New and more efficient escaping
355 -------------------------------
356
357 Contrary to earlier versions of Fluid which used a ViewHelperNode for `f:format.htmlentities` around other nodes it wished to
358 escape, standalone Fluid has implemented a custom SyntaxTreeNode type which does the escaping in a more efficient manner
359 (directly using `htmlentities`). Although it means you cannot override this escaping behaviour by overriding the
360 `f:format.htmlentities` ViewHelper (which is completely possible to do with Fluid now) it should mean a significant boost to
361 performance as it avoids an excessive amount of ViewHelper resolving and -rendering operations, replacing them with a single PHP
362 function call wrapped in a tiny class, which compiles also to a single function call and which compiles in a way that it wraps
363 the compiled output of the Node it escapes as a pure string operation.
364
365 Escaping interception is still contained within the `Configuration` instance given to the TemplateParser - and those can be
366 manipulated with a custom RenderingContext (see above).
367
368 .. index:: Fluid, PHP-API, Frontend, Backend