1<?php 2 3namespace Doctrine\DBAL\Query\Expression; 4 5use Countable; 6use Doctrine\Deprecations\Deprecation; 7use ReturnTypeWillChange; 8 9use function array_merge; 10use function count; 11use function implode; 12 13/** 14 * Composite expression is responsible to build a group of similar expression. 15 */ 16class CompositeExpression implements Countable 17{ 18 /** 19 * Constant that represents an AND composite expression. 20 */ 21 public const TYPE_AND = 'AND'; 22 23 /** 24 * Constant that represents an OR composite expression. 25 */ 26 public const TYPE_OR = 'OR'; 27 28 /** 29 * The instance type of composite expression. 30 * 31 * @var string 32 */ 33 private $type; 34 35 /** 36 * Each expression part of the composite expression. 37 * 38 * @var self[]|string[] 39 */ 40 private $parts = []; 41 42 /** 43 * @internal Use the and() / or() factory methods. 44 * 45 * @param string $type Instance type of composite expression. 46 * @param self[]|string[] $parts Composition of expressions to be joined on composite expression. 47 */ 48 public function __construct($type, array $parts = []) 49 { 50 $this->type = $type; 51 52 $this->addMultiple($parts); 53 54 Deprecation::triggerIfCalledFromOutside( 55 'doctrine/dbal', 56 'https://github.com/doctrine/dbal/pull/3864', 57 'Do not use CompositeExpression constructor directly, use static and() and or() factory methods.' 58 ); 59 } 60 61 /** 62 * @param self|string $part 63 * @param self|string ...$parts 64 */ 65 public static function and($part, ...$parts): self 66 { 67 return new self(self::TYPE_AND, array_merge([$part], $parts)); 68 } 69 70 /** 71 * @param self|string $part 72 * @param self|string ...$parts 73 */ 74 public static function or($part, ...$parts): self 75 { 76 return new self(self::TYPE_OR, array_merge([$part], $parts)); 77 } 78 79 /** 80 * Adds multiple parts to composite expression. 81 * 82 * @deprecated This class will be made immutable. Use with() instead. 83 * 84 * @param self[]|string[] $parts 85 * 86 * @return CompositeExpression 87 */ 88 public function addMultiple(array $parts = []) 89 { 90 Deprecation::triggerIfCalledFromOutside( 91 'doctrine/dbal', 92 'https://github.com/doctrine/dbal/issues/3844', 93 'CompositeExpression::addMultiple() is deprecated, use CompositeExpression::with() instead.' 94 ); 95 96 foreach ($parts as $part) { 97 $this->add($part); 98 } 99 100 return $this; 101 } 102 103 /** 104 * Adds an expression to composite expression. 105 * 106 * @deprecated This class will be made immutable. Use with() instead. 107 * 108 * @param mixed $part 109 * 110 * @return CompositeExpression 111 */ 112 public function add($part) 113 { 114 Deprecation::triggerIfCalledFromOutside( 115 'doctrine/dbal', 116 'https://github.com/doctrine/dbal/issues/3844', 117 'CompositeExpression::add() is deprecated, use CompositeExpression::with() instead.' 118 ); 119 120 if (empty($part)) { 121 return $this; 122 } 123 124 if ($part instanceof self && count($part) === 0) { 125 return $this; 126 } 127 128 $this->parts[] = $part; 129 130 return $this; 131 } 132 133 /** 134 * Returns a new CompositeExpression with the given parts added. 135 * 136 * @param self|string $part 137 * @param self|string ...$parts 138 */ 139 public function with($part, ...$parts): self 140 { 141 $that = clone $this; 142 143 $that->parts[] = $part; 144 145 foreach ($parts as $part) { 146 $that->parts[] = $part; 147 } 148 149 return $that; 150 } 151 152 /** 153 * Retrieves the amount of expressions on composite expression. 154 * 155 * @return int 156 */ 157 #[ReturnTypeWillChange] 158 public function count() 159 { 160 return count($this->parts); 161 } 162 163 /** 164 * Retrieves the string representation of this composite expression. 165 * 166 * @return string 167 */ 168 public function __toString() 169 { 170 if ($this->count() === 1) { 171 return (string) $this->parts[0]; 172 } 173 174 return '(' . implode(') ' . $this->type . ' (', $this->parts) . ')'; 175 } 176 177 /** 178 * Returns the type of this composite expression (AND/OR). 179 * 180 * @return string 181 */ 182 public function getType() 183 { 184 return $this->type; 185 } 186} 187