Skip to content

Commit c5a186b

Browse files
authored
[TASK] Update Symfony expression language (#6044)
* [TASK] Update Symfony expression language * Move codesnippets to separate files * Apply CGL, best practices, resolve imports and namespaces * Unify the example file positions * Add anchors where missing * correct indentation Releases: main, 13.4 * [TASK] Update Symfony expression language * Move codesnippets to separate files * Apply CGL, best practices, resolve imports and namespaces * Unify the example file positions * Add anchors where missing * correct indentation Releases: main, 13.4
1 parent 0d1182c commit c5a186b

File tree

7 files changed

+154
-127
lines changed

7 files changed

+154
-127
lines changed
Lines changed: 45 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,31 @@
1-
.. include:: /Includes.rst.txt
2-
.. index:: Symfony expression language
3-
.. _symfony-expression-language:
1+
:navigation-title: Symfony expression language
42

5-
===========================
6-
Symfony expression language
7-
===========================
3+
.. include:: /Includes.rst.txt
4+
.. index:: Symfony expression language
5+
.. _symfony-expression-language:
6+
7+
=================================
8+
Symfony expression language (SEL)
9+
=================================
810

911
Symfony expression language (SEL) is used by TYPO3 in a couple of places. The most
1012
well-known ones are :ref:`TypoScript conditions <t3tsref:typoscript-syntax-global-condition>`.
1113
The :ref:`TypoScript <t3tsref:conditions>` and :ref:`TSconfig <t3tsref:tsconfig-conditions>` references list
1214
available variables and functions of these contexts. But the TYPO3 Core API allows
1315
enriching expressions with additional functionality, which is what this chapter is about.
1416

17+
.. contents:: Table of contents
18+
19+
.. _symfony-expression-language-api:
1520

16-
Main API
17-
========
21+
Main API of the Symfony expression language
22+
===========================================
1823

1924
The TYPO3 Core API provides a relatively slim API in front of the Symfony expression
2025
language: Symfony expressions are used in different contexts (TypoScript conditions,
2126
the EXT:form framework, maybe more).
2227

23-
The class :php:`TYPO3\CMS\Core\ExpressionLanguage\Resolver` is used to prepare the
28+
The class :php:`\TYPO3\CMS\Core\ExpressionLanguage\Resolver` is used to prepare the
2429
expression language processor based on a given context (identified by a string,
2530
for example "typoscript"), and loads registered available variables and functions
2631
for this context.
@@ -32,58 +37,39 @@ Evaluation of single expressions is then initiated calling
3237
:php:`$myResolver->evaluate()`. While TypoScript casts the return value to :php:`bool`,
3338
Symfony expression evaluation can potentially return :php:`mixed`.
3439

40+
.. index::
41+
pair: Symfony expression language; Custom provider
42+
pair: Symfony expression language; TypoScript
43+
.. _sel-within-typoscript-conditions:
44+
.. _sel-ts-registering-new-provider-within-extension:
3545

36-
.. index::
37-
pair: Symfony expression language; Custom provider
38-
pair: Symfony expression language; TypoScript
39-
.. _sel-within-typoscript-conditions:
40-
.. _sel-ts-registering-new-provider-within-extension:
41-
42-
Registering new provider
43-
========================
46+
Registering a custom Symfony expression provider
47+
================================================
4448

4549
There has to be a provider, no matter whether variables or functions will be provided.
4650
A provider is registered in the extension file :file:`Configuration/ExpressionLanguage.php`.
47-
This will register the defined :php:`CustomTypoScriptConditionProvider` PHP class as
48-
provider within the context `typoscript`.
49-
50-
.. code-block:: php
51-
:caption: EXT:some_extension/Configuration/ExpressionLanguage.php
52-
53-
return [
54-
'typoscript' => [
55-
\MyVendor\SomeExtension\ExpressionLanguage\CustomTypoScriptConditionProvider::class,
56-
]
57-
];
58-
5951

60-
.. _sel-ts-implement-provider-within-extension:
61-
62-
Implementing a provider
63-
=======================
64-
65-
The provider is a PHP class like :file:`/Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php`,
66-
depending on the formerly registered PHP class name:
52+
The following example registers the defined PHP class as
53+
provider within the context `typoscript`.
6754

68-
.. code-block:: php
69-
:caption: EXT:some_extension/Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php
55+
.. literalinclude:: _codesnippets/_ExpressionLanguage.php
56+
:caption: EXT:my_extension/Configuration/ExpressionLanguage.php
7057

71-
namespace MyVendor\SomeExtension\ExpressionLanguage;
58+
.. _sel-ts-implement-provider-within-extension:
7259

73-
use TYPO3\CMS\Core\ExpressionLanguage\AbstractProvider;
60+
Implementing a custom Symfony expression provider
61+
=================================================
7462

75-
class CustomTypoScriptConditionProvider extends AbstractProvider
76-
{
77-
public function __construct()
78-
{
79-
}
80-
}
63+
The provider is a PHP class like the following, depending on the formerly
64+
registered PHP class name:
8165

66+
.. literalinclude:: _codesnippets/_CustomTypoScriptConditionProviderEmpty.php
67+
:caption: EXT:my_extension/Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php
8268

83-
.. _sel-ts-additional-variables:
69+
.. _sel-ts-additional-variables:
8470

8571
Additional variables
86-
====================
72+
--------------------
8773

8874
Additional variables can be provided by the registered provider class.
8975
In practice, adding additional variables is used rather seldom: To
@@ -92,95 +78,27 @@ a good idea. Instead, consuming code should provide available variables
9278
by handing them over to the :php:`Resolver` constructor already.
9379
The example below adds a new variable `variableA` with value `valueB`:
9480

95-
.. code-block:: php
96-
:caption: EXT:some_extension/Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php
81+
.. literalinclude:: _codesnippets/_CustomTypoScriptConditionProviderA.php
82+
:caption: EXT:my_extension/Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php
9783

98-
class CustomTypoScriptConditionProvider extends AbstractProvider
99-
{
100-
public function __construct()
101-
{
102-
$this->expressionLanguageVariables = [
103-
'variableA' => 'valueB',
104-
];
105-
}
106-
}
107-
108-
.. _sel-ts-additional-functions:
84+
.. _sel-ts-additional-functions:
10985

11086
Additional functions
111-
====================
87+
--------------------
11288

11389
Additional functions can be provided with another class that has to be
11490
registered in the provider:
11591

116-
.. code-block:: php
117-
:caption: EXT:some_extension/Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php
118-
119-
class CustomTypoScriptConditionProvider extends AbstractProvider
120-
{
121-
public function __construct()
122-
{
123-
$this->expressionLanguageProviders = [
124-
CustomConditionFunctionsProvider::class,
125-
];
126-
}
127-
}
92+
.. literalinclude:: _codesnippets/_CustomConditionFunctionsProvider.php
93+
:caption: EXT:my_extension/Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php
12894

12995
The (artificial) implementation below calls some external URL based on given variables:
13096

131-
.. code-block:: php
132-
:caption: EXT:some_extension/Classes/ExpressionLanguage/CustomConditionFunctionsProvider.php
133-
134-
namespace Vendor\SomeExtension\TypoScript;
135-
136-
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
137-
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
138-
139-
class CustomConditionFunctionsProvider implements ExpressionFunctionProviderInterface
140-
{
141-
public function getFunctions()
142-
{
143-
return [
144-
$this->getWebserviceFunction(),
145-
];
146-
}
147-
148-
protected function getWebserviceFunction(): ExpressionFunction
149-
{
150-
return new ExpressionFunction(
151-
'webservice',
152-
static fn () => null, // Not implemented, we only use the evaluator
153-
static function ($arguments, $endpoint, $uid) {
154-
return GeneralUtility::getUrl(
155-
'https://example.org/endpoint/'
156-
. $endpoint
157-
. '/'
158-
. $uid
159-
);
160-
}
161-
);
162-
}
163-
}
97+
.. literalinclude:: _codesnippets/_CustomConditionFunctionsProvider.php
98+
:caption: EXT:my_extension/Classes/ExpressionLanguage/CustomConditionFunctionsProvider.php
99+
164100

165101
A usage example in TypoScript could be this:
166102

167-
.. code-block:: typoscript
168-
:caption: EXT:some_extension/Configuration/TypoScript/setup.typoscript
169-
170-
[webservice('pages', 10)]
171-
page.10 >
172-
page.10 = TEXT
173-
page.10.value = Matched
174-
[GLOBAL]
175-
176-
# Or compare the result of the function to a string
177-
[webservice('pages', 10) === 'Expected page title']
178-
page.10 >
179-
page.10 = TEXT
180-
page.10.value = Matched
181-
[GLOBAL]
182-
183-
# if there are no parameters, your own conditions still need brackets
184-
[conditionWithoutParameters()]
185-
# do something
186-
[GLOBAL]
103+
.. literalinclude:: _codesnippets/_conditions.typoscript
104+
:caption: EXT:my_extension/Configuration/TypoScript/setup.typoscript
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MyVendor\MyExtension\TypoScript;
6+
7+
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
8+
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
9+
use TYPO3\CMS\Core\Utility\GeneralUtility;
10+
11+
class CustomConditionFunctionsProvider implements ExpressionFunctionProviderInterface
12+
{
13+
public function getFunctions(): array
14+
{
15+
return [
16+
$this->getWebserviceFunction(),
17+
];
18+
}
19+
20+
protected function getWebserviceFunction(): ExpressionFunction
21+
{
22+
return new ExpressionFunction(
23+
'webservice',
24+
static fn() => null, // Not implemented, we only use the evaluator
25+
static function ($arguments, $endpoint, $uid) {
26+
return GeneralUtility::getUrl(
27+
'https://example.org/endpoint/'
28+
. $endpoint
29+
. '/'
30+
. $uid,
31+
);
32+
},
33+
);
34+
}
35+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MyVendor\MyExtension\TypoScript;
6+
7+
use TYPO3\CMS\Core\ExpressionLanguage\AbstractProvider;
8+
9+
class CustomTypoScriptConditionProvider extends AbstractProvider
10+
{
11+
public function __construct()
12+
{
13+
$this->expressionLanguageProviders = [
14+
CustomConditionFunctionsProvider::class,
15+
];
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MyVendor\MyExtension\TypoScript;
6+
7+
use TYPO3\CMS\Core\ExpressionLanguage\AbstractProvider;
8+
9+
class CustomTypoScriptConditionProvider extends AbstractProvider
10+
{
11+
public function __construct()
12+
{
13+
$this->expressionLanguageVariables = [
14+
'variableA' => 'valueB',
15+
];
16+
}
17+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MyVendor\MyExtension\TypoScript;
6+
7+
use TYPO3\CMS\Core\ExpressionLanguage\AbstractProvider;
8+
9+
class CustomTypoScriptConditionProvider extends AbstractProvider
10+
{
11+
public function __construct() {}
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use MyVendor\MyExtension\TypoScript\CustomTypoScriptConditionProvider;
6+
7+
return [
8+
'typoscript' => [
9+
CustomTypoScriptConditionProvider::class,
10+
],
11+
];
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[webservice('pages', 10)]
2+
page.10 >
3+
page.10 = TEXT
4+
page.10.value = Matched
5+
[GLOBAL]
6+
7+
# Or compare the result of the function to a string
8+
[webservice('pages', 10) === 'Expected page title']
9+
page.10 >
10+
page.10 = TEXT
11+
page.10.value = Matched
12+
[GLOBAL]
13+
14+
# if there are no parameters, your own conditions still need brackets
15+
[conditionWithoutParameters()]
16+
# do something
17+
[GLOBAL]

0 commit comments

Comments
 (0)