Feature: #104482 - Add if() support to ExpressionBuilder

See forge#104482

Description

The TYPO3 \TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder provides a new method to phrase "if-then-else" expressions. Those are translated into IF or CASE statements depending on the used database engine.

ExpressionBuilder::if()

Creates an IF-THEN-ELSE expression.

Method signature
/**
 * Creates IF-THEN-ELSE expression construct compatible with all supported database vendors.
 * No automatic quoting or escaping is done, which allows to build up nested expression statements.
 *
 * **Example:**
 * ```
 * $queryBuilder
 *   ->selectLiteral(
 *     $queryBuilder->expr()->if(
 *       $queryBuilder->expr()->eq('hidden', $queryBuilder->createNamedParameter(0, Connection::PARAM_INT)),
 *       $queryBuilder->quote('page-is-visible'),
 *       $queryBuilder->quote('page-is-not-visible'),
 *       'result_field_name'
 *     ),
 *   )
 *   ->from('pages');
 * ```
 *
 * **Result with MySQL:**
 * ```
 * SELECT (IF(`hidden` = 0, 'page-is-visible', 'page-is-not-visible')) AS `result_field_name` FROM `pages`
 * ```
 */
public function if(
    CompositeExpression|\Doctrine\DBAL\Query\Expression\CompositeExpression|\Stringable|string $condition,
    \Stringable|string $truePart,
    \Stringable|string $falsePart,
    \Stringable|string|null $as = null
): string {
    $platform = $this->connection->getDatabasePlatform();
    $pattern = match (true) {
        $platform instanceof DoctrineSQLitePlatform => 'IIF(%s, %s, %s)',
        $platform instanceof DoctrinePostgreSQLPlatform => 'CASE WHEN %s THEN %s ELSE %s END',
        $platform instanceof DoctrineMariaDBPlatform,
        $platform instanceof DoctrineMySQLPlatform => 'IF(%s, %s, %s)',
        default => throw new \RuntimeException(
            sprintf('Platform "%s" not supported for "%s"', $platform::class, __METHOD__),
            1721806463
        )
    };
    $expression = sprintf($pattern, $condition, $truePart, $falsePart);
    if ($as !== null) {
        $expression = $this->as(sprintf('(%s)', $expression), $as);
    }
    return $expression;
}
Copied!

Impact

Extension authors can use the new expression method to build more advanced queries without the requirement to deal with the correct implementation for all supported database vendors.