‪TYPO3CMS  9.5
ExpressionBuilder.php
Go to the documentation of this file.
1 <?php
2 declare(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 
18 use Doctrine\DBAL\Platforms\AbstractPlatform;
20 
33 {
34  const ‪EQ = '=';
35  const ‪NEQ = '<>';
36  const ‪LT = '<';
37  const ‪LTE = '<=';
38  const ‪GT = '>';
39  const ‪GTE = '>=';
40 
41  const ‪QUOTE_NOTHING = 0;
43  const ‪QUOTE_PARAMETER = 2;
44 
50  protected ‪$connection;
51 
58  {
59  $this->connection = ‪$connection;
60  }
61 
69  public function ‪andX(...$expressions): ‪CompositeExpression
70  {
71  return new ‪CompositeExpression(CompositeExpression::TYPE_AND, $expressions);
72  }
73 
81  public function ‪orX(...$expressions): CompositeExpression
82  {
83  return new CompositeExpression(CompositeExpression::TYPE_OR, $expressions);
84  }
85 
95  public function ‪comparison($leftExpression, string $operator, $rightExpression): string
96  {
97  return $leftExpression . ' ' . $operator . ' ' . $rightExpression;
98  }
99 
108  public function ‪eq(string $fieldName, $value): string
109  {
110  return $this->‪comparison($this->connection->quoteIdentifier($fieldName), static::EQ, $value);
111  }
112 
127  public function ‪neq(string $fieldName, $value): string
128  {
129  return $this->‪comparison($this->connection->quoteIdentifier($fieldName), static::NEQ, $value);
130  }
131 
140  public function ‪lt($fieldName, $value): string
141  {
142  return $this->‪comparison($this->connection->quoteIdentifier($fieldName), static::LT, $value);
143  }
144 
153  public function ‪lte(string $fieldName, $value): string
154  {
155  return $this->‪comparison($this->connection->quoteIdentifier($fieldName), static::LTE, $value);
156  }
157 
166  public function ‪gt(string $fieldName, $value): string
167  {
168  return $this->‪comparison($this->connection->quoteIdentifier($fieldName), static::GT, $value);
169  }
170 
179  public function ‪gte(string $fieldName, $value): string
180  {
181  return $this->‪comparison($this->connection->quoteIdentifier($fieldName), static::GTE, $value);
182  }
183 
191  public function ‪isNull(string $fieldName): string
192  {
193  return $this->connection->quoteIdentifier($fieldName) . ' IS NULL';
194  }
195 
203  public function ‪isNotNull(string $fieldName): string
204  {
205  return $this->connection->quoteIdentifier($fieldName) . ' IS NOT NULL';
206  }
207 
216  public function ‪like(string $fieldName, $value): string
217  {
218  return $this->‪comparison($this->connection->quoteIdentifier($fieldName), 'LIKE', $value);
219  }
220 
229  public function ‪notLike(string $fieldName, $value): string
230  {
231  return $this->‪comparison($this->connection->quoteIdentifier($fieldName), 'NOT LIKE', $value);
232  }
233 
243  public function ‪in(string $fieldName, $value): string
244  {
245  return $this->‪comparison(
246  $this->connection->quoteIdentifier($fieldName),
247  'IN',
248  '(' . implode(', ', (array)$value) . ')'
249  );
250  }
251 
261  public function ‪notIn(string $fieldName, $value): string
262  {
263  return $this->‪comparison(
264  $this->connection->quoteIdentifier($fieldName),
265  'NOT IN',
266  '(' . implode(', ', (array)$value) . ')'
267  );
268  }
269 
280  public function ‪inSet(string $fieldName, string $value, bool $isColumn = false): string
281  {
282  if ($value === '') {
283  throw new \InvalidArgumentException(
284  'ExpressionBuilder::inSet() can not be used with an empty string value.',
285  1459696089
286  );
287  }
288 
289  if (strpos($value, ',') !== false) {
290  throw new \InvalidArgumentException(
291  'ExpressionBuilder::inSet() can not be used with values that contain a comma (",").',
292  1459696090
293  );
294  }
295 
296  switch ($this->connection->getDatabasePlatform()->getName()) {
297  case 'postgresql':
298  case 'pdo_postgresql':
299  return $this->‪comparison(
300  $isColumn ? $value . '::text' : $this->‪literal($this->‪unquoteLiteral((string)$value)),
301  self::EQ,
302  sprintf(
303  'ANY(string_to_array(%s, %s))',
304  $this->connection->quoteIdentifier($fieldName) . '::text',
305  $this->literal(',')
306  )
307  );
308  case 'oci8':
309  case 'pdo_oracle':
310  throw new \RuntimeException(
311  'FIND_IN_SET support for database platform "Oracle" not yet implemented.',
312  1459696680
313  );
314  case 'sqlsrv':
315  case 'pdo_sqlsrv':
316  case 'mssql':
317  // See unit and functional tests for details
318  if ($isColumn) {
319  $expression = $this->‪orX(
320  $this->‪eq($fieldName, $value),
321  $this->‪like($fieldName, $value . ' + \',%\''),
322  $this->‪like($fieldName, '\'%,\' + ' . $value),
323  $this->‪like($fieldName, '\'%,\' + ' . $value . ' + \',%\'')
324  );
325  } else {
326  $likeEscapedValue = str_replace(
327  ['[', '%'],
328  ['[[]', '[%]'],
329  $this->‪unquoteLiteral($value)
330  );
331  $expression = $this->‪orX(
332  $this->‪eq($fieldName, $this->‪literal($this->‪unquoteLiteral((string)$value))),
333  $this->‪like($fieldName, $this->‪literal($likeEscapedValue . ',%')),
334  $this->‪like($fieldName, $this->‪literal('%,' . $likeEscapedValue)),
335  $this->‪like($fieldName, $this->‪literal('%,' . $likeEscapedValue . ',%'))
336  );
337  }
338  return (string)$expression;
339  case 'sqlite':
340  case 'sqlite3':
341  case 'pdo_sqlite':
342  if (strpos($value, ':') === 0 || $value === '?') {
343  throw new \InvalidArgumentException(
344  'ExpressionBuilder::inSet() for SQLite can not be used with placeholder arguments.',
345  1476029421
346  );
347  }
348  $comparison = sprintf(
349  'instr(%s, %s)',
350  implode(
351  '||',
352  [
353  $this->‪literal(','),
354  $this->connection->quoteIdentifier($fieldName),
355  $this->literal(','),
356  ]
357  ),
358  $isColumn ?
359  implode(
360  '||',
361  [
362  $this->‪literal(','),
363  // do not explicitly quote value as it is expected to be
364  // quoted by the caller
365  'cast(' . $value . ' as text)',
366  $this->‪literal(','),
367  ]
368  )
369  : $this->‪literal(
370  ',' . $this->‪unquoteLiteral($value) . ','
371  )
372  );
373  return $comparison;
374  default:
375  return sprintf(
376  'FIND_IN_SET(%s, %s)',
377  $value,
378  $this->connection->quoteIdentifier($fieldName)
379  );
380  }
381  }
382 
390  public function ‪bitAnd(string $fieldName, int $value): string
391  {
392  switch ($this->connection->getDatabasePlatform()->getName()) {
393  case 'oci8':
394  case 'pdo_oracle':
395  return sprintf(
396  'BITAND(%s, %s)',
397  $this->connection->quoteIdentifier($fieldName),
398  $value
399  );
400  default:
401  return $this->‪comparison(
402  $this->connection->quoteIdentifier($fieldName),
403  '&',
404  $value
405  );
406  }
407  }
408 
416  public function ‪min(string $fieldName, string $alias = null): string
417  {
418  return $this->‪calculation('MIN', $fieldName, $alias);
419  }
420 
428  public function ‪max(string $fieldName, string $alias = null): string
429  {
430  return $this->‪calculation('MAX', $fieldName, $alias);
431  }
432 
440  public function ‪avg(string $fieldName, string $alias = null): string
441  {
442  return $this->‪calculation('AVG', $fieldName, $alias);
443  }
444 
452  public function ‪sum(string $fieldName, string $alias = null): string
453  {
454  return $this->‪calculation('SUM', $fieldName, $alias);
455  }
456 
464  public function ‪count(string $fieldName, string $alias = null): string
465  {
466  return $this->‪calculation('COUNT', $fieldName, $alias);
467  }
468 
476  public function ‪length(string $fieldName, string $alias = null): string
477  {
478  return $this->‪calculation('LENGTH', $fieldName, $alias);
479  }
480 
489  protected function ‪calculation(string $aggregateName, string $fieldName, string $alias = null): string
490  {
491  $aggregateSQL = sprintf(
492  '%s(%s)',
493  $aggregateName,
494  $this->connection->quoteIdentifier($fieldName)
495  );
496 
497  if (!empty($alias)) {
498  $aggregateSQL .= ' AS ' . $this->connection->quoteIdentifier($alias);
499  }
500 
501  return $aggregateSQL;
502  }
503 
512  public function ‪trim(string $fieldName, int $position = AbstractPlatform::TRIM_UNSPECIFIED, string $char = null)
513  {
514  return $this->connection->getDatabasePlatform()->getTrimExpression(
515  $this->connection->quoteIdentifier($fieldName),
516  $position,
517  ($char === null ? false : $this->literal($char))
518  );
519  }
520 
529  public function ‪literal($input, string $type = null)
530  {
531  return $this->connection->quote($input, $type);
532  }
533 
540  protected function ‪unquoteLiteral(string $value): string
541  {
542  $quoteChar = $this->connection
543  ->getDatabasePlatform()
544  ->getStringLiteralQuoteCharacter();
545 
546  $isQuoted = strpos($value, $quoteChar) === 0 && strpos(strrev($value), $quoteChar) === 0;
547 
548  if ($isQuoted) {
549  return str_replace($quoteChar . $quoteChar, $quoteChar, substr($value, 1, -1));
550  }
551 
552  return $value;
553  }
554 }
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\max
‪string max(string $fieldName, string $alias=null)
Definition: ExpressionBuilder.php:427
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\sum
‪string sum(string $fieldName, string $alias=null)
Definition: ExpressionBuilder.php:451
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\gt
‪string gt(string $fieldName, $value)
Definition: ExpressionBuilder.php:165
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\QUOTE_NOTHING
‪const QUOTE_NOTHING
Definition: ExpressionBuilder.php:41
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\unquoteLiteral
‪string unquoteLiteral(string $value)
Definition: ExpressionBuilder.php:539
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\like
‪string like(string $fieldName, $value)
Definition: ExpressionBuilder.php:215
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
Definition: ExpressionBuilder.php:33
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\EQ
‪const EQ
Definition: ExpressionBuilder.php:34
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\literal
‪mixed literal($input, string $type=null)
Definition: ExpressionBuilder.php:528
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\bitAnd
‪string bitAnd(string $fieldName, int $value)
Definition: ExpressionBuilder.php:389
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\eq
‪string eq(string $fieldName, $value)
Definition: ExpressionBuilder.php:107
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\count
‪string count(string $fieldName, string $alias=null)
Definition: ExpressionBuilder.php:463
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\LTE
‪const LTE
Definition: ExpressionBuilder.php:37
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\lt
‪string lt($fieldName, $value)
Definition: ExpressionBuilder.php:139
‪TYPO3\CMS\Core\Database\Query\Expression
Definition: CompositeExpression.php:3
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\notIn
‪string notIn(string $fieldName, $value)
Definition: ExpressionBuilder.php:260
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\neq
‪string neq(string $fieldName, $value)
Definition: ExpressionBuilder.php:126
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\calculation
‪string calculation(string $aggregateName, string $fieldName, string $alias=null)
Definition: ExpressionBuilder.php:488
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\QUOTE_IDENTIFIER
‪const QUOTE_IDENTIFIER
Definition: ExpressionBuilder.php:42
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\GTE
‪const GTE
Definition: ExpressionBuilder.php:39
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\__construct
‪__construct(Connection $connection)
Definition: ExpressionBuilder.php:56
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\lte
‪string lte(string $fieldName, $value)
Definition: ExpressionBuilder.php:152
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression
Definition: CompositeExpression.php:23
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\in
‪string in(string $fieldName, $value)
Definition: ExpressionBuilder.php:242
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\andX
‪CompositeExpression andX(... $expressions)
Definition: ExpressionBuilder.php:68
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\GT
‪const GT
Definition: ExpressionBuilder.php:38
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\orX
‪CompositeExpression orX(... $expressions)
Definition: ExpressionBuilder.php:80
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\NEQ
‪const NEQ
Definition: ExpressionBuilder.php:35
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\min
‪string min(string $fieldName, string $alias=null)
Definition: ExpressionBuilder.php:415
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\length
‪string length(string $fieldName, string $alias=null)
Definition: ExpressionBuilder.php:475
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\LT
‪const LT
Definition: ExpressionBuilder.php:36
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:31
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\gte
‪string gte(string $fieldName, $value)
Definition: ExpressionBuilder.php:178
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\$connection
‪Connection $connection
Definition: ExpressionBuilder.php:49
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\avg
‪string avg(string $fieldName, string $alias=null)
Definition: ExpressionBuilder.php:439
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\notLike
‪string notLike(string $fieldName, $value)
Definition: ExpressionBuilder.php:228
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\isNull
‪string isNull(string $fieldName)
Definition: ExpressionBuilder.php:190
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\QUOTE_PARAMETER
‪const QUOTE_PARAMETER
Definition: ExpressionBuilder.php:43
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\isNotNull
‪string isNotNull(string $fieldName)
Definition: ExpressionBuilder.php:202
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\inSet
‪string inSet(string $fieldName, string $value, bool $isColumn=false)
Definition: ExpressionBuilder.php:279
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\trim
‪string trim(string $fieldName, int $position=AbstractPlatform::TRIM_UNSPECIFIED, string $char=null)
Definition: ExpressionBuilder.php:511
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\comparison
‪string comparison($leftExpression, string $operator, $rightExpression)
Definition: ExpressionBuilder.php:94