[TASK] Add a function to safely traverse arrays in TS conditions 08/61708/4
authorMarkus Klein <markus.klein@typo3.org>
Sat, 14 Sep 2019 21:40:56 +0000 (23:40 +0200)
committerDaniel Goerz <daniel.goerz@posteo.de>
Sun, 12 Jan 2020 18:22:28 +0000 (19:22 +0100)
Example:
[traverse(request.getQueryParams(), 'tx_news_pi/news') > 0]

Resolves: #89176
Releases: master, 9.5
Change-Id: Ic589f68382951c203afa5ad6a7bc16fbddbc20b2
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/61708
Tested-by: Susanne Moog <look@susi.dev>
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Daniel Goerz <daniel.goerz@posteo.de>
Reviewed-by: Susanne Moog <look@susi.dev>
Reviewed-by: Daniel Goerz <daniel.goerz@posteo.de>
typo3/sysext/core/Classes/ExpressionLanguage/FunctionsProvider/DefaultFunctionsProvider.php
typo3/sysext/core/Documentation/Changelog/9.4/Feature-85829-ImplementSymfonyExpressionLanguageForTypoScriptConditions.rst

index a20ee9e..7664643 100644 (file)
@@ -19,6 +19,8 @@ use Symfony\Component\ExpressionLanguage\ExpressionFunction;
 use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
 use TYPO3\CMS\Core\Configuration\Features;
 use TYPO3\CMS\Core\Context\Context;
+use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\StringUtility;
 use TYPO3\CMS\Core\Utility\VersionNumberUtility;
@@ -41,6 +43,7 @@ class DefaultFunctionsProvider implements ExpressionFunctionProviderInterface
             $this->getEnvFunction(),
             $this->getDateFunction(),
             $this->getFeatureToggleFunction(),
+            $this->getTraverseArrayFunction(),
         ];
     }
 
@@ -108,4 +111,20 @@ class DefaultFunctionsProvider implements ExpressionFunctionProviderInterface
                 ->isFeatureEnabled($featureName);
         });
     }
+
+    public function getTraverseArrayFunction(): ExpressionFunction
+    {
+        return new ExpressionFunction('traverse', function () {
+            // Not implemented, we only use the evaluator
+        }, function ($arguments, $array, $path) {
+            if (!is_array($array) || !is_string($path) || $path === '') {
+                return '';
+            }
+            try {
+                return ArrayUtility::getValueByPath($array, $path);
+            } catch (MissingArrayPathException $e) {
+                return '';
+            }
+        });
+    }
 }
index 0e8c0a8..93dfaf3 100644 (file)
@@ -51,6 +51,10 @@ Here are some examples to understand the power of the expression language:
    # This condition matches if current request is **not** https
    [END]
 
+   [traverse(request.getQueryParams(), 'tx_news_pi/news') > 0]
+   # This condition matches if current query parameters have tx_news_pi[news] set to a value greater than zero
+   [END]
+
 
 Variables
 ---------
@@ -117,56 +121,62 @@ Functions
 Functions take over the logic of the old conditions which do more than a simple comparison check.
 The following functions are available in **any** context:
 
