1 | <?php |
||
28 | class Query implements \IteratorAggregate |
||
29 | { |
||
30 | use Macroable { |
||
31 | Macroable::__call as __macroableCall; |
||
32 | } |
||
33 | use AliasProvider; |
||
34 | use WhereProvider; |
||
35 | use OrderProvider; |
||
36 | use SelectProvider; |
||
37 | use GroupByProvider; |
||
38 | use RelationProvider; |
||
39 | use RepositoryProvider; |
||
40 | use ExecutionsProvider; |
||
41 | use LimitAndOffsetProvider; |
||
42 | |||
43 | /** |
||
44 | * @var CriterionInterface[]|\SplObjectStorage |
||
45 | */ |
||
46 | protected $criteria; |
||
47 | |||
48 | /** |
||
49 | * @var array|ObjectRepository[] |
||
50 | */ |
||
51 | protected $scopes = []; |
||
52 | |||
53 | /** |
||
54 | * Query constructor. |
||
55 | * @param ObjectRepository|null $repository |
||
56 | */ |
||
57 | 67 | public function __construct(ObjectRepository $repository = null) |
|
58 | { |
||
59 | 67 | $this->criteria = new \SplObjectStorage(); |
|
60 | |||
61 | 67 | if ($repository) { |
|
62 | 14 | $this->from($repository); |
|
63 | } |
||
64 | 67 | } |
|
65 | |||
66 | /** |
||
67 | * Adds the specified set of scopes (method groups) to the query. |
||
68 | * |
||
69 | * @param object|string ...$scopes |
||
70 | * @return Query|$this |
||
71 | */ |
||
72 | 33 | public function scope(...$scopes): self |
|
78 | |||
79 | /** |
||
80 | * Returns a list of selection criteria. |
||
81 | * |
||
82 | * @return \Generator|CriterionInterface[] |
||
83 | */ |
||
84 | 67 | public function getCriteria(): \Generator |
|
88 | |||
89 | /** |
||
90 | * Creates a new query (alias to the constructor). |
||
91 | * |
||
92 | * @param CriterionInterface $criterion |
||
93 | * @return Query|$this |
||
94 | */ |
||
95 | 63 | public function add(CriterionInterface $criterion): self |
|
101 | |||
102 | /** |
||
103 | * Creates a new query (alias to the constructor). |
||
104 | * |
||
105 | * @param ObjectRepository|null $repository |
||
106 | * @return Query |
||
107 | */ |
||
108 | 67 | public static function new(ObjectRepository $repository = null): Query |
|
112 | |||
113 | /** |
||
114 | * @param string $name |
||
115 | * @return null |
||
116 | */ |
||
117 | 18 | public function __get(string $name) |
|
125 | |||
126 | /** |
||
127 | * @param string $method |
||
128 | * @param array $parameters |
||
129 | * @return mixed|$this|Query |
||
130 | */ |
||
131 | 4 | public function __call(string $method, array $parameters = []) |
|
132 | { |
||
133 | 4 | foreach ($this->scopes as $scope) { |
|
134 | 4 | if (\method_exists($scope, $method)) { |
|
135 | /** @var Query $query */ |
||
136 | 4 | $query = \is_object($scope) |
|
137 | 4 | ? clone $scope->$method(...$parameters) |
|
138 | 4 | : clone $scope::$method(...$parameters); |
|
139 | |||
140 | 4 | foreach ($query->getCriteria() as $criterion) { |
|
141 | 4 | $this->add($criterion); |
|
142 | } |
||
143 | |||
144 | 4 | return $this; |
|
145 | } |
||
146 | } |
||
147 | |||
148 | return $this->__macroableCall($method, $parameters); |
||
149 | } |
||
150 | |||
151 | /** |
||
152 | * Returns a set of scopes for the specified query. |
||
153 | * |
||
154 | * @return array|ObjectRepository[] |
||
155 | */ |
||
156 | 7 | public function getScopes(): array |
|
160 | |||
161 | /** |
||
162 | * Attaches a child query to the parent without affecting |
||
163 | * the set of criteria (selections). |
||
164 | * |
||
165 | * @param Query $query |
||
166 | * @return Query |
||
167 | */ |
||
168 | 5 | public function attach(Query $query): Query |
|
169 | { |
||
170 | 5 | $this->repository |
|
171 | 2 | ? $query->from($this->getRepository()) |
|
|
|||
172 | 3 | : $query->alias = $this->getAlias(); |
|
173 | |||
174 | 5 | return $query; |
|
175 | } |
||
176 | |||
177 | /** |
||
178 | * @param string $alias |
||
179 | * @return Query|$this|self |
||
180 | */ |
||
181 | 2 | public function withAlias(string $alias): Query |
|
182 | { |
||
183 | 2 | $this->alias = $alias; |
|
184 | |||
185 | 2 | foreach ($this->criteria as $criterion) { |
|
186 | $criterion->withAlias($alias); |
||
187 | } |
||
188 | |||
189 | 2 | return $this; |
|
190 | } |
||
191 | |||
192 | /** |
||
193 | * Creates a new query using the current set of scopes. |
||
194 | * |
||
195 | * @return Query |
||
196 | */ |
||
197 | 7 | public function create(): Query |
|
201 | |||
202 | /** |
||
203 | * Copies a set of Criteria from the child query to the parent. |
||
204 | * |
||
205 | * @param Query $query |
||
206 | * @return Query |
||
207 | */ |
||
208 | 2 | public function merge(Query $query): Query |
|
209 | { |
||
210 | 2 | foreach ($query->getCriteria() as $criterion) { |
|
211 | $criterion->withAlias($query->getAlias()); |
||
212 | $this->add($criterion); |
||
213 | } |
||
214 | |||
215 | 2 | return $this; |
|
216 | } |
||
217 | |||
218 | /** |
||
219 | * @return void |
||
220 | */ |
||
221 | 4 | public function __clone() |
|
222 | { |
||
223 | 4 | $reflection = new \ReflectionClass($this); |
|
224 | |||
225 | 4 | foreach ($reflection->getProperties() as $property) { |
|
226 | 4 | $property->setAccessible(true); |
|
227 | 4 | $value = $property->getValue($this); |
|
228 | |||
229 | 4 | if (\is_object($value)) { |
|
230 | 4 | $property->setValue($this, clone $value); |
|
231 | } |
||
232 | } |
||
233 | 4 | } |
|
234 | |||
235 | /** |
||
236 | * @return \Generator |
||
237 | */ |
||
238 | public function getIterator(): \Generator |
||
244 | |||
245 | /** |
||
246 | * @return bool |
||
247 | */ |
||
248 | public function isEmpty(): bool |
||
249 | { |
||
250 | return $this->criteria->count() === 0; |
||
252 | } |
||
253 |
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.