---
title: "Symfony expression language (SEL)"
manual: "TYPO3 Explained"
version: "main"
permalink: "https://docs.typo3.org/permalink/t3coreapi:symfony-expression-language@main"
source: "ApiOverview/SymfonyExpressionLanguage/Index.rst"
rendered: "2026-09-24T12:36:55+00:00"
---

# Symfony expression language (SEL) {#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/main/en-us/Syntax/Conditions/Index.html#typoscript-syntax-global-condition).
The [TypoScript](https://docs.typo3.org/m/typo3/reference-typoscript/main/en-us/Conditions/Index.html#conditions) and [TSconfig](https://docs.typo3.org/m/typo3/reference-typoscript/main/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.

**Table of contents**

-   [Main API of the Symfony expression language](https://docs.typo3.org/permalink/t3coreapi:main-api-of-the-symfony-expression-language@main)
-   [Registering a custom Symfony expression provider](https://docs.typo3.org/permalink/t3coreapi:registering-a-custom-symfony-expression-provider@main)
-   [Implementing a custom Symfony expression provider](https://docs.typo3.org/permalink/t3coreapi:implementing-a-custom-symfony-expression-provider@main)

## Main API of the Symfony expression language {#symfony-expression-language-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/main/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`.

## Registering a custom Symfony expression 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`.

The following example registers the defined PHP class as
provider within the context `typoscript`.

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

```php
<?php

declare(strict_types=1);

use MyVendor\MyExtension\TypoScript\CustomTypoScriptConditionProvider;

return [
  'typoscript' => [
    CustomTypoScriptConditionProvider::class,
  ],
];

```

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

The provider is a PHP class like the following, depending on the formerly
registered PHP class name:

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

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\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:my_extension/Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\ExpressionLanguage;

use TYPO3\CMS\Core\ExpressionLanguage\AbstractProvider;

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:my_extension/Classes/ExpressionLanguage/CustomTypoScriptConditionProvider.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\ExpressionLanguage;

use TYPO3\CMS\Core\ExpressionLanguage\AbstractProvider;

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

```

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

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

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\ExpressionLanguage;

use Symfony\Component\ExpressionLanguage\ExpressionFunction;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class CustomConditionFunctionsProvider implements ExpressionFunctionProviderInterface
{
  public function getFunctions(): array
  {
    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:my_extension/Configuration/Sets/MyExtension/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]

```