-+------------------------+-----------------------+---------------------------------------------------------+
-| Function               | Parameter             | Description                                             |
-+========================+=======================+=========================================================+
-| request                | Custom Object         | This object provides 4 methods                          |
-|                        |                       |                                                         |
-| .getQueryParams()      |                       | `[request.getQueryParams()['foo'] == 1]`                |
-|                        |                       |                                                         |
-| .getParsedBody()       |                       | `[request.getParsedBody()['foo'] == 1]`                 |
-|                        |                       |                                                         |
-| .getHeaders()          |                       | `[request.getHeaders()['Accept'] == 'json']`            |
-|                        |                       |                                                         |
-| .getCookieParams()     |                       | `[request.getCookieParams()['foo'] == 1]`               |
-|                        |                       |                                                         |
-| .getNormalizedParams() |                       | `[request.getNormalizedParams().isHttps()]`             |
-+------------------------+-----------------------+---------------------------------------------------------+
-| date                   | String                | Get current date in given format.                       |
-|                        |                       | Examples:                                               |
-|                        |                       |                                                         |
-|                        |                       | * true if day of current month is 7: `[date("j") == 7]` |
-|                        |                       | * true if day of current week is 7: `[date("w") == 7]`  |
-|                        |                       | * true if day of current year is 7: `[date("z") == 7]`  |
-|                        |                       | * true if current hour is 7: `[date("G") == 7]`         |
-+------------------------+-----------------------+---------------------------------------------------------+
-| like                   | String                | This function has two parameters:                       |
-|                        |                       | the first parameter is the string to search in          |
-|                        |                       | the second parameter is the search string               |
-|                        |                       | Example: `[like("foobarbaz", "*bar*")]`                 |
-+------------------------+-----------------------+---------------------------------------------------------+
-| ip                     | String                | Value or Constraint, Wildcard or RegExp possible        |
-|                        |                       | special value: devIP (match the devIPMask)              |
-+------------------------+-----------------------+---------------------------------------------------------+
-| compatVersion          | String                | version constraint, e.g. `9.4` or `9.4.0`               |
-+------------------------+-----------------------+---------------------------------------------------------+
-| loginUser              | String                | value or constraint, wildcard or RegExp possible        |
-|                        |                       | Examples:                                               |
-|                        |                       |                                                         |
-|                        |                       | * `[loginUser('*')]` // any logged in user              |
-|                        |                       | * `[loginUser(1)]` // user with uid 1                   |
-|                        |                       | * `[loginUser('1,3,5')]` // user 1, 3 or 5              |
-|                        |                       | * `[loginUser('*') == false]` // not logged in          |
-+------------------------+-----------------------+---------------------------------------------------------+
-| getTSFE                | Object                | TypoScriptFrontendController (`$GLOBALS['TSFE']`)       |
-|                        |                       |                                                         |
-|                        |                       | Conditions based on `getTSFE()` used in a context where |
-|                        |                       | TSFE is not available will always evaluate to false.    |
-+------------------------+-----------------------+---------------------------------------------------------+
-| getenv                 | String                | PHP function: :php:`getenv()`                           |
-+------------------------+-----------------------+---------------------------------------------------------+
-| usergroup              | String                | value or constraint, wildcard or RegExp possible        |
-+------------------------+-----------------------+---------------------------------------------------------+
++------------------------+-----------------------+-------------------------------------------------------------------------+
+| Function               | Parameter             | Description                                                             |
++========================+=======================+=========================================================================+
+| request                | Custom Object         | This object provides 4 methods                                          |
+|                        |                       |                                                                         |
+| .getQueryParams()      |                       | `[request.getQueryParams()['foo'] == 1]`                                |
+|                        |                       |                                                                         |
+| .getParsedBody()       |                       | `[request.getParsedBody()['foo'] == 1]`                                 |
+|                        |                       |                                                                         |
+| .getHeaders()          |                       | `[request.getHeaders()['Accept'] == 'json']`                            |
+|                        |                       |                                                                         |
+| .getCookieParams()     |                       | `[request.getCookieParams()['foo'] == 1]`                               |
+|                        |                       |                                                                         |
+| .getNormalizedParams() |                       | `[request.getNormalizedParams().isHttps()]`                             |
++------------------------+-----------------------+-------------------------------------------------------------------------+
+| date                   | String                | Get current date in given format.                                       |
+|                        |                       | Examples:                                                               |
+|                        |                       |                                                                         |
+|                        |                       | * true if day of current month is 7: `[date("j") == 7]`                 |
+|                        |                       | * true if day of current week is 7: `[date("w") == 7]`                  |
+|                        |                       | * true if day of current year is 7: `[date("z") == 7]`                  |
+|                        |                       | * true if current hour is 7: `[date("G") == 7]`                         |
++------------------------+-----------------------+-------------------------------------------------------------------------+
+| like                   | String                | This function has two parameters:                                       |
+|                        |                       | the first parameter is the string to search in                          |
+|                        |                       | the second parameter is the search string                               |
+|                        |                       | Example: `[like("foobarbaz", "*bar*")]`                                 |
++------------------------+-----------------------+-------------------------------------------------------------------------+
+| traverse               | Array and String      | This function has two parameters:                                       |
+|                        |                       | - first parameter is the array to traverse                              |
+|                        |                       | - second parameter is the path to traverse                              |
+|                        |                       |   Syntax: <array-key>[/<array-key>]*                                    |
+|                        |                       | Example: `[traverse(request.getQueryParams(), 'tx_news_pi/news') > 0]`  |
++------------------------+-----------------------+-------------------------------------------------------------------------+
+| ip                     | String                | Value or Constraint, Wildcard or RegExp possible                        |
+|                        |                       | special value: devIP (match the devIPMask)                              |
++------------------------+-----------------------+-------------------------------------------------------------------------+
+| compatVersion          | String                | version constraint, e.g. `9.4` or `9.4.0`                               |
++------------------------+-----------------------+-------------------------------------------------------------------------+
+| loginUser              | String                | value or constraint, wildcard or RegExp possible                        |
+|                        |                       | Examples:                                                               |
+|                        |                       |                                                                         |
+|                        |                       | * `[loginUser('*')]` // any logged in user                              |
+|                        |                       | * `[loginUser(1)]` // user with uid 1                                   |
+|                        |                       | * `[loginUser('1,3,5')]` // user 1, 3 or 5                              |
+|                        |                       | * `[loginUser('*') == false]` // not logged in                          |
++------------------------+-----------------------+-------------------------------------------------------------------------+
+| getTSFE                | Object                | TypoScriptFrontendController (`$GLOBALS['TSFE']`)                       |
+|                        |                       |                                                                         |
+|                        |                       | Conditions based on `getTSFE()` used in a context where                 |
+|                        |                       | TSFE is not available will always evaluate to false.                    |
++------------------------+-----------------------+-------------------------------------------------------------------------+
+| getenv                 | String                | PHP function: :php:`getenv()`                                           |
++------------------------+-----------------------+-------------------------------------------------------------------------+
+| usergroup              | String                | value or constraint, wildcard or RegExp possible                        |
++------------------------+-----------------------+-------------------------------------------------------------------------+
 
 
 The following functions are only available in **frontend** context: