1<?php
2
3declare(strict_types=1);
4
5/*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18namespace TYPO3\CMS\Core\ExpressionLanguage;
19
20use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
21use TYPO3\CMS\Core\Utility\GeneralUtility;
22
23/**
24 * Class Resolver
25 */
26class Resolver
27{
28    /**
29     * @var ProviderInterface
30     */
31    protected $provider;
32
33    /**
34     * @var \Symfony\Component\ExpressionLanguage\ExpressionLanguage
35     */
36    protected $expressionLanguage;
37
38    /**
39     * @var array
40     */
41    public $expressionLanguageVariables = [];
42
43    /**
44     * @param string $context
45     * @param array $variables
46     */
47    public function __construct(string $context, array $variables)
48    {
49        $functionProviderInstances = [];
50        $providers = GeneralUtility::makeInstance(ProviderConfigurationLoader::class)->getExpressionLanguageProviders()[$context] ?? [];
51        // Always add default provider
52        array_unshift($providers, DefaultProvider::class);
53        $providers = array_unique($providers);
54        $functionProviders = [];
55        $generalVariables = [];
56        foreach ($providers as $provider) {
57            /** @var ProviderInterface $providerInstance */
58            $providerInstance = GeneralUtility::makeInstance($provider);
59            $functionProviders[] = $providerInstance->getExpressionLanguageProviders();
60            $generalVariables[] = $providerInstance->getExpressionLanguageVariables();
61        }
62        $functionProviders = array_merge(...$functionProviders);
63        $generalVariables = array_replace_recursive(...$generalVariables);
64        $this->expressionLanguageVariables = array_replace_recursive($generalVariables, $variables);
65        foreach ($functionProviders as $functionProvider) {
66            $functionProviderInstances[] = GeneralUtility::makeInstance($functionProvider);
67        }
68        $this->expressionLanguage = new ExpressionLanguage(null, $functionProviderInstances);
69    }
70
71    /**
72     * Evaluate an expression.
73     *
74     * @param string $condition The expression to parse
75     * @return bool
76     */
77    public function evaluate(string $condition): bool
78    {
79        // The TypoScript [ELSE] condition is not known by the Symfony Expression Language
80        // and must not be evaluated. If/else logic is handled in TypoScriptParser.
81        if (strtoupper($condition) === 'ELSE') {
82            return false;
83        }
84
85        return (bool)$this->expressionLanguage->evaluate($condition, $this->expressionLanguageVariables);
86    }
87
88    /**
89     * Compiles an expression source code.
90     *
91     * @param string $condition The expression to compile
92     * @return string
93     */
94    public function compile(string $condition): string
95    {
96        return (string)$this->expressionLanguage->compile($condition, array_keys($this->expressionLanguageVariables));
97    }
98}
99