‪TYPO3CMS  ‪main
CompositeExpression.php
Go to the documentation of this file.
1 <?php
2 
3 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 
19 
20 use Doctrine\DBAL\Query\Expression\CompositeExpression as DoctrineCompositeExpression;
21 
26 class ‪CompositeExpression extends DoctrineCompositeExpression
27 {
33  private array ‪$parts;
34 
38  private string ‪$type;
39 
40  private bool ‪$isOuter;
41 
46  public function ‪__construct(string ‪$type, array ‪$parts = [], bool ‪$isOuter = false)
47  {
48  $this->isOuter = ‪$isOuter;
49  // parent::__construct() call is left out by intention. doctrine/dbal works with private properties, which
50  // make it otherwise impossible to keep compat method signature and providing the features needed.
51  $this->type = ‪$type;
52  if (‪$parts !== []) {
53  // doctrine/dbal solved the issue to avoid empty parts by making it mandatory to avoid instantiating this
54  // class without a part. As we allow this and handle empty parts later on, we apply the empty check here.
55  // @see https://github.com/doctrine/dbal/issues/2388
56  array_filter(‪$parts, static fn(‪CompositeExpression|DoctrineCompositeExpression|string|null $value): bool => !self::isEmptyPart($value));
57  }
58  $this->parts = ‪$parts;
59  }
60 
66  public function ‪__toString(): string
67  {
68  $this->parts = array_filter($this->parts, static fn(‪CompositeExpression|DoctrineCompositeExpression|string|null $value): bool => !self::isEmptyPart($value));
69  if ($this->‪count() === 0) {
70  return '';
71  }
72  if ($this->‪count() === 1) {
73  return (string)$this->parts[0];
74  }
75  if ($this->isOuter) {
76  return '(' . implode(') ' . $this->type . ' (', $this->parts) . ')';
77  }
78  return '((' . implode(') ' . $this->type . ' (', $this->parts) . '))';
79  }
80 
85  public static function ‪and($part = null, ...‪$parts): self
86  {
87  $mergedParts = array_merge([$part], ‪$parts);
88  array_filter($mergedParts, static fn(‪CompositeExpression|DoctrineCompositeExpression|string|null $value): bool => !self::isEmptyPart($value));
89  return (new self(self::TYPE_AND, []))->with(...$mergedParts);
90  }
91 
96  public static function ‪or($part = null, ...‪$parts): self
97  {
98  $mergedParts = array_merge([$part], ‪$parts);
99  array_filter($mergedParts, static fn(‪CompositeExpression|DoctrineCompositeExpression|string|null $value): bool => !self::isEmptyPart($value));
100  return (new self(self::TYPE_OR, []))->with(...$mergedParts);
101  }
102 
109  public function ‪with($part = null, ...‪$parts): self
110  {
111  $mergedParts = array_merge([$part], ‪$parts);
112  array_filter($mergedParts, static fn(‪CompositeExpression|DoctrineCompositeExpression|string|null $value): bool => !self::isEmptyPart($value));
113  $that = clone $this;
114  foreach ($mergedParts as $singlePart) {
115  // Due to a bug in Doctrine DBAL, we must add our own check here,
116  // which we luckily can, as we use a subclass anyway.
117  // @see https://github.com/doctrine/dbal/issues/2388
118  if (!self::isEmptyPart($singlePart)) {
119  $that->parts[] = $singlePart;
120  }
121  }
122 
123  return $that;
124  }
125 
129  public function ‪count(): int
130  {
131  return ‪count($this->parts);
132  }
133 
137  public function ‪getType(): string
138  {
139  return ‪$this->type;
140  }
141 
142  private static function ‪isEmptyPart(‪CompositeExpression|DoctrineCompositeExpression|string|null $value): bool
143  {
144  return $value === null
145  || ($value instanceof DoctrineCompositeExpression && $value->count() === 0)
146  || trim((string)$value, '() ') === ''
147  ;
148  }
149 }
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression\or
‪static or($part=null,... $parts)
Definition: CompositeExpression.php:96
‪TYPO3\CMS\Core\Database\Query\Expression
Definition: CompositeExpression.php:18
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression\__toString
‪__toString()
Definition: CompositeExpression.php:66
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression\__construct
‪__construct(string $type, array $parts=[], bool $isOuter=false)
Definition: CompositeExpression.php:46
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression\and
‪static and($part=null,... $parts)
Definition: CompositeExpression.php:85
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression
Definition: CompositeExpression.php:27
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression\$parts
‪array $parts
Definition: CompositeExpression.php:33
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression\isEmptyPart
‪static isEmptyPart(CompositeExpression|DoctrineCompositeExpression|string|null $value)
Definition: CompositeExpression.php:142
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression\count
‪count()
Definition: CompositeExpression.php:129
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression\with
‪with($part=null,... $parts)
Definition: CompositeExpression.php:109
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression\$type
‪string $type
Definition: CompositeExpression.php:38
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression\getType
‪getType()
Definition: CompositeExpression.php:137
‪TYPO3\CMS\Core\Database\Query\Expression\CompositeExpression\$isOuter
‪bool $isOuter
Definition: CompositeExpression.php:40