diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7bea25ae5..b3101c671 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -48,5 +48,6 @@ jobs:
- name: Documentation integrity
run: |
- FLUID_DOCUMENTATION_OUTPUT_DIR=Documentation/ViewHelpers vendor/bin/fluidDocumentation generate vendor/t3docs/fluid-documentation-generator/config/fluidStandalone/*
+ FLUID_DOCUMENTATION_OUTPUT_DIR=DocumentationTemp vendor/bin/fluidDocumentation generate vendor/t3docs/fluid-documentation-generator/config/fluidStandalone/*
+ cp -r DocumentationTemp/Fluid DocumentationTemp/Fluid.json Documentation/ViewHelpers/ && rm -r DocumentationTemp
git add Documentation/*; git status; git status | grep -q "nothing to commit, working tree clean"
diff --git a/Documentation/Development/Decisions.rst b/Documentation/Development/Decisions.rst
deleted file mode 100644
index 2bc002c10..000000000
--- a/Documentation/Development/Decisions.rst
+++ /dev/null
@@ -1,146 +0,0 @@
-.. include:: /Includes.rst.txt
-
-.. _decisions:
-
-======================================
-Decoupling decisions and compatibility
-======================================
-
-This is a historical elaboration on some details when this project has been
-decoupled form `TYPO3.Flow` and made a standalone library. Isn't of too much
-help nowadays anymore, but can be helpful for some insight on why things
-materialized as is.
-
-In order to decouple this package from `TYPO3.Flow` a few necessary but
-implication-filled decisions had to be made.
-
-No more dependency injection
-============================
-
-It is simply gone and will not be implemented again in any shape or form. The DI
-concept from `TYPO3.Flow` does not apply on a wider scale and it is every bit as
-possible to achieve the same results through the constructor methods. While DI
-is a nice concept for usability, it is better to sacrifice it for more universal
-class support.
-
-No more widget support
-======================
-
-It is also gone and will not be implemented again. However: because of the
-nature of Fluid and ViewHelpers, **recreating the implementation that behaves
-like Widgets but does so in the context of the framework in which it gets used**
-is the correct way to achieve this behavior.
-
-As an added benefit, all translated labels and a **lot** of functional tests and
-fixtures can and have been removed.
-
-ViewHelpers can't use render method arguments
-=============================================
-
-Although still technically feasible to implement, a decision was made to
-sacrifice the support for `render()` method arguments in ViewHelpers
-(as opposed to using `registerArgument` inside `initializeArguments`).
-The following reasons are given:
-
-1. Render method type hinting beyond strict types is impossible without
- analysing phpdoc comments which implies Reflection as well as a dependency
- on the `TYPO3.Flow` annotation parser.
-2. Performance and testability is exactly the same.
-3. A single method to register arguments now exists and `ArgumentDefinition` can
- be reduced in complexity.
-4. Having only one method to check in every instance means better performance
- overall.
-
-Overriding these capabilites is possible and implies a custom
-`ViewHelperInvoker` returned from a custom `ViewHelperResolver`.
-
-The View consumes TemplatePaths
-===============================
-
-Rather than allow the View class to be aware of the Request via the
-ControllerContext, both the Request and ControllerContext concepts have been
-completely removed. A new strategy has taken the place of these: the
-TemplatePaths.
-
-In order to instantiate a View instance, a special TemplatePaths instance must
-now be passed as first argument. This TemplatePaths instance *is then
-responsible for all the resolving and retrieval of template files*. This means
-that replacing the TemplatePaths instance that gets used will allow another
-implementation to **effectively change how Fluid resolves template files**.
-
-This also means that the View itself no longer has any file resolving
-capabilities. Instead, it relies on the provided instance to resolve every file
-and template source. For usability, there are dedicated methods to set template
-path and filename as well as layout path and filename.
-
-**Because of this the path treatments are now completely decoupled and no longer
-uses expression expansions to create arrays of expected paths**. Instead, each
-path is iterated and the epected filename checked and returned if found. In
-order to potentially re-implement this decoupled package into `TYPO3.Flow` as
-well as `TYPO3.CMS` this means that these paths can then be generated by the MVC
-and simply passed along to the View - or, íf more complex behavior is required,
-a custom TemplatePaths implementation can be created.
-
-As a side effect of this, **the View no longer supports any options**. Where
-before a user was able to pass paths, filenames and other settings as `options`
-on the View, such behavior is no longer required due to the use of
-TemplatePaths. However, such behavior can be restored by subclassing the
-TemplateView and adding `options` support which simply delegates to
-TemplatePaths to change root paths etc.
-
-Obviously your paths can no longer use any custom syntax or markers for
-replacement such as `EXT:...` paths or `@marker` patterns. To use such
-expressions make sure you convert the paths *before* you pass them to the View;
-e.g. do so inside your custom TemplatePaths or before you pass the paths to the
-built-in TemplatePaths object.
-
-Deprecated code has been evicted
-================================
-
-This includes all and every support for the legacy path name conventions - only
-arrays of paths are now accepted except when specifying the full template- or
-layout path and filename on the View.
-
-Note about injecting functionality
-==================================
-
-It is possible to restore almost all of the removed features by creating custom
-implementations of the following classes:
-
-* https://github.com/TYPO3Fluid/Fluid/blob/main/src/View/TemplatePaths.php to
- change how template files are resolved.
-* https://github.com/TYPO3Fluid/Fluid/blob/main/src/Core/ViewHelper/ViewHelperResolver.php
- to change how each ViewHelper is resolved, how its arguments are retrieved,
- which namespaces are available and expected class names of ViewHelpers.
-
-When combined in a package that implements `TYPO3.Fluid` in a framework, these
-two classes together make it possible to change all the behaviors that were
-changed to make `TYPO3.Fluid` more portable. The solutions are, in order:
-
-1. Dependency injection in ViewHelpers can be restored by overriding the
- `createViewHelperClassInstance` method of the ViewHelperResolver
- implementation. The View itself can of course also be loaded by an object
- manager that does injection.
-2. Widgets can be reintroduced as a framework-specific feature by making the
- ViewHelperResolver return the desired class names when the TemplateParser
- tries to load the ViewHelpers that were removed. This includes all of the
- other ViewHelpers which were sacrificed for portability because they had too
- strong dependencies on the framework; for example the `f:form` helpers known
- from TYPO3 CMS and Flow.
-3. The arguments of each ViewHelper can be adjusted - or the class itself can be
- replaced. This allows the framework to replace those ViewHelpers that have
- been "dumbed down" (for example the debug ViewHelper which in CMS or Flow
- would use the DebuggerUtility to display variables but in this standalone
- version uses a plain `var_dump`).
-4. The TemplatePaths implementation can be replaced by one that supports the
- necessary folder structures and path treatments, for example allowing the
- `EXT:....` syntax in paths and making it possible to "bubble sub package" or
- whatever special feature the template file resolving should support.
-5. Deprecated code and support for legacy class names can be introduced by
- overriding the ViewHelperResolver. The aliases can be defined any way
- desired - as long as the ViewHelperResolver is aware of them and will return
- the **new** class as replacement.
-6. The way the ViewHelpers are themselves executed can be overridden via a
- custom ViewHelperInvoker returned from the custom ViewHelperResolver.
- Overriding this part allows, among other things, restoring the `render()`
- method argument support.
diff --git a/Documentation/Development/Expressions.rst b/Documentation/Development/Expressions.rst
deleted file mode 100644
index d65820be1..000000000
--- a/Documentation/Development/Expressions.rst
+++ /dev/null
@@ -1,138 +0,0 @@
-.. include:: /Includes.rst.txt
-
-.. _creating-expressionnodes:
-
-========================
-Creating ExpressionNodes
-========================
-
-To understand what an ExpressionNode is and which cases can be solved by
-implementing custom ones, first read the
-:doc:`chapter about implementing Fluid `. Once you
-grasp what an ExpressionNode is and how it works, a very brief example is all
-you need.
-
-First: an ExpressionNode is always one PHP class. Where you place it is
-completely up to you - but to have the class actually be detected and used by
-Fluid, *the class name must be returned from a custom ViewHelperResolver*.
-This concept is also explained in the implementation chapter.
-
-In Fluid's default ViewHelperResolver, the following code is responsible for
-returning expression node class names:
-
-.. code-block:: php
-
- /**
- * List of class names implementing ExpressionNodeInterface
- * which will be consulted when an expression does not match
- * any built-in parser expression types.
- *
- * @var string
- */
- protected $expressionNodeTypes = [
- 'TYPO3Fluid\\Fluid\\Core\\Parser\\SyntaxTree\\Expression\\CastingExpressionNode',
- 'TYPO3Fluid\\Fluid\\Core\\Parser\\SyntaxTree\\Expression\\MathExpressionNode',
- 'TYPO3Fluid\\Fluid\\Core\\Parser\\SyntaxTree\\Expression\\TernaryExpressionNode',
- ];
-
- /**
- * @return string
- */
- public function getExpressionNodeTypes()
- {
- return $this->expressionNodeTypes;
- }
-
-You may or may not want the listed expression nodes included, but if you change
-the available expression types you should of course document this difference
-about your implementation.
-
-The following are fairly normal ways of replacing or extending this array of
-class names:
-
-* Override the property `$expressionNodeTypes` and define your own array
-* Override the `getExpressionNodeTypes` method and return a complete array
-* Override the `getExpressionNodeTypes` method and modify/append the array from
- `parent::getExpressionNodeTypes`
-
-Once you are ready to create your ExpressionNode class, all you need is a very
-simple one. The following class is the ternary ExpressionNode from Fluid itself
-which detects the `{a ? b : c}` syntax and evaluates `a` as boolean and if true,
-renders `b` else renders `c`. To get this behavior, we need a (relatively
-simple) regular expression and one method to evaluate the expression while being
-aware of the rendering context (which stores all variables, controller name,
-action name etc).
-
-.. code-block:: php
-
- assign('variablename', 'value');`. Custom View types can be
-implemented by subclassing the default class - but in order to avoid
-problems, make sure you also call the original class' constructor method.
-
-Creating a custom View allows you to change just a few aspects, mainly about
-composition: which implementations of `TemplatePaths` the View requires, if it
-needs a custom `ViewHelperResolver`, if it must have some default variables, if
-it should have a default cache, etc.
-
-.. note::
-
- The special variable `layoutName` is reserved and can be assigned to a
- template to set its Layout instead of using ``.
-
-TemplatePaths
-=============
-
-In the default `TemplatePaths` object included with `TYPO3.Fluid` we provide a
-set of conventions for resolving the template files that go into rendering a
-Fluid template - the templates themselves, plus partials and layouts.
-
-You should use the default `TemplatePaths` object if:
-
-1. You are able to place your template files in folders that match the
- `TYPO3.Fluid` conventions, including the convention of subfolders named the
- same as your controllers.
-2. You are able to provide the template paths that get used as an array with
- which `TemplatePaths` can be initialized.
-3. Or you are able to individually set each group of paths.
-4. You are able to rely on standard format handling (`format` simply being the
- file extension of template files).
-
-And you should replace the `TemplatePaths` with your own subclass if:
-
-1. You answered no to any of the above.
-2. You want to be able to deliver template content before parsing, from other
- sources than files.
-3. You want the resolving of template files for controller actions to happen in
- a different way.
-4. You want to create other (caching-) identifiers for your partials, layouts
- and templates than defaults.
-
-Whether you use your own class or the default, the `TemplatePaths` instance
-*must be provided as first argument for the View*.
-
-RenderingContext
-================
-
-Because `TYPO3.Fluid` was created in an MVC context it supports MVC behaviors,
-including setting a "context" for your rendering process - to associate the
-rendering with a controller and an action. The default `RenderingContext`
-provided by `TYPO3.Fluid` has limited support: it supports a controller name
-and an action name.
-
-Should you require additional context variables - for example a package name,
-a sub-controller identification, a user validation, the HTTP request object,
-a Response object, or whatever - you can create your own type of
-`RenderingContext` and pass that to the View. Doing this allows you to access
-this `RenderingContext` from within ViewHelpers. One obvious purpose for this
-is to *create custom links to controller actions*.
-
-You should use the default `RenderingContext` object if:
-
-1. You don't use an MVC context - you just render single templates possibly with
- partials and layouts.
-2. You use MVC and are able to rely on just a controller name and action name
- for your implementation.
-3. You can rely on the default way of storing template- and ViewHelper
- variables.
-
-You should replace the `RenderingContext` with your own if:
-
-1. You answered no to any of the above.
-2. You require additional (framework/implementation-specific) attributes on the
- `RenderingContext`.
-3. You require dynamic ways of returning the controller name, action name
- (or other custom attributes).
-4. You wish to modify or replace the special `VariableContainer` objects that
- store variables to implement things like reserved variable names, persistent
- and auto-added variables and similar container-related operations.
-
-Whether you use your own class or the default, the `RenderingContext` instance
-*must be passed as second argument for the View*. If you do not pass a
-`RenderingContext`, the default one will automatically be used.
-
-FluidCache
-==========
-
-The caching of Fluid templates happens by compiling the templates to PHP files
-which execute much faster than a parsed template ever could. These compiled
-templates can only be stored if a `FluidCacheInterface`-implementing object is
-provided. `TYPO3.Fluid` provides one such caching implementation: the
-`SimpleFileCache` which just stores compiled PHP code in a designated directory.
-
-Should you need to store the compiled templates in other ways you can implement
-`FluidCacheInterface` in your caching object.
-
-Whether you use your own cache class or the default, the `FluidCache`
-*must be passed as third parameter for the View* or it
-*must be assigned using `$view->getRenderingContext()->setCache($cacheInstance)`
-before calling `$view->render()`*.
-
-TemplateProcessor
-=================
-
-While custom `TemplatePaths` also allows sources of template files to be
-modified before they are given to the TemplateParser, a custom `TemplatePaths`
-implementation is sometimes overkill - and has the drawback of completely
-overruling the reading of template file sources and making it up to the custom
-class how exactly this processing happens.
-
-In order to allow a more readily accessible and flexible way of pre-processing
-template sources and affect key aspects of the parsing process, a
-`TemplateProcessorInterface` is provided. Implementing this interface and the
-methods it designates allows your class to be passed to the `TemplateView` and
-be triggered every time a template source is parsed, right before parsing
-starts:
-
-.. code-block:: php
-
- $myTemplateProcessor = new MyTemplateProcessor();
- $myTemplateProcessor->setDoMyMagicThing(true);
- $templateView->setTemplateProcessors([
- $myTemplateProcessor
- ]);
-
-The registration method requires an array - this is to let you define multiple
-processors without needing to wrap them in a single class as well as reuse
-validation/manipulation across frameworks and only replace the parts that need
-to be replaced.
-
-This makes the method `preProcessSource($templateSource)` be called on this
-class every time the TemplateParser is asked to parse a Fluid template.
-Modifying the source and returning it makes that new template source be used.
-Inside the TemplateProcessor method you have access to the TemplateParser and
-ViewHelperResolver instances which the View uses.
-
-The result is that TemplateProcessor instances are able to, for example:
-
-* Validate template sources and implement reporting/logging of errors in for
- example a framework.
-* Fix things like character encoding issues in template sources.
-* Process Fluid code from potentially untrusted sources, for example doing XSS
- removals before parsing.
-* Extract legacy namespace definitions and assign those to the
- ViewHelperResolver for active use.
-* Extract legacy escaping instruction headers and assign those to the
- TemplateParser's Configuration instance.
-* Enable the use of custom template code in file's header, extracted and used
- by a framework.
-
-Note again: these same behaviors are possible using a custom `TemplatePaths`
-implementation - but even with such a custom implementation this
-TemplateProcessor pattern can still be used to manipulate/validate the sources
-coming from `TemplatePaths`, providing a nice way to decouple paths resolving
-from template source processing.
-
-ViewHelperInvoker
-=================
-
-The `ViewHelperInvoker` is a class dedicated to validating current arguments of
-and if valid, calling the ViewHelper's render method. The default object
-supports only the arguments added via `initializeArguments` and
-`(register|override)Argument` on the ViewHelper - and it does not use internal
-instance caching; it creates and renders new ViewHelpers for every node.
-
-You should replace the `ViewHelperInvoker` if:
-
-1. You must support different ways of calling ViewHelpers such as alternative
- `setArguments` names.
-2. You wish to change the way the invoker uses and stores ViewHelper instances,
- for example to use an internal cache.
-3. You wish to change the way ViewHelper arguments are validated, for example
- changing the Exceptions that are thrown.
-4. You wish to perform processing on the output of ViewHelpers, for example to
- remove XSS attempts according to your own rules.
-
-.. note::
-
- ViewHelper instance creation and argument retrieval is handled by the
- ViewHelperResolver.
-
-If you wish to use a custom `ViewHelperInvoker` you **must** do so via a custom
-`ViewHelperResolver`. You are given the class name of the ViewHelper to resolve
-a `ViewHelperInvoker` - which means you can also use different invokers for
-different classes.
-
-.. _implementation-view-helper-resolver:
-
-ViewHelperResolver
-==================
-
-In `TYPO3.Fluid` most of your options for extending the language - for example,
-adding new ways to format strings, to make special condition types, custom links
-and such - are connected to ViewHelpers. These are the special classes that are
-called using for exampel
-`{somestring}`.
-
-A ViewHelper is essentially referenced by the namespace and the path to the
-ViewHelper, in this case `f` being the namespace and `format.htmlentities` being
-the path.
-
-The `ViewHelperResolver` is the class responsible for turning these two pieces
-of information into an expected class name and when this class is resolved, to
-retrieve from it the arguments you can use for each ViewHelper.
-
-You should use the default `ViewHelperResolver` if:
-
-1. You can rely on the default way of turning a namespace and path of a
- ViewHelper into a class name.
-2. You can rely on the default way ViewHelpers return the arguments they
- support.
-3. You can rely on instantiation of ViewHelpers happening through a simple
- `new $class()`.
-4. You can rely on the default `ViewHelperInvoker`.
-
-You should replace the `ViewHelperResolver` if:
-
-1. You answered no to any of the above.
-2. You want to make ViewHelper namespaces available in templates without
- importing.
-3. You want to change which class is resolved from a given namespace and
- ViewHelper path, for example allowing you to add your own ViewHelpers to the
- default namespace or replace default ViewHelpers with your own.
-4. You want to change the argument retrieval from ViewHelpers or you want to
- manipulate the arguments (for example, giving them a default value, making
- them optional, changing their data type).
-5. You have to use a custom `ViewHelperInvoker` to actually render your
- ViewHelpers.
-
-The default `ViewHelperResolver` can be replaced in one way only: calling
-`$view->setViewHelperResolver($resolverInstance);` on the TemplateView. However,
-a custom View class can of course replace this and other aspects of the View
-such as `TemplatePaths`.
-
-ExpressionNodes
-===============
-
-The `ExpressionNode` concept is the most profound way you can manipulate the
-Fluid language itself, adding to it new syntax options that can be used inside
-the shorthand `{...}` syntax. Normally you are confined to using ViewHelpers
-when you want such special processing in your templates - but using
-`ExpressionNodes` allows you to add these processings as actual parts of the
-templating language itself; avoiding the need to include a ViewHelper namespace.
-
-`TYPO3.Fluid` itself provides the following types of `ExpressionNodes`:
-
-1. `MathExpressionNode` which scans for and evaluates simple mathematical
- expressions like `{variable + 1}`.
-2. `TernaryExpressionNode` which implements a ternary condition in Fluid syntax
- like `{ifsomething ? thenoutputthis : elsethis}`
-3. `CastingExpressionNode` which casts variables to a certain type, e.g.
- `{suspectType as integer}`, `{myInteger as boolean}`.
-
-An `ExpressionNode` basically consists of one an expression matching pattern
-(regex), one non-static method to evaluate the expression `public function
-evaluate(RenderingContextInterface $renderingContext)` and a mirror of this
-function which can be called statically:
-`public static evaluteExpression(RenderingContextInterface $renderingContext, $expression)`.
-The non-static method should then simply delegate to the static method and use
-the expression stored in `$this->expression` as second parameter for the static
-method call.
-
-`ExpressionNodes` automatically support compilation and will generate compiled
-code which stores the expression and calls the static `evaluateExpression`
-method with the rendering context and the stored expression.
-
-You should create your own `ExpressionNodes` if:
-
-1. You want a custom syntax in your Fluid templates (theoretical example:
- casting variables using `{(integer)variablename}`).
-2. You want to replace either of the above mentioned `ExpressionNodes` with ones
- using the same, or an expanded version of their regular expression patterns
- to further extend the strings they capture and process.
-
-**Limitations**
-
-1. Contrary to other nodes in Fluid, `ExpressionNodes` cannot be used in tag
- form. Only the shorthand/inline syntax is supported.
-2. `ExpressionNodes` are not recursive unless they have recursive behavior
- internally (this is for example different from array nodes which match
- sub-arrays recursively). In other words: `ExpressionNodes` are intended for
- *simple syntaxes and variables*.
-
-To create a new type of `ExpressionNode` - perhaps one that fits your framework:
-
-1. Make sure you subclass
- `TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\Expression\AbstractExpressionNode`
- and implement `TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\Expression\ExpressionNodeInterface`
- in your class.
-2. Make sure your class pass `public static $detectionExpression = '%s';` where
- `%s` is a perl regular expression which returns at least one match if the
- expression can be handled by your `ExpressionNode` class.
-3. Make sure your class implements a
- `public static evaluateExpression(RenderingContextInterface $renderingContext, $expression)`
- method which will be able to process the expression in a statically called
- context.
-
-Any `ExpressionNode` types added this way are also compilable off-the-bat. The
-one thing you can't change is how this compiling happens - so if your
-`ExpressionNode` does some heavy processing you may consider implementing a
-dedicated cache for it.
-
-Additional `ExpressionNode` class names can be returned from a custom
-`ViewHelperResolver` (see above) by overriding the `getExpressionNodeTypes()`
-method **and/or** the `protected $expressionTypes` property to append your class
-names to the list. Each `ExpressionNode` is consulted in the order they appear
-in this list - and only the first one that matches will be used.
diff --git a/Documentation/Development/Index.rst b/Documentation/Development/Index.rst
deleted file mode 100644
index 72d56a5d8..000000000
--- a/Documentation/Development/Index.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-.. include:: /Includes.rst.txt
-
-.. _development:
-
-===========
-Development
-===========
-
-.. toctree::
- :maxdepth: 2
- :titlesonly:
-
- Implementation
- CreatingViewHelpers
- Expressions
- Decisions
diff --git a/Documentation/Extending/ExpressionNodes.rst b/Documentation/Extending/ExpressionNodes.rst
new file mode 100644
index 000000000..d15229a65
--- /dev/null
+++ b/Documentation/Extending/ExpressionNodes.rst
@@ -0,0 +1,167 @@
+.. include:: /Includes.rst.txt
+
+.. _creating-expressionnodes:
+
+========================
+Creating ExpressionNodes
+========================
+
+The :php:`ExpressionNode` concept is the most profound way you can manipulate the
+Fluid language itself, adding to it new syntax options that can be used inside
+the shorthand `{...}` syntax. Normally you are confined to using ViewHelpers
+when you want such special processing in your templates - but using
+ExpressionNodes allows you to add these processings as actual parts of the
+templating language itself; avoiding the need to include a ViewHelper namespace.
+
+Fluid itself provides the following types of `ExpressionNodes`:
+
+1. :php:`MathExpressionNode` which scans for and evaluates simple mathematical
+ expressions like `{variable + 1}`.
+2. :php:`TernaryExpressionNode` which implements a ternary condition in Fluid syntax
+ like `{ifsomething ? thenoutputthis : elsethis}`
+3. :php:`CastingExpressionNode` which casts variables to a certain type, e.g.
+ `{suspectType as integer}`, `{myInteger as boolean}`.
+
+An :php:`ExpressionNode` basically consists of one an expression matching pattern
+(regex), one non-static method to evaluate the expression
+:php:`public function evaluate(RenderingContextInterface $renderingContext)`
+and a mirror of this function which can be called statically:
+:php:`public static evaluteExpression(RenderingContextInterface $renderingContext, $expression)`.
+The non-static method should then simply delegate to the static method and use
+the expression stored in `$this->expression` as second parameter for the static
+method call.
+
+ExpressionNodes automatically support compilation and will generate compiled
+code which stores the expression and calls the static :php:`evaluateExpression()`
+method with the rendering context and the stored expression.
+
+You should create your own ExpressionNodes if:
+
+1. You want a custom syntax in your Fluid templates (theoretical example:
+ casting variables using `{(integer)variablename}`).
+2. You want to replace either of the above mentioned :php:`ExpressionNodes` with ones
+ using the same, or an expanded version of their regular expression patterns
+ to further extend the strings they capture and process.
+
+.. _creating-expressionnodes-implementation:
+
+Implementation
+==============
+
+An ExpressionNode is always one PHP class. Where you place it is
+completely up to you - but to have the class actually be detected and used by
+Fluid, it needs to be added to the rendering context by calling :php:`setExpressionNodeTypes()`.
+
+In Fluid's default :php:`RenderingContext`, the following code is responsible for
+returning expression node class names:
+
+.. code-block:: php
+
+ /**
+ * List of class names implementing ExpressionNodeInterface
+ * which will be consulted when an expression does not match
+ * any built-in parser expression types.
+ *
+ * @var string
+ */
+ protected $expressionNodeTypes = [
+ 'TYPO3Fluid\\Fluid\\Core\\Parser\\SyntaxTree\\Expression\\CastingExpressionNode',
+ 'TYPO3Fluid\\Fluid\\Core\\Parser\\SyntaxTree\\Expression\\MathExpressionNode',
+ 'TYPO3Fluid\\Fluid\\Core\\Parser\\SyntaxTree\\Expression\\TernaryExpressionNode',
+ ];
+
+ /**
+ * @return string
+ */
+ public function getExpressionNodeTypes()
+ {
+ return $this->expressionNodeTypes;
+ }
+
+You may or may not want the listed expression nodes included, but if you change
+the available expression types you should of course document this difference
+about your implementation.
+
+The following class is the math ExpressionNode from Fluid itself
+which detects the `{a + 1}` and other simple mathematical operations.
+To get this behavior, we need a (relatively
+simple) regular expression and one method to evaluate the expression while being
+aware of the rendering context (which stores all variables, controller name,
+action name etc).
+
+.. code-block:: php
+
+ `
+ :button-style: btn btn-secondary stretched-link
+
+ .. card:: Creating ExpressionNodes
+
+ Learn how to extend Fluid by creating custom expression syntax
+
+ .. card-footer:: :ref:`Learn about ExpressionNodes `
+ :button-style: btn btn-secondary stretched-link
+
+.. toctree::
+ :hidden:
+ :titlesonly:
+
+ ViewHelpers
+ ExpressionNodes
diff --git a/Documentation/Development/CreatingViewHelpers.rst b/Documentation/Extending/ViewHelpers.rst
similarity index 100%
rename from Documentation/Development/CreatingViewHelpers.rst
rename to Documentation/Extending/ViewHelpers.rst
diff --git a/Documentation/Index.rst b/Documentation/Index.rst
index 9e54f74aa..db601777e 100644
--- a/Documentation/Index.rst
+++ b/Documentation/Index.rst
@@ -14,8 +14,7 @@ Fluid Rendering Engine
en
:Author:
- Claus Due, Sebastian Kurfürst, Karsten Dambekalns, Robert Lemke & Fluid
- contributors
+ Fluid contributors
:License:
This document is published under the
@@ -38,15 +37,33 @@ If using Fluid in combination with TYPO3 CMS, a look at the documentation of
**Table of Contents:**
-.. toctree::
- :maxdepth: 2
- :titlesonly:
-
- Installation/Index
- Usage/Index
- Development/Index
- ViewHelpers/Index
- Changelog/Index
+.. toctree::
+ :caption: About Fluid
+ :maxdepth: 1
+ :titlesonly:
+
+ Introduction/Index
+ Installation/Index
+ Usage/Index
+ Syntax/Index
+
+.. toctree::
+ :caption: ViewHelper Reference
+ :maxdepth: 1
+ :titlesonly:
+
+ ViewHelpers/Fluid/Index
+ ViewHelpers/SchemaFiles
+
+.. toctree::
+ :caption: Appendix
+ :maxdepth: 1
+ :titlesonly:
+
+ Extending/Index
+ Integrating/Index
+ Internals/Index
+ Changelog/Index
.. Meta Menu
diff --git a/Documentation/Installation/Index.rst b/Documentation/Installation/Index.rst
index d0db92ac8..f35be11de 100644
--- a/Documentation/Installation/Index.rst
+++ b/Documentation/Installation/Index.rst
@@ -6,18 +6,13 @@
Installation
============
-1. Include as composer dependency using
+Fluid is distributed through composer. It can be added to your project by
+executing the following command:
- .. code-block:: bash
+.. code-block:: bash
- composer require typo3fluid/fluid
+ composer require typo3fluid/fluid
-2. Run
-
- .. code-block:: bash
-
- composer install
-
- to generate the vendor class autoloader.
-
-3. The classes from `TYPO3.Fluid` can now be used in your composer project.
+To get started with Fluid, take a look at the
+:ref:`Fluid Syntax ` as well as the
+:ref:`Getting Started Guide `.
diff --git a/Documentation/Integrating/Index.rst b/Documentation/Integrating/Index.rst
new file mode 100644
index 000000000..6dea23b5d
--- /dev/null
+++ b/Documentation/Integrating/Index.rst
@@ -0,0 +1,255 @@
+.. include:: /Includes.rst.txt
+
+.. _implementations:
+.. _integrating-fluid:
+
+=================
+Integrating Fluid
+=================
+
+Fluid provides a standard implementation which works great on simple MVC
+frameworks and as standalone rendering engine. However, the standard
+implementation may lack certain features needed by the product into which you
+are integrating Fluid.
+
+To make sure you are able to override key behaviors of Fluid the package
+will delegate much of the resolving, instantiation, argument mapping and
+rendering of ViewHelpers to special classes which can be both manipulated and
+overridden by the user. These special classes and their use cases are:
+
+.. contents::
+
+.. _templateview:
+
+TemplateView
+============
+
+A fairly standard View implementation. The default object expects
+:php:`TemplatePaths` as constructor argument and has a handful of utility methods
+like :php:`$view->assign('variablename', 'value');`. Custom View types can be
+implemented by subclassing the default class - but in order to avoid
+problems, make sure you also call the original class' constructor method.
+
+Creating a custom View allows you to change just a few aspects, mainly about
+composition: which implementations of `TemplatePaths` the View requires, if it
+needs a :ref:`custom ViewHelperResolver `,
+if it must have some default variables, if it should have a default cache, etc.
+
+.. note::
+
+ The special variable `layoutName` is reserved and can be assigned to a
+ template to set its Layout instead of using ``.
+
+.. _templatepaths:
+
+TemplatePaths
+=============
+
+In the default :php:`TemplatePaths` object included with Fluid we provide a
+set of conventions for resolving the template files that go into rendering a
+Fluid template - the templates themselves, plus partials and layouts.
+
+You should use the default :php:`TemplatePaths` object if:
+
+1. You are able to place your template files in folders that match the
+ Fluid conventions, including the convention of subfolders named the
+ same as your controllers.
+2. You are able to provide the template paths that get used as an array with
+ which :php:`TemplatePaths` can be initialized.
+3. Or you are able to individually set each group of paths.
+4. You are able to rely on standard format handling (`format` simply being the
+ file extension of template files).
+
+And you should replace the :php:`TemplatePaths` with your own subclass if:
+
+1. You answered no to any of the above.
+2. You want to be able to deliver template content before parsing, from other
+ sources than files.
+3. You want the resolving of template files for controller actions to happen in
+ a different way.
+4. You want to create other (caching-) identifiers for your partials, layouts
+ and templates than defaults.
+
+Whether you use your own class or the default, the :php:`TemplatePaths` instance
+*must be provided as first argument for the View*.
+
+.. _renderingcontext:
+
+RenderingContext
+================
+
+The rendering context is *the* state object in Fluid's rendering process.
+By default, it contains references to all other objects that are relevant
+in the rendering process, such as the :php:`TemplateParser`, the :php:`TemplateCompiler`,
+a :php:`StandardVariableProvider` or the :php:`TemplatePaths` mentioned above.
+It also contains information about the current template context, somewhat
+confusingly stored in :php:`controllerName` and :php:`controllerAction` due to the
+MVC origins of Fluid.
+
+Since Fluid 2.14, it is also possible to add arbitrary data to the rendering
+context, which obsoletes most cases where you would have to override the
+rendering context implementation in Fluid integrations:
+
+.. code-block:: php
+
+ $myCustomState = new \Vendor\Package\MyClass::class();
+ $view->getRenderingContext()->setAttribute(\Vendor\Package\MyClass::class, $myCustomState);
+
+
+If at all possible, it should be avoided to use a custom `RenderingContext`
+implementation. However, currently it might still be necessary for some cases,
+for example if you want to replace the default implementation of one of the other
+dependencies, such as the :php:`StandardVariableProvider`.
+
+With further refactoring, we try to provide better ways for these use cases in the future.
+
+.. _fluidcache:
+
+FluidCache
+==========
+
+The caching of Fluid templates happens by compiling the templates to PHP files
+which execute much faster than a parsed template ever could. These compiled
+templates can only be stored if a :php:`FluidCacheInterface`-implementing object is
+provided. Fluid provides one such caching implementation: the
+:php:`SimpleFileCache` which just stores compiled PHP code in a designated directory.
+
+Should you need to store the compiled templates in other ways you can implement
+:php:`FluidCacheInterface` in your caching object.
+
+Whether you use your own cache class or the default, the `FluidCache`
+*must be passed as third parameter for the View* or it
+*must be assigned using :php:`$view->getRenderingContext()->setCache($cacheInstance)`
+before calling :php:`$view->render()`*.
+
+.. _viewhelperinvoker:
+
+ViewHelperInvoker
+=================
+
+The :php:`ViewHelperInvoker` is a class dedicated to validating current arguments of
+and if valid, calling the ViewHelper's render method. It is the primary API to
+execute a ViewHelper from within PHP code. The default object
+supports the arguments added via :php:`initializeArguments()` and
+:php:`registerArgument()` on the ViewHelper and provides all additional arguments
+via :php:`handleAdditionalArguments()` to the ViewHelper class. By default, the
+ViewHelper implementations throw an exception, but this handling can be overwritten,
+as demonstrated by :php:`AbstractTagBasedViewHelper`.
+
+You should replace the :php:`ViewHelperInvoker` if:
+
+1. You must support different ways of calling ViewHelpers such as alternative
+ `setArguments` names.
+2. You wish to change the way the invoker uses and stores ViewHelper instances,
+ for example to use an internal cache.
+3. You wish to change the way ViewHelper arguments are validated, for example
+ changing the Exceptions that are thrown.
+4. You wish to perform processing on the output of ViewHelpers, for example to
+ remove XSS attempts according to your own rules.
+
+.. note::
+
+ ViewHelper instance creation and argument retrieval is handled by the
+ :ref:`ViewHelperResolver `.
+
+.. _implementation-view-helper-resolver:
+.. _viewhelperresolver:
+
+ViewHelperResolver
+==================
+
+In Fluid most of your options for extending the language - for example,
+adding new ways to format strings, to make special condition types, custom links
+and such - are implemented as ViewHelpers. These are the special classes that are
+called using for example
+:xml:`{somestring}`.
+
+A ViewHelper is essentially referenced by the namespace and the path to the
+ViewHelper, in this case `f` being the namespace and `format.htmlentities` being
+the path.
+
+The :php:`ViewHelperResolver` is the class responsible for turning these two pieces
+of information into an expected class name and when this class is resolved, to
+retrieve from it the arguments you can use for each ViewHelper.
+
+You should use the default :php:`ViewHelperResolver` if:
+
+1. You can rely on the default way of turning a namespace and path of a
+ ViewHelper into a class name.
+2. You can rely on the default way ViewHelpers return the arguments they
+ support.
+3. You can rely on instantiation of ViewHelpers happening through a simple
+ `new $class()`.
+
+You should replace the :php:`ViewHelperResolver` if:
+
+1. You answered no to any of the above.
+2. You want to make ViewHelper namespaces available in templates without
+ importing.
+3. You want to use the dependency injection of your framework to resolve
+ and instantiate ViewHelper objects.
+4. You want to change which class is resolved from a given namespace and
+ ViewHelper path, for example allowing you to add your own ViewHelpers to the
+ default namespace or replace default ViewHelpers with your own.
+5. You want to change the argument retrieval from ViewHelpers or you want to
+ manipulate the arguments (for example, giving them a default value, making
+ them optional, changing their data type).
+
+The default :php:`ViewHelperResolver` can be replaced on the rendering context by calling
+:php:`$renderingContext->setViewHelperResolver($resolverInstance);`.
+
+.. _templateprocessor:
+
+TemplateProcessor
+=================
+
+While custom :ref:`TemplatePaths ` also allows sources
+of template files to be modified before they are given to the TemplateParser, a
+custom :php:`TemplatePaths` implementation is sometimes overkill - and has the drawback
+of completely overruling the reading of template file sources and making it up to
+the custom class how exactly this processing happens.
+
+In order to allow a more readily accessible and flexible way of pre-processing
+template sources and affect key aspects of the parsing process, a
+:php:`TemplateProcessorInterface` is provided. Implementing this interface and the
+methods it designates allows your class to be passed to the :php:`TemplateView` and
+be triggered every time a template source is parsed, right before parsing
+starts:
+
+.. code-block:: php
+
+ $myTemplateProcessor = new MyTemplateProcessor();
+ $myTemplateProcessor->setDoMyMagicThing(true);
+ $templateView->setTemplateProcessors([
+ $myTemplateProcessor
+ ]);
+
+The registration method requires an array - this is to let you define multiple
+processors without needing to wrap them in a single class as well as reuse
+validation/manipulation across frameworks and only replace the parts that need
+to be replaced.
+
+This makes the method :php:`preProcessSource($templateSource)` be called on this
+class every time the TemplateParser is asked to parse a Fluid template.
+Modifying the source and returning it makes that new template source be used.
+Inside the TemplateProcessor method you have access to the TemplateParser and
+ViewHelperResolver instances which the View uses.
+
+The result is that TemplateProcessor instances are able to, for example:
+
+* Validate template sources and implement reporting/logging of errors in a framework.
+* Fix things like character encoding issues in template sources.
+* Process Fluid code from potentially untrusted sources, for example doing XSS
+ removals before parsing.
+* Extract legacy namespace definitions and assign those to the
+ ViewHelperResolver for active use.
+* Extract legacy escaping instruction headers and assign those to the
+ TemplateParser's Configuration instance.
+* Enable the use of custom template code in file's header, extracted and used
+ by a framework.
+
+Note again: these same behaviors are possible using a custom :php:`TemplatePaths`
+implementation - but even with such a custom implementation this
+TemplateProcessor pattern can still be used to manipulate/validate the sources
+coming from :php:`TemplatePaths`, providing a nice way to decouple paths resolving
+from template source processing.
diff --git a/Documentation/Internals/Index.rst b/Documentation/Internals/Index.rst
new file mode 100644
index 000000000..7738ad6f6
--- /dev/null
+++ b/Documentation/Internals/Index.rst
@@ -0,0 +1,13 @@
+.. include:: /Includes.rst.txt
+
+.. _fluid-internals:
+
+===============
+Fluid Internals
+===============
+
+.. toctree::
+ :maxdepth: 2
+ :titlesonly:
+
+ *
diff --git a/Documentation/Usage/RunningExamples.rst b/Documentation/Internals/RunningExamples.rst
similarity index 100%
rename from Documentation/Usage/RunningExamples.rst
rename to Documentation/Internals/RunningExamples.rst
diff --git a/Documentation/Introduction/Index.rst b/Documentation/Introduction/Index.rst
new file mode 100644
index 000000000..019133b9b
--- /dev/null
+++ b/Documentation/Introduction/Index.rst
@@ -0,0 +1,25 @@
+.. include:: /Includes.rst.txt
+
+.. _introduction:
+
+============
+Introduction
+============
+
+Fluid is a PHP-based templating engine for web projects. In contrast to other
+templating engines, it uses an XML-based syntax in its templates, which allows
+template authors to apply their existing HTML knowledge in Fluid templates.
+
+Fluid originated in the TYPO3 and Neos ecosystem before it was extracted
+from these projects into a separate PHP package. While its main usage nowadays
+is within TYPO3 projects, it can also be used as an independent templating
+language in PHP projects.
+
+In Fluid, all dynamic output is escaped by default, which makes the templating
+engine secure by default. This prevents common XSS (Cross Site Scripting)
+mistakes that can easily happen in HTML templates.
+
+Fluid comes with a range of so-called ViewHelpers that allow various formatting
+and output modification directly in the template. Custom logic can be added
+by providing custom ViewHelper implementations through a straightforward
+PHP API.
diff --git a/Documentation/Syntax/Comments.rst b/Documentation/Syntax/Comments.rst
new file mode 100644
index 000000000..9eb09fb40
--- /dev/null
+++ b/Documentation/Syntax/Comments.rst
@@ -0,0 +1,33 @@
+.. include:: /Includes.rst.txt
+
+:navigation-title: Comments
+
+.. _comments-syntax:
+
+======================
+Fluid Syntax: Comments
+======================
+
+If you want to completely skip parts of your template, you can make use of
+the :ref:` ViewHelper `.
+
+.. versionchanged:: Fluid 4.0
+ The content of the :ref:` ViewHelper ` is removed
+ before parsing. It is no longer necessary to combine it with CDATA tags
+ to disable parsing.
+
+.. code-block:: xml
+
+
+ This will be ignored by the Fluid parser and will not appear in
+ the source code of the rendered template
+
+
+You can also use the :ref:` ViewHelper ` to temporarily comment
+out invalid Fluid syntax while debugging:
+
+.. code-block:: xml
+
+
+
+
diff --git a/Documentation/Syntax/ConditionsBooleans.rst b/Documentation/Syntax/ConditionsBooleans.rst
new file mode 100644
index 000000000..249086424
--- /dev/null
+++ b/Documentation/Syntax/ConditionsBooleans.rst
@@ -0,0 +1,91 @@
+.. include:: /Includes.rst.txt
+
+:navigation-title: Conditions & Booleans
+
+.. _conditions-syntax:
+
+===================================
+Fluid Syntax: Conditions & Booleans
+===================================
+
+.. _boolean-conditions:
+
+Boolean conditions
+==================
+
+Boolean conditions are expressions that evaluate to true or false.
+
+Boolean conditions can be used as ViewHelper arguments, whenever the datatype
+`boolean` is given, e.g. in the `condition` argument of the
+:ref:` ViewHelper `.
+
+1. The expression can be a variable which is evaluated as follows:
+
+ * number: evaluates to `true`, if is not `0`.
+ * array: evaluates to `true` if it contains at least one element
+
+2. The expression can be a statement consisting of: `term1 operator term2`, for
+ example `{variable} > 3`
+
+ * The operator can be one of `>`, `>=`, `<`, `<=`,
+ `==`, `===`, `!=`, `!==` or `%`,
+
+3. The previous expressions can be combined with `||` (or) or `&&` (and).
+
+
+Examples:
+
+.. code-block:: xml
+
+
+ ...
+
+
+
+
+ ...
+
+
+ ...
+
+
+
+
+ ...
+
+
+
+Example using the inline notation:
+
+.. code-block:: xml
+
+
+ ...
+
+
+.. _boolean-literals:
+
+Boolean literals
+================
+
+.. versionadded:: Fluid 4.0
+ The boolean literals `{true}` and `{false}` have been introduced.
+
+You can use the boolean literals `{true}` and `{false}` in ViewHelper calls. This works
+both in tag and inline syntax:
+
+.. code-block:: xml
+
+
+
+ {f:render(section: 'MySection', optional: true)}
+
+If a ViewHelper argument is defined as `boolean`, it is also possible to provide
+values of different types, which will then be converted to boolean implicitly:
+
+.. code-block:: xml
+
+
+
+This can be used to remain compatible to Fluid 2, which didn't support boolean literals
+in all cases.
diff --git a/Documentation/Syntax/Escaping.rst b/Documentation/Syntax/Escaping.rst
new file mode 100644
index 000000000..2b9f73d02
--- /dev/null
+++ b/Documentation/Syntax/Escaping.rst
@@ -0,0 +1,144 @@
+.. include:: /Includes.rst.txt
+
+:navigation-title: Escaping
+
+.. _escaping-syntax:
+
+======================
+Fluid Syntax: Escaping
+======================
+
+.. _escaping-behavior:
+
+Escaping behavior in inline syntax
+==================================
+
+At a certain nesting level, `'` needs to be escaped with a backslash:
+
+.. code-block:: xml
+
+
+
+
+
+While escaping cannot be avoided in all cases, alternatives should always be
+preferred to improve the readability of templates. Depending on the use cases, there
+are different approaches to achieve this.
+
+
+Passing variables to inline ViewHelpers
+---------------------------------------
+
+If only a variable is passed as a ViewHelper argument, the single quotes and curly braces
+can be omitted:
+
+.. code-block:: xml
+
+ {f:format.case(mode: 'upper', value: myVariable)}
+
+
+Using ViewHelper chaining if possible
+-------------------------------------
+
+A lot of ViewHelpers that perform changes on a single value also accept that value as
+child value. This allows a much cleaner syntax if you combine multiple ViewHelpers for
+one value:
+
+.. code-block:: xml
+
+ {myVariable -> f:format.case(mode: 'upper') -> f:format.trim()}
+
+.. _escaping-workarounds:
+
+Workarounds for syntax collision with JS and CSS
+================================================
+
+While it is generally advisable to avoid inline JavaScript and CSS code within
+Fluid templates, sometimes it might be unavoidable. This might lead to collisions
+between Fluid's inline or variable syntax and the curly braces used in JavaScript
+and CSS.
+
+Currently, there is no clean way to solve this due to limitations of Fluid's parser.
+This would need a bigger rewrite, which is not yet feasible due to other more pressing
+issues. However, there are workarounds that might be applicable in your use case.
+
+f:format.json ViewHelper
+------------------------
+
+If your goal is to create JSON in your template, you can create an object in Fluid
+and then use the :ref:` ViewHelper `
+to generate valid JSON:
+
+.. code-block:: xml
+
+
+
+
+This can also be used directly in JavaScript code:
+
+.. code-block:: xml
+
+