---
title: "Symfony expression language"
manual: "TYPO3 Explained"
version: "12.4"
permalink: "https://docs.typo3.org/permalink/t3coreapi:symfony-expression-language@12.4"
source: "ApiOverview/SymfonyExpressionLanguage/Index.rst"
rendered: "2026-10-21T15:29:37+00:00"
---

> [!WARNING]
> **Attention**
>
> TYPO3 v12 has reached end-of-life as of April 30th 2026 and
> is no longer being maintained. Use the version switcher on the top
> left of this page to select documentation for a supported version of TYPO3.
>
> Need more time before upgrading?
> You can purchase Extended Long Term Support (ELTS) for TYPO3 v12 here:
> [TYPO3 ELTS](https://typo3.com/services/extended-support-elts).

# Symfony expression language {#symfony-expression-language}

Symfony expression language (SEL) is used by TYPO3 in a couple of places. The most
well-known ones are [TypoScript conditions](https://docs.typo3.org/m/typo3/reference-typoscript/12.4/en-us/Syntax/Conditions/Index.html#typoscript-syntax-global-condition).
The [TypoScript](https://docs.typo3.org/m/typo3/reference-typoscript/12.4/en-us/Conditions/Index.html#conditions) and [TSconfig](https://docs.typo3.org/m/typo3/reference-typoscript/12.4/en-us/UsingSettingTSconfig/Conditions.html#tsconfig-conditions) references list
available variables and functions of these contexts. But the TYPO3 Core API allows
enriching expressions with additional functionality, which is what this chapter is about.

## Main API {#main-api}

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

The class `\TYPO3\CMS\Core\ExpressionLanguage\Resolver` is used to prepare the
expression language processor based on a given context (identified by a string,
for example "typoscript"), and loads registered available variables and functions
for this context.

The [System > Configuration](https://docs.typo3.org/c/typo3/cms-lowlevel/12.4/en-us/BackendModules/Configuration.html#module-configuration) module
provides a list of all registered Symfony expression language providers.

Evaluation of single expressions is then initiated calling
`$myResolver->evaluate()`. While TypoScript casts the return value to `bool`,
Symfony expression evaluation can potentially return `mixed`.

<a id="sel-within-typoscript-conditions"></a>

## Registering new provider {#sel-ts-registering-new-provider-within-extension}

There has to be a provider, no matter whether variables or functions will be provided.
A provider is registered in the extension file `Configuration/ExpressionLanguage.php`.
This will register the defined `CustomTypoScriptConditionProvider` PHP class as
provider within the context `typoscript`.

**EXT:some_extension/Configuration/ExpressionLanguage.php**

```php
return [
    'typoscript' => [
        \MyVendor\SomeExtension\ExpressionLanguage\CustomTypoScriptConditionProvider::class,
    ]
];
```

## Implementing a provider {#sel-ts-implement-provider-within-extension}

The provider is a PHP class like `/Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php`,
depending on the formerly registered PHP class name:

**EXT:some_extension/Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php**

```php
namespace MyVendor\SomeExtension\ExpressionLanguage;

use TYPO3\CMS\Core\ExpressionLanguage\AbstractProvider;

class CustomTypoScriptConditionProvider extends AbstractProvider
{
    public function __construct()
    {
    }
}
```

## Additional variables {#sel-ts-additional-variables}

Additional variables can be provided by the registered provider class.
In practice, adding additional variables is used rather seldom: To
access state, they tend to use `$GLOBALS`, which in general is not
a good idea. Instead, consuming code should provide available variables
by handing them over to the `Resolver` constructor already.
The example below adds a new variable `variableA` with value `valueB`:

**EXT:some_extension/Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php**

```php
class CustomTypoScriptConditionProvider extends AbstractProvider
{
    public function __construct()
    {
        $this->expressionLanguageVariables = [
            'variableA' => 'valueB',
        ];
    }
}
```

## Additional functions {#sel-ts-additional-functions}

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

**EXT:some_extension/Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php**

```php
class CustomTypoScriptConditionProvider extends AbstractProvider
{
    public function __construct()
    {
        $this->expressionLanguageProviders = [
            CustomConditionFunctionsProvider::class,
        ];
    }
}
```

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

**EXT:some_extension/Classes/ExpressionLanguage/CustomConditionFunctionsProvider.php**

```php
namespace Vendor\SomeExtension\TypoScript;

use Symfony\Component\ExpressionLanguage\ExpressionFunction;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;

class CustomConditionFunctionsProvider implements ExpressionFunctionProviderInterface
{
    public function getFunctions()
    {
        return [
            $this->getWebserviceFunction(),
        ];
    }

    protected function getWebserviceFunction(): ExpressionFunction
    {
        return new ExpressionFunction(
            'webservice',
            static fn () => null, // Not implemented, we only use the evaluator
            static function ($arguments, $endpoint, $uid) {
                return GeneralUtility::getUrl(
                    'https://example.org/endpoint/'
                    . $endpoint
                    . '/'
                    . $uid
                );
            }
        );
    }
}
```

A usage example in TypoScript could be this:

**EXT:some_extension/Configuration/TypoScript/setup.typoscript**

```typoscript
[webservice('pages', 10)]
    page.10 >
    page.10 = TEXT
    page.10.value = Matched
[GLOBAL]

# Or compare the result of the function to a string
[webservice('pages', 10) === 'Expected page title']
    page.10 >
    page.10 = TEXT
    page.10.value = Matched
[GLOBAL]

# if there are no parameters, your own conditions still need brackets
[conditionWithoutParameters()]
    # do something
[GLOBAL]
```
