1 | <?php |
||||
2 | |||||
3 | declare(strict_types=1); |
||||
4 | |||||
5 | namespace Doctrine\ORM\Persisters\Collection; |
||||
6 | |||||
7 | use BadMethodCallException; |
||||
8 | use Doctrine\Common\Collections\Criteria; |
||||
9 | use Doctrine\DBAL\DBALException; |
||||
10 | use Doctrine\ORM\Mapping\ClassMetadata; |
||||
11 | use Doctrine\ORM\Mapping\FieldMetadata; |
||||
12 | use Doctrine\ORM\Mapping\JoinColumnMetadata; |
||||
13 | use Doctrine\ORM\Mapping\ManyToManyAssociationMetadata; |
||||
14 | use Doctrine\ORM\Mapping\ToManyAssociationMetadata; |
||||
15 | use Doctrine\ORM\Mapping\ToOneAssociationMetadata; |
||||
16 | use Doctrine\ORM\PersistentCollection; |
||||
17 | use Doctrine\ORM\Persisters\SqlValueVisitor; |
||||
18 | use Doctrine\ORM\Query; |
||||
19 | use Doctrine\ORM\Utility\PersisterHelper; |
||||
20 | use function array_fill; |
||||
21 | use function count; |
||||
22 | use function get_class; |
||||
23 | use function implode; |
||||
24 | use function in_array; |
||||
25 | use function reset; |
||||
26 | use function sprintf; |
||||
27 | |||||
28 | /** |
||||
29 | * Persister for many-to-many collections. |
||||
30 | */ |
||||
31 | class ManyToManyPersister extends AbstractCollectionPersister |
||||
32 | { |
||||
33 | /** |
||||
34 | * {@inheritdoc} |
||||
35 | */ |
||||
36 | 18 | public function delete(PersistentCollection $collection) |
|||
37 | { |
||||
38 | 18 | $association = $collection->getMapping(); |
|||
39 | |||||
40 | 18 | if (! $association->isOwningSide()) { |
|||
41 | return; // ignore inverse side |
||||
42 | } |
||||
43 | |||||
44 | 18 | $class = $this->em->getClassMetadata($association->getSourceEntity()); |
|||
45 | 18 | $joinTable = $association->getJoinTable(); |
|||
46 | 18 | $types = []; |
|||
47 | |||||
48 | 18 | foreach ($joinTable->getJoinColumns() as $joinColumn) { |
|||
49 | /** @var JoinColumnMetadata $joinColumn */ |
||||
50 | 18 | $referencedColumnName = $joinColumn->getReferencedColumnName(); |
|||
51 | |||||
52 | 18 | if (! $joinColumn->getType()) { |
|||
53 | $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $class, $this->em)); |
||||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
54 | } |
||||
55 | |||||
56 | 18 | $types[] = $joinColumn->getType(); |
|||
57 | } |
||||
58 | |||||
59 | 18 | $sql = $this->getDeleteSQL($collection); |
|||
60 | 18 | $params = $this->getDeleteSQLParameters($collection); |
|||
61 | |||||
62 | 18 | $this->conn->executeUpdate($sql, $params, $types); |
|||
63 | 18 | } |
|||
64 | |||||
65 | /** |
||||
66 | * {@inheritdoc} |
||||
67 | */ |
||||
68 | 329 | public function update(PersistentCollection $collection) |
|||
69 | { |
||||
70 | 329 | $association = $collection->getMapping(); |
|||
71 | |||||
72 | 329 | if (! $association->isOwningSide()) { |
|||
73 | 236 | return; // ignore inverse side |
|||
74 | } |
||||
75 | |||||
76 | 328 | [$deleteSql, $deleteTypes] = $this->getDeleteRowSQL($collection); |
|||
77 | 328 | [$insertSql, $insertTypes] = $this->getInsertRowSQL($collection); |
|||
78 | |||||
79 | 328 | foreach ($collection->getDeleteDiff() as $element) { |
|||
80 | 10 | $this->conn->executeUpdate( |
|||
81 | 10 | $deleteSql, |
|||
82 | 10 | $this->getDeleteRowSQLParameters($collection, $element), |
|||
83 | 10 | $deleteTypes |
|||
84 | ); |
||||
85 | } |
||||
86 | |||||
87 | 328 | foreach ($collection->getInsertDiff() as $element) { |
|||
88 | 328 | $this->conn->executeUpdate( |
|||
89 | 328 | $insertSql, |
|||
90 | 328 | $this->getInsertRowSQLParameters($collection, $element), |
|||
91 | 328 | $insertTypes |
|||
92 | ); |
||||
93 | } |
||||
94 | 328 | } |
|||
95 | |||||
96 | /** |
||||
97 | * {@inheritdoc} |
||||
98 | */ |
||||
99 | 3 | public function get(PersistentCollection $collection, $index) |
|||
100 | { |
||||
101 | 3 | $association = $collection->getMapping(); |
|||
102 | |||||
103 | 3 | if (! ($association instanceof ToManyAssociationMetadata && $association->getIndexedBy())) { |
|||
104 | throw new BadMethodCallException('Selecting a collection by index is only supported on indexed collections.'); |
||||
105 | } |
||||
106 | |||||
107 | 3 | $persister = $this->uow->getEntityPersister($association->getTargetEntity()); |
|||
108 | 3 | $mappedKey = $association->isOwningSide() |
|||
109 | 2 | ? $association->getInversedBy() |
|||
110 | 3 | : $association->getMappedBy(); |
|||
111 | |||||
112 | $criteria = [ |
||||
113 | 3 | $mappedKey => $collection->getOwner(), |
|||
114 | 3 | $association->getIndexedBy() => $index, |
|||
115 | ]; |
||||
116 | |||||
117 | 3 | return $persister->load($criteria, null, $association, [], 0, 1); |
|||
118 | } |
||||
119 | |||||
120 | /** |
||||
121 | * {@inheritdoc} |
||||
122 | */ |
||||
123 | 18 | public function count(PersistentCollection $collection) |
|||
124 | { |
||||
125 | 18 | $conditions = []; |
|||
126 | 18 | $params = []; |
|||
127 | 18 | $types = []; |
|||
128 | 18 | $association = $collection->getMapping(); |
|||
129 | 18 | $identifier = $this->uow->getEntityIdentifier($collection->getOwner()); |
|||
130 | 18 | $sourceClass = $this->em->getClassMetadata($association->getSourceEntity()); |
|||
131 | 18 | $targetClass = $this->em->getClassMetadata($association->getTargetEntity()); |
|||
132 | 18 | $owningAssociation = ! $association->isOwningSide() |
|||
133 | 4 | ? $targetClass->getProperty($association->getMappedBy()) |
|||
134 | 18 | : $association; |
|||
135 | |||||
136 | 18 | $joinTable = $owningAssociation->getJoinTable(); |
|||
137 | 18 | $joinTableName = $joinTable->getQuotedQualifiedName($this->platform); |
|||
138 | 18 | $joinColumns = $association->isOwningSide() |
|||
139 | 14 | ? $joinTable->getJoinColumns() |
|||
140 | 18 | : $joinTable->getInverseJoinColumns(); |
|||
141 | |||||
142 | 18 | foreach ($joinColumns as $joinColumn) { |
|||
143 | /** @var JoinColumnMetadata $joinColumn */ |
||||
144 | 18 | $quotedColumnName = $this->platform->quoteIdentifier($joinColumn->getColumnName()); |
|||
145 | 18 | $referencedColumnName = $joinColumn->getReferencedColumnName(); |
|||
146 | |||||
147 | 18 | if (! $joinColumn->getType()) { |
|||
148 | 1 | $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $sourceClass, $this->em)); |
|||
0 ignored issues
–
show
$sourceClass of type Doctrine\Common\Persistence\Mapping\ClassMetadata is incompatible with the type Doctrine\ORM\Mapping\ClassMetadata expected by parameter $class of Doctrine\ORM\Utility\Per...lper::getTypeOfColumn() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
149 | } |
||||
150 | |||||
151 | 18 | $conditions[] = sprintf('t.%s = ?', $quotedColumnName); |
|||
152 | 18 | $params[] = $identifier[$sourceClass->fieldNames[$referencedColumnName]]; |
|||
153 | 18 | $types[] = $joinColumn->getType(); |
|||
154 | } |
||||
155 | |||||
156 | 18 | [$joinTargetEntitySQL, $filterSql] = $this->getFilterSql($association); |
|||
157 | |||||
158 | 18 | if ($filterSql) { |
|||
159 | 3 | $conditions[] = $filterSql; |
|||
160 | } |
||||
161 | |||||
162 | // If there is a provided criteria, make part of conditions |
||||
163 | // @todo Fix this. Current SQL returns something like: |
||||
164 | /*if ($criteria && ($expression = $criteria->getWhereExpression()) !== null) { |
||||
165 | // A join is needed on the target entity |
||||
166 | $targetTableName = $targetClass->table->getQuotedQualifiedName($this->platform); |
||||
167 | $targetJoinSql = ' JOIN ' . $targetTableName . ' te' |
||||
168 | . ' ON' . implode(' AND ', $this->getOnConditionSQL($association)); |
||||
169 | |||||
170 | // And criteria conditions needs to be added |
||||
171 | $persister = $this->uow->getEntityPersister($targetClass->getClassName()); |
||||
172 | $visitor = new SqlExpressionVisitor($persister, $targetClass); |
||||
173 | $conditions[] = $visitor->dispatch($expression); |
||||
174 | |||||
175 | $joinTargetEntitySQL = $targetJoinSql . $joinTargetEntitySQL; |
||||
176 | }*/ |
||||
177 | |||||
178 | $sql = 'SELECT COUNT(*)' |
||||
179 | 18 | . ' FROM ' . $joinTableName . ' t' |
|||
180 | 18 | . $joinTargetEntitySQL |
|||
181 | 18 | . ' WHERE ' . implode(' AND ', $conditions); |
|||
182 | |||||
183 | 18 | return $this->conn->fetchColumn($sql, $params, 0, $types); |
|||
184 | } |
||||
185 | |||||
186 | /** |
||||
187 | * {@inheritDoc} |
||||
188 | */ |
||||
189 | 8 | public function slice(PersistentCollection $collection, $offset, $length = null) |
|||
190 | { |
||||
191 | 8 | $association = $collection->getMapping(); |
|||
192 | 8 | $persister = $this->uow->getEntityPersister($association->getTargetEntity()); |
|||
193 | |||||
194 | 8 | return $persister->getManyToManyCollection($association, $collection->getOwner(), $offset, $length); |
|||
195 | } |
||||
196 | |||||
197 | /** |
||||
198 | * {@inheritdoc} |
||||
199 | */ |
||||
200 | 7 | public function containsKey(PersistentCollection $collection, $key) |
|||
201 | { |
||||
202 | 7 | $association = $collection->getMapping(); |
|||
203 | |||||
204 | 7 | if (! ($association instanceof ToManyAssociationMetadata && $association->getIndexedBy())) { |
|||
205 | throw new BadMethodCallException('Selecting a collection by index is only supported on indexed collections.'); |
||||
206 | } |
||||
207 | |||||
208 | 7 | [$quotedJoinTable, $whereClauses, $params, $types] = $this->getJoinTableRestrictionsWithKey($collection, $key, true); |
|||
209 | |||||
210 | 7 | $sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses); |
|||
211 | |||||
212 | 7 | return (bool) $this->conn->fetchColumn($sql, $params, 0, $types); |
|||
213 | } |
||||
214 | |||||
215 | /** |
||||
216 | * {@inheritDoc} |
||||
217 | */ |
||||
218 | 7 | public function contains(PersistentCollection $collection, $element) |
|||
219 | { |
||||
220 | 7 | if (! $this->isValidEntityState($element)) { |
|||
221 | 2 | return false; |
|||
222 | } |
||||
223 | |||||
224 | 7 | [$quotedJoinTable, $whereClauses, $params, $types] = $this->getJoinTableRestrictions($collection, $element, true); |
|||
225 | |||||
226 | 7 | $sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses); |
|||
227 | |||||
228 | 7 | return (bool) $this->conn->fetchColumn($sql, $params, 0, $types); |
|||
229 | } |
||||
230 | |||||
231 | /** |
||||
232 | * {@inheritDoc} |
||||
233 | */ |
||||
234 | 2 | public function removeElement(PersistentCollection $collection, $element) |
|||
235 | { |
||||
236 | 2 | if (! $this->isValidEntityState($element)) { |
|||
237 | 2 | return false; |
|||
238 | } |
||||
239 | |||||
240 | 2 | [$quotedJoinTable, $whereClauses, $params, $types] = $this->getJoinTableRestrictions($collection, $element, false); |
|||
241 | |||||
242 | 2 | $sql = 'DELETE FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses); |
|||
243 | |||||
244 | 2 | return (bool) $this->conn->executeUpdate($sql, $params, $types); |
|||
245 | } |
||||
246 | |||||
247 | /** |
||||
248 | * {@inheritDoc} |
||||
249 | */ |
||||
250 | 12 | public function loadCriteria(PersistentCollection $collection, Criteria $criteria) |
|||
251 | { |
||||
252 | 12 | $association = $collection->getMapping(); |
|||
253 | 12 | $owner = $collection->getOwner(); |
|||
254 | 12 | $ownerMetadata = $this->em->getClassMetadata(get_class($owner)); |
|||
255 | 12 | $identifier = $this->uow->getEntityIdentifier($owner); |
|||
256 | 12 | $targetClass = $this->em->getClassMetadata($association->getTargetEntity()); |
|||
257 | 12 | $onConditions = $this->getOnConditionSQL($association); |
|||
258 | 12 | $whereClauses = $params = $types = []; |
|||
259 | |||||
260 | 12 | if (! $association->isOwningSide()) { |
|||
261 | 1 | $association = $targetClass->getProperty($association->getMappedBy()); |
|||
262 | 1 | $joinColumns = $association->getJoinTable()->getInverseJoinColumns(); |
|||
263 | } else { |
||||
264 | 11 | $joinColumns = $association->getJoinTable()->getJoinColumns(); |
|||
265 | } |
||||
266 | |||||
267 | 12 | foreach ($joinColumns as $joinColumn) { |
|||
268 | /** @var JoinColumnMetadata $joinColumn */ |
||||
269 | 12 | $quotedColumnName = $this->platform->quoteIdentifier($joinColumn->getColumnName()); |
|||
270 | 12 | $referencedColumnName = $joinColumn->getReferencedColumnName(); |
|||
271 | |||||
272 | 12 | if (! $joinColumn->getType()) { |
|||
273 | $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $ownerMetadata, $this->em)); |
||||
0 ignored issues
–
show
$ownerMetadata of type Doctrine\Common\Persistence\Mapping\ClassMetadata is incompatible with the type Doctrine\ORM\Mapping\ClassMetadata expected by parameter $class of Doctrine\ORM\Utility\Per...lper::getTypeOfColumn() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
274 | } |
||||
275 | |||||
276 | 12 | $whereClauses[] = sprintf('t.%s = ?', $quotedColumnName); |
|||
277 | 12 | $params[] = $identifier[$ownerMetadata->fieldNames[$referencedColumnName]]; |
|||
278 | 12 | $types[] = $joinColumn->getType(); |
|||
279 | } |
||||
280 | |||||
281 | 12 | $parameters = $this->expandCriteriaParameters($criteria); |
|||
282 | |||||
283 | 12 | foreach ($parameters as $parameter) { |
|||
284 | 7 | [$name, $value, $operator] = $parameter; |
|||
285 | |||||
286 | 7 | $property = $targetClass->getProperty($name); |
|||
287 | 7 | $columnName = $this->platform->quoteIdentifier($property->getColumnName()); |
|||
288 | |||||
289 | 7 | $whereClauses[] = sprintf('te.%s %s ?', $columnName, $operator); |
|||
290 | 7 | $params[] = $value; |
|||
291 | 7 | $types[] = $property->getType(); |
|||
292 | } |
||||
293 | |||||
294 | 12 | $tableName = $targetClass->table->getQuotedQualifiedName($this->platform); |
|||
295 | 12 | $joinTableName = $association->getJoinTable()->getQuotedQualifiedName($this->platform); |
|||
296 | 12 | $resultSetMapping = new Query\ResultSetMappingBuilder($this->em); |
|||
297 | |||||
298 | 12 | $resultSetMapping->addRootEntityFromClassMetadata($targetClass->getClassName(), 'te'); |
|||
299 | |||||
300 | 12 | $sql = 'SELECT ' . $resultSetMapping->generateSelectClause() |
|||
301 | 12 | . ' FROM ' . $tableName . ' te' |
|||
302 | 12 | . ' JOIN ' . $joinTableName . ' t ON' |
|||
303 | 12 | . implode(' AND ', $onConditions) |
|||
304 | 12 | . ' WHERE ' . implode(' AND ', $whereClauses); |
|||
305 | |||||
306 | 12 | $sql .= $this->getOrderingSql($criteria, $targetClass); |
|||
0 ignored issues
–
show
$targetClass of type Doctrine\Common\Persistence\Mapping\ClassMetadata is incompatible with the type Doctrine\ORM\Mapping\ClassMetadata expected by parameter $targetClass of Doctrine\ORM\Persisters\...ister::getOrderingSql() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
307 | 12 | $sql .= $this->getLimitSql($criteria); |
|||
308 | |||||
309 | 12 | $stmt = $this->conn->executeQuery($sql, $params, $types); |
|||
310 | |||||
311 | 12 | return $this->em->newHydrator(Query::HYDRATE_OBJECT)->hydrateAll($stmt, $resultSetMapping); |
|||
312 | } |
||||
313 | |||||
314 | /** |
||||
315 | * Generates the filter SQL for a given mapping. |
||||
316 | * |
||||
317 | * This method is not used for actually grabbing the related entities |
||||
318 | * but when the extra-lazy collection methods are called on a filtered |
||||
319 | * association. This is why besides the many to many table we also |
||||
320 | * have to join in the actual entities table leading to additional |
||||
321 | * JOIN. |
||||
322 | * |
||||
323 | * @return string[] ordered tuple: |
||||
324 | * - JOIN condition to add to the SQL |
||||
325 | * - WHERE condition to add to the SQL |
||||
326 | */ |
||||
327 | 32 | public function getFilterSql(ManyToManyAssociationMetadata $association) |
|||
328 | { |
||||
329 | 32 | $targetClass = $this->em->getClassMetadata($association->getTargetEntity()); |
|||
330 | 32 | $rootClass = $this->em->getClassMetadata($targetClass->getRootClassName()); |
|||
331 | 32 | $filterSql = $this->generateFilterConditionSQL($rootClass, 'te'); |
|||
0 ignored issues
–
show
$rootClass of type Doctrine\Common\Persistence\Mapping\ClassMetadata is incompatible with the type Doctrine\ORM\Mapping\ClassMetadata expected by parameter $targetEntity of Doctrine\ORM\Persisters\...ateFilterConditionSQL() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
332 | |||||
333 | 32 | if ($filterSql === '') { |
|||
334 | 32 | return ['', '']; |
|||
335 | } |
||||
336 | |||||
337 | // A join is needed if there is filtering on the target entity |
||||
338 | 6 | $tableName = $rootClass->table->getQuotedQualifiedName($this->platform); |
|||
339 | 6 | $joinSql = ' JOIN ' . $tableName . ' te' |
|||
340 | 6 | . ' ON' . implode(' AND ', $this->getOnConditionSQL($association)); |
|||
341 | |||||
342 | 6 | return [$joinSql, $filterSql]; |
|||
343 | } |
||||
344 | |||||
345 | /** |
||||
346 | * Generates the filter SQL for a given entity and table alias. |
||||
347 | * |
||||
348 | * @param ClassMetadata $targetEntity Metadata of the target entity. |
||||
349 | * @param string $targetTableAlias The table alias of the joined/selected table. |
||||
350 | * |
||||
351 | * @return string The SQL query part to add to a query. |
||||
352 | */ |
||||
353 | 32 | protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias) |
|||
354 | { |
||||
355 | 32 | $filterClauses = []; |
|||
356 | |||||
357 | 32 | foreach ($this->em->getFilters()->getEnabledFilters() as $filter) { |
|||
358 | 6 | $filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias); |
|||
359 | |||||
360 | 6 | if ($filterExpr) { |
|||
361 | 6 | $filterClauses[] = '(' . $filterExpr . ')'; |
|||
362 | } |
||||
363 | } |
||||
364 | |||||
365 | 32 | if (! $filterClauses) { |
|||
366 | 32 | return ''; |
|||
367 | } |
||||
368 | |||||
369 | 6 | $filterSql = implode(' AND ', $filterClauses); |
|||
370 | |||||
371 | 6 | return isset($filterClauses[1]) |
|||
372 | ? '(' . $filterSql . ')' |
||||
373 | 6 | : $filterSql; |
|||
374 | } |
||||
375 | |||||
376 | /** |
||||
377 | * Generate ON condition |
||||
378 | * |
||||
379 | * @return string[] |
||||
380 | */ |
||||
381 | 18 | protected function getOnConditionSQL(ManyToManyAssociationMetadata $association) |
|||
382 | { |
||||
383 | 18 | $targetClass = $this->em->getClassMetadata($association->getTargetEntity()); |
|||
384 | 18 | $owningAssociation = ! $association->isOwningSide() |
|||
385 | 3 | ? $targetClass->getProperty($association->getMappedBy()) |
|||
386 | 18 | : $association; |
|||
387 | |||||
388 | 18 | $joinTable = $owningAssociation->getJoinTable(); |
|||
389 | 18 | $joinColumns = $association->isOwningSide() |
|||
390 | 15 | ? $joinTable->getInverseJoinColumns() |
|||
391 | 18 | : $joinTable->getJoinColumns(); |
|||
392 | |||||
393 | 18 | $conditions = []; |
|||
394 | |||||
395 | 18 | foreach ($joinColumns as $joinColumn) { |
|||
396 | 18 | $quotedColumnName = $this->platform->quoteIdentifier($joinColumn->getColumnName()); |
|||
397 | 18 | $quotedReferencedColumnName = $this->platform->quoteIdentifier($joinColumn->getReferencedColumnName()); |
|||
398 | |||||
399 | 18 | $conditions[] = ' t.' . $quotedColumnName . ' = te.' . $quotedReferencedColumnName; |
|||
400 | } |
||||
401 | |||||
402 | 18 | return $conditions; |
|||
403 | } |
||||
404 | |||||
405 | /** |
||||
406 | * {@inheritdoc} |
||||
407 | * |
||||
408 | * @override |
||||
409 | */ |
||||
410 | 18 | protected function getDeleteSQL(PersistentCollection $collection) |
|||
411 | { |
||||
412 | 18 | $association = $collection->getMapping(); |
|||
413 | 18 | $joinTable = $association->getJoinTable(); |
|||
414 | 18 | $joinTableName = $joinTable->getQuotedQualifiedName($this->platform); |
|||
415 | 18 | $columns = []; |
|||
416 | |||||
417 | 18 | foreach ($joinTable->getJoinColumns() as $joinColumn) { |
|||
418 | 18 | $columns[] = $this->platform->quoteIdentifier($joinColumn->getColumnName()); |
|||
419 | } |
||||
420 | |||||
421 | 18 | return 'DELETE FROM ' . $joinTableName . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?'; |
|||
422 | } |
||||
423 | |||||
424 | /** |
||||
425 | * {@inheritdoc} |
||||
426 | * |
||||
427 | * {@internal Order of the parameters must be the same as the order of the columns in getDeleteSql. }} |
||||
428 | * |
||||
429 | * @override |
||||
430 | */ |
||||
431 | 18 | protected function getDeleteSQLParameters(PersistentCollection $collection) |
|||
432 | { |
||||
433 | 18 | $association = $collection->getMapping(); |
|||
434 | 18 | $identifier = $this->uow->getEntityIdentifier($collection->getOwner()); |
|||
435 | 18 | $joinTable = $association->getJoinTable(); |
|||
436 | 18 | $joinColumns = $joinTable->getJoinColumns(); |
|||
437 | |||||
438 | // Optimization for single column identifier |
||||
439 | 18 | if (count($joinColumns) === 1) { |
|||
440 | 15 | return [reset($identifier)]; |
|||
441 | } |
||||
442 | |||||
443 | // Composite identifier |
||||
444 | 3 | $sourceClass = $this->em->getClassMetadata($association->getSourceEntity()); |
|||
445 | 3 | $params = []; |
|||
446 | |||||
447 | 3 | foreach ($joinColumns as $joinColumn) { |
|||
448 | 3 | $params[] = $identifier[$sourceClass->fieldNames[$joinColumn->getReferencedColumnName()]]; |
|||
449 | } |
||||
450 | |||||
451 | 3 | return $params; |
|||
452 | } |
||||
453 | |||||
454 | /** |
||||
455 | * Gets the SQL statement used for deleting a row from the collection. |
||||
456 | * |
||||
457 | * @return string[]|string[][] ordered tuple containing the SQL to be executed and an array |
||||
458 | * of types for bound parameters |
||||
459 | */ |
||||
460 | 328 | protected function getDeleteRowSQL(PersistentCollection $collection) |
|||
461 | { |
||||
462 | 328 | $association = $collection->getMapping(); |
|||
463 | 328 | $class = $this->em->getClassMetadata($association->getSourceEntity()); |
|||
464 | 328 | $targetClass = $this->em->getClassMetadata($association->getTargetEntity()); |
|||
465 | 328 | $columns = []; |
|||
466 | 328 | $types = []; |
|||
467 | |||||
468 | 328 | $joinTable = $association->getJoinTable(); |
|||
469 | 328 | $joinTableName = $joinTable->getQuotedQualifiedName($this->platform); |
|||
470 | |||||
471 | 328 | foreach ($joinTable->getJoinColumns() as $joinColumn) { |
|||
472 | /** @var JoinColumnMetadata $joinColumn */ |
||||
473 | 328 | $quotedColumnName = $this->platform->quoteIdentifier($joinColumn->getColumnName()); |
|||
474 | 328 | $referencedColumnName = $joinColumn->getReferencedColumnName(); |
|||
475 | |||||
476 | 328 | if (! $joinColumn->getType()) { |
|||
477 | 34 | $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $class, $this->em)); |
|||
0 ignored issues
–
show
$class of type Doctrine\Common\Persistence\Mapping\ClassMetadata is incompatible with the type Doctrine\ORM\Mapping\ClassMetadata expected by parameter $class of Doctrine\ORM\Utility\Per...lper::getTypeOfColumn() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
478 | } |
||||
479 | |||||
480 | 328 | $columns[] = $quotedColumnName; |
|||
481 | 328 | $types[] = $joinColumn->getType(); |
|||
482 | } |
||||
483 | |||||
484 | 328 | foreach ($joinTable->getInverseJoinColumns() as $joinColumn) { |
|||
485 | /** @var JoinColumnMetadata $joinColumn */ |
||||
486 | 328 | $quotedColumnName = $this->platform->quoteIdentifier($joinColumn->getColumnName()); |
|||
487 | 328 | $referencedColumnName = $joinColumn->getReferencedColumnName(); |
|||
488 | |||||
489 | 328 | if (! $joinColumn->getType()) { |
|||
490 | 34 | $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em)); |
|||
491 | } |
||||
492 | |||||
493 | 328 | $columns[] = $quotedColumnName; |
|||
494 | 328 | $types[] = $joinColumn->getType(); |
|||
495 | } |
||||
496 | |||||
497 | return [ |
||||
498 | 328 | sprintf('DELETE FROM %s WHERE %s = ?', $joinTableName, implode(' = ? AND ', $columns)), |
|||
499 | 328 | $types, |
|||
500 | ]; |
||||
501 | } |
||||
502 | |||||
503 | /** |
||||
504 | * Gets the SQL parameters for the corresponding SQL statement to delete the given |
||||
505 | * element from the given collection. |
||||
506 | * |
||||
507 | * {@internal Order of the parameters must be the same as the order of the columns in getDeleteRowSql. }} |
||||
508 | * |
||||
509 | * @param mixed $element |
||||
510 | * |
||||
511 | * @return mixed[] |
||||
512 | */ |
||||
513 | 10 | protected function getDeleteRowSQLParameters(PersistentCollection $collection, $element) |
|||
514 | { |
||||
515 | 10 | return $this->collectJoinTableColumnParameters($collection, $element); |
|||
516 | } |
||||
517 | |||||
518 | /** |
||||
519 | * Gets the SQL statement used for inserting a row in the collection. |
||||
520 | * |
||||
521 | * @return string[]|string[][] ordered tuple containing the SQL to be executed and an array |
||||
522 | * of types for bound parameters |
||||
523 | */ |
||||
524 | 328 | protected function getInsertRowSQL(PersistentCollection $collection) |
|||
525 | { |
||||
526 | 328 | $association = $collection->getMapping(); |
|||
527 | 328 | $class = $this->em->getClassMetadata($association->getSourceEntity()); |
|||
528 | 328 | $targetClass = $this->em->getClassMetadata($association->getTargetEntity()); |
|||
529 | 328 | $columns = []; |
|||
530 | 328 | $types = []; |
|||
531 | |||||
532 | 328 | $joinTable = $association->getJoinTable(); |
|||
533 | 328 | $joinTableName = $joinTable->getQuotedQualifiedName($this->platform); |
|||
534 | |||||
535 | 328 | foreach ($joinTable->getJoinColumns() as $joinColumn) { |
|||
536 | /** @var JoinColumnMetadata $joinColumn */ |
||||
537 | 328 | $quotedColumnName = $this->platform->quoteIdentifier($joinColumn->getColumnName()); |
|||
538 | 328 | $referencedColumnName = $joinColumn->getReferencedColumnName(); |
|||
539 | |||||
540 | 328 | if (! $joinColumn->getType()) { |
|||
541 | $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $class, $this->em)); |
||||
0 ignored issues
–
show
$class of type Doctrine\Common\Persistence\Mapping\ClassMetadata is incompatible with the type Doctrine\ORM\Mapping\ClassMetadata expected by parameter $class of Doctrine\ORM\Utility\Per...lper::getTypeOfColumn() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
542 | } |
||||
543 | |||||
544 | 328 | $columns[] = $quotedColumnName; |
|||
545 | 328 | $types[] = $joinColumn->getType(); |
|||
546 | } |
||||
547 | |||||
548 | 328 | foreach ($joinTable->getInverseJoinColumns() as $joinColumn) { |
|||
549 | /** @var JoinColumnMetadata $joinColumn */ |
||||
550 | 328 | $quotedColumnName = $this->platform->quoteIdentifier($joinColumn->getColumnName()); |
|||
551 | 328 | $referencedColumnName = $joinColumn->getReferencedColumnName(); |
|||
552 | |||||
553 | 328 | if (! $joinColumn->getType()) { |
|||
554 | $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em)); |
||||
555 | } |
||||
556 | |||||
557 | 328 | $columns[] = $quotedColumnName; |
|||
558 | 328 | $types[] = $joinColumn->getType(); |
|||
559 | } |
||||
560 | |||||
561 | 328 | $columnNamesAsString = implode(', ', $columns); |
|||
562 | 328 | $columnValuesAsString = implode(', ', array_fill(0, count($columns), '?')); |
|||
563 | |||||
564 | return [ |
||||
565 | 328 | sprintf('INSERT INTO %s (%s) VALUES (%s)', $joinTableName, $columnNamesAsString, $columnValuesAsString), |
|||
566 | 328 | $types, |
|||
567 | ]; |
||||
568 | } |
||||
569 | |||||
570 | /** |
||||
571 | * Gets the SQL parameters for the corresponding SQL statement to insert the given |
||||
572 | * element of the given collection into the database. |
||||
573 | * |
||||
574 | * {@internal Order of the parameters must be the same as the order of the columns in getInsertRowSql. }} |
||||
575 | * |
||||
576 | * @param mixed $element |
||||
577 | * |
||||
578 | * @return mixed[] |
||||
579 | */ |
||||
580 | 328 | protected function getInsertRowSQLParameters(PersistentCollection $collection, $element) |
|||
581 | { |
||||
582 | 328 | return $this->collectJoinTableColumnParameters($collection, $element); |
|||
583 | } |
||||
584 | |||||
585 | /** |
||||
586 | * Collects the parameters for inserting/deleting on the join table in the order |
||||
587 | * of the join table columns. |
||||
588 | * |
||||
589 | * @param object $element |
||||
590 | * |
||||
591 | * @return mixed[] |
||||
592 | */ |
||||
593 | 328 | private function collectJoinTableColumnParameters(PersistentCollection $collection, $element) |
|||
594 | { |
||||
595 | 328 | $params = []; |
|||
596 | 328 | $association = $collection->getMapping(); |
|||
597 | 328 | $owningClass = $this->em->getClassMetadata(get_class($collection->getOwner())); |
|||
598 | 328 | $targetClass = $collection->getTypeClass(); |
|||
599 | 328 | $owningIdentifier = $this->uow->getEntityIdentifier($collection->getOwner()); |
|||
600 | 328 | $targetIdentifier = $this->uow->getEntityIdentifier($element); |
|||
601 | 328 | $joinTable = $association->getJoinTable(); |
|||
602 | |||||
603 | 328 | foreach ($joinTable->getJoinColumns() as $joinColumn) { |
|||
604 | 328 | $fieldName = $owningClass->fieldNames[$joinColumn->getReferencedColumnName()]; |
|||
605 | |||||
606 | 328 | $params[] = $owningIdentifier[$fieldName]; |
|||
607 | } |
||||
608 | |||||
609 | 328 | foreach ($joinTable->getInverseJoinColumns() as $joinColumn) { |
|||
610 | 328 | $fieldName = $targetClass->fieldNames[$joinColumn->getReferencedColumnName()]; |
|||
611 | |||||
612 | 328 | $params[] = $targetIdentifier[$fieldName]; |
|||
613 | } |
||||
614 | |||||
615 | 328 | return $params; |
|||
616 | } |
||||
617 | |||||
618 | /** |
||||
619 | * @param string $key |
||||
620 | * @param bool $addFilters Whether the filter SQL should be included or not. |
||||
621 | * |
||||
622 | * @return mixed[] ordered vector: |
||||
623 | * - quoted join table name |
||||
624 | * - where clauses to be added for filtering |
||||
625 | * - parameters to be bound for filtering |
||||
626 | * - types of the parameters to be bound for filtering |
||||
627 | */ |
||||
628 | 7 | private function getJoinTableRestrictionsWithKey(PersistentCollection $collection, $key, $addFilters) |
|||
629 | { |
||||
630 | 7 | $association = $collection->getMapping(); |
|||
631 | 7 | $owningAssociation = $association; |
|||
632 | 7 | $indexBy = $owningAssociation->getIndexedBy(); |
|||
633 | 7 | $identifier = $this->uow->getEntityIdentifier($collection->getOwner()); |
|||
634 | 7 | $sourceClass = $this->em->getClassMetadata($owningAssociation->getSourceEntity()); |
|||
635 | 7 | $targetClass = $this->em->getClassMetadata($owningAssociation->getTargetEntity()); |
|||
636 | |||||
637 | 7 | if (! $owningAssociation->isOwningSide()) { |
|||
638 | 3 | $owningAssociation = $targetClass->getProperty($owningAssociation->getMappedBy()); |
|||
639 | 3 | $joinTable = $owningAssociation->getJoinTable(); |
|||
640 | 3 | $joinColumns = $joinTable->getJoinColumns(); |
|||
641 | 3 | $inverseJoinColumns = $joinTable->getInverseJoinColumns(); |
|||
642 | } else { |
||||
643 | 4 | $joinTable = $owningAssociation->getJoinTable(); |
|||
644 | 4 | $joinColumns = $joinTable->getInverseJoinColumns(); |
|||
645 | 4 | $inverseJoinColumns = $joinTable->getJoinColumns(); |
|||
646 | } |
||||
647 | |||||
648 | 7 | $joinTableName = $joinTable->getQuotedQualifiedName($this->platform); |
|||
649 | 7 | $quotedJoinTable = $joinTableName . ' t'; |
|||
650 | 7 | $whereClauses = []; |
|||
651 | 7 | $params = []; |
|||
652 | 7 | $types = []; |
|||
653 | 7 | $joinNeeded = ! in_array($indexBy, $targetClass->identifier, true); |
|||
654 | |||||
655 | 7 | if ($joinNeeded) { // extra join needed if indexBy is not a @id |
|||
656 | 3 | $joinConditions = []; |
|||
657 | |||||
658 | 3 | foreach ($joinColumns as $joinColumn) { |
|||
659 | /** @var JoinColumnMetadata $joinColumn */ |
||||
660 | 3 | $quotedColumnName = $this->platform->quoteIdentifier($joinColumn->getColumnName()); |
|||
661 | 3 | $quotedReferencedColumnName = $this->platform->quoteIdentifier($joinColumn->getReferencedColumnName()); |
|||
662 | |||||
663 | 3 | $joinConditions[] = ' t.' . $quotedColumnName . ' = tr.' . $quotedReferencedColumnName; |
|||
664 | } |
||||
665 | |||||
666 | 3 | $tableName = $targetClass->table->getQuotedQualifiedName($this->platform); |
|||
667 | 3 | $quotedJoinTable .= ' JOIN ' . $tableName . ' tr ON ' . implode(' AND ', $joinConditions); |
|||
668 | 3 | $indexByProperty = $targetClass->getProperty($indexBy); |
|||
669 | |||||
670 | switch (true) { |
||||
671 | 3 | case $indexByProperty instanceof FieldMetadata: |
|||
672 | 3 | $quotedColumnName = $this->platform->quoteIdentifier($indexByProperty->getColumnName()); |
|||
673 | |||||
674 | 3 | $whereClauses[] = sprintf('tr.%s = ?', $quotedColumnName); |
|||
675 | 3 | $params[] = $key; |
|||
676 | 3 | $types[] = $indexByProperty->getType(); |
|||
677 | 3 | break; |
|||
678 | |||||
679 | case $indexByProperty instanceof ToOneAssociationMetadata && $indexByProperty->isOwningSide(): |
||||
680 | // Cannot be supported because PHP does not accept objects as keys. =( |
||||
681 | break; |
||||
682 | } |
||||
683 | } |
||||
684 | |||||
685 | 7 | foreach ($inverseJoinColumns as $joinColumn) { |
|||
686 | /** @var JoinColumnMetadata $joinColumn */ |
||||
687 | 7 | $quotedColumnName = $this->platform->quoteIdentifier($joinColumn->getColumnName()); |
|||
688 | 7 | $referencedColumnName = $joinColumn->getReferencedColumnName(); |
|||
689 | |||||
690 | 7 | if (! $joinColumn->getType()) { |
|||
691 | $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $sourceClass, $this->em)); |
||||
0 ignored issues
–
show
$sourceClass of type Doctrine\Common\Persistence\Mapping\ClassMetadata is incompatible with the type Doctrine\ORM\Mapping\ClassMetadata expected by parameter $class of Doctrine\ORM\Utility\Per...lper::getTypeOfColumn() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
692 | } |
||||
693 | |||||
694 | 7 | $whereClauses[] = sprintf('t.%s = ?', $quotedColumnName); |
|||
695 | 7 | $params[] = $identifier[$sourceClass->fieldNames[$joinColumn->getReferencedColumnName()]]; |
|||
696 | 7 | $types[] = $joinColumn->getType(); |
|||
697 | } |
||||
698 | |||||
699 | 7 | if (! $joinNeeded) { |
|||
700 | 4 | foreach ($joinColumns as $joinColumn) { |
|||
701 | /** @var JoinColumnMetadata $joinColumn */ |
||||
702 | 4 | $quotedColumnName = $this->platform->quoteIdentifier($joinColumn->getColumnName()); |
|||
703 | 4 | $referencedColumnName = $joinColumn->getReferencedColumnName(); |
|||
704 | |||||
705 | 4 | if (! $joinColumn->getType()) { |
|||
706 | $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em)); |
||||
707 | } |
||||
708 | |||||
709 | 4 | $whereClauses[] = sprintf('t.%s = ?', $quotedColumnName); |
|||
710 | 4 | $params[] = $key; |
|||
711 | 4 | $types[] = $joinColumn->getType(); |
|||
712 | } |
||||
713 | } |
||||
714 | |||||
715 | 7 | if ($addFilters) { |
|||
716 | 7 | [$joinTargetEntitySQL, $filterSql] = $this->getFilterSql($association); |
|||
717 | |||||
718 | 7 | if ($filterSql) { |
|||
719 | $quotedJoinTable .= ' ' . $joinTargetEntitySQL; |
||||
720 | $whereClauses[] = $filterSql; |
||||
721 | } |
||||
722 | } |
||||
723 | |||||
724 | 7 | return [$quotedJoinTable, $whereClauses, $params, $types]; |
|||
725 | } |
||||
726 | |||||
727 | /** |
||||
728 | * @param object $element |
||||
729 | * @param bool $addFilters Whether the filter SQL should be included or not. |
||||
730 | * |
||||
731 | * @return mixed[] ordered vector: |
||||
732 | * - quoted join table name |
||||
733 | * - where clauses to be added for filtering |
||||
734 | * - parameters to be bound for filtering |
||||
735 | * - types of the parameters to be bound for filtering |
||||
736 | */ |
||||
737 | 9 | private function getJoinTableRestrictions(PersistentCollection $collection, $element, $addFilters) |
|||
738 | { |
||||
739 | 9 | $association = $collection->getMapping(); |
|||
740 | 9 | $owningAssociation = $association; |
|||
741 | |||||
742 | 9 | if (! $association->isOwningSide()) { |
|||
743 | 4 | $sourceClass = $this->em->getClassMetadata($association->getTargetEntity()); |
|||
744 | 4 | $targetClass = $this->em->getClassMetadata($association->getSourceEntity()); |
|||
745 | 4 | $sourceIdentifier = $this->uow->getEntityIdentifier($element); |
|||
746 | 4 | $targetIdentifier = $this->uow->getEntityIdentifier($collection->getOwner()); |
|||
747 | |||||
748 | 4 | $owningAssociation = $sourceClass->getProperty($association->getMappedBy()); |
|||
749 | } else { |
||||
750 | 5 | $sourceClass = $this->em->getClassMetadata($association->getSourceEntity()); |
|||
751 | 5 | $targetClass = $this->em->getClassMetadata($association->getTargetEntity()); |
|||
752 | 5 | $sourceIdentifier = $this->uow->getEntityIdentifier($collection->getOwner()); |
|||
753 | 5 | $targetIdentifier = $this->uow->getEntityIdentifier($element); |
|||
754 | } |
||||
755 | |||||
756 | 9 | $joinTable = $owningAssociation->getJoinTable(); |
|||
757 | 9 | $joinTableName = $joinTable->getQuotedQualifiedName($this->platform); |
|||
758 | 9 | $quotedJoinTable = $joinTableName; |
|||
759 | 9 | $whereClauses = []; |
|||
760 | 9 | $params = []; |
|||
761 | 9 | $types = []; |
|||
762 | |||||
763 | 9 | foreach ($joinTable->getJoinColumns() as $joinColumn) { |
|||
764 | /** @var JoinColumnMetadata $joinColumn */ |
||||
765 | 9 | $quotedColumnName = $this->platform->quoteIdentifier($joinColumn->getColumnName()); |
|||
766 | 9 | $referencedColumnName = $joinColumn->getReferencedColumnName(); |
|||
767 | |||||
768 | 9 | if (! $joinColumn->getType()) { |
|||
769 | $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $sourceClass, $this->em)); |
||||
0 ignored issues
–
show
$sourceClass of type Doctrine\Common\Persistence\Mapping\ClassMetadata is incompatible with the type Doctrine\ORM\Mapping\ClassMetadata expected by parameter $class of Doctrine\ORM\Utility\Per...lper::getTypeOfColumn() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
770 | } |
||||
771 | |||||
772 | 9 | $whereClauses[] = ($addFilters ? 't.' : '') . $quotedColumnName . ' = ?'; |
|||
773 | 9 | $params[] = $sourceIdentifier[$sourceClass->fieldNames[$referencedColumnName]]; |
|||
774 | 9 | $types[] = $joinColumn->getType(); |
|||
775 | } |
||||
776 | |||||
777 | 9 | foreach ($joinTable->getInverseJoinColumns() as $joinColumn) { |
|||
778 | /** @var JoinColumnMetadata $joinColumn */ |
||||
779 | 9 | $quotedColumnName = $this->platform->quoteIdentifier($joinColumn->getColumnName()); |
|||
780 | 9 | $referencedColumnName = $joinColumn->getReferencedColumnName(); |
|||
781 | |||||
782 | 9 | if (! $joinColumn->getType()) { |
|||
783 | $joinColumn->setType(PersisterHelper::getTypeOfColumn($referencedColumnName, $targetClass, $this->em)); |
||||
784 | } |
||||
785 | |||||
786 | 9 | $whereClauses[] = ($addFilters ? 't.' : '') . $quotedColumnName . ' = ?'; |
|||
787 | 9 | $params[] = $targetIdentifier[$targetClass->fieldNames[$referencedColumnName]]; |
|||
788 | 9 | $types[] = $joinColumn->getType(); |
|||
789 | } |
||||
790 | |||||
791 | 9 | if ($addFilters) { |
|||
792 | 7 | $quotedJoinTable .= ' t'; |
|||
793 | |||||
794 | 7 | [$joinTargetEntitySQL, $filterSql] = $this->getFilterSql($association); |
|||
795 | |||||
796 | 7 | if ($filterSql) { |
|||
797 | 3 | $quotedJoinTable .= ' ' . $joinTargetEntitySQL; |
|||
798 | 3 | $whereClauses[] = $filterSql; |
|||
799 | } |
||||
800 | } |
||||
801 | |||||
802 | 9 | return [$quotedJoinTable, $whereClauses, $params, $types]; |
|||
803 | } |
||||
804 | |||||
805 | /** |
||||
806 | * Expands Criteria Parameters by walking the expressions and grabbing all |
||||
807 | * parameters and types from it. |
||||
808 | * |
||||
809 | * @return mixed[] |
||||
810 | */ |
||||
811 | 12 | private function expandCriteriaParameters(Criteria $criteria) |
|||
812 | { |
||||
813 | 12 | $expression = $criteria->getWhereExpression(); |
|||
814 | |||||
815 | 12 | if ($expression === null) { |
|||
816 | 5 | return []; |
|||
817 | } |
||||
818 | |||||
819 | 7 | $valueVisitor = new SqlValueVisitor(); |
|||
820 | |||||
821 | 7 | $valueVisitor->dispatch($expression); |
|||
822 | |||||
823 | 7 | [, $types] = $valueVisitor->getParamsAndTypes(); |
|||
824 | |||||
825 | 7 | return $types; |
|||
826 | } |
||||
827 | |||||
828 | /** |
||||
829 | * @return string |
||||
830 | */ |
||||
831 | 12 | private function getOrderingSql(Criteria $criteria, ClassMetadata $targetClass) |
|||
832 | { |
||||
833 | 12 | $orderings = $criteria->getOrderings(); |
|||
834 | |||||
835 | 12 | if ($orderings) { |
|||
836 | 3 | $orderBy = []; |
|||
837 | |||||
838 | 3 | foreach ($orderings as $name => $direction) { |
|||
839 | 3 | $property = $targetClass->getProperty($name); |
|||
840 | 3 | $columnName = $this->platform->quoteIdentifier($property->getColumnName()); |
|||
841 | |||||
842 | 3 | $orderBy[] = $columnName . ' ' . $direction; |
|||
843 | } |
||||
844 | |||||
845 | 3 | return ' ORDER BY ' . implode(', ', $orderBy); |
|||
846 | } |
||||
847 | |||||
848 | 9 | return ''; |
|||
849 | } |
||||
850 | |||||
851 | /** |
||||
852 | * @return string |
||||
853 | * |
||||
854 | * @throws DBALException |
||||
855 | */ |
||||
856 | 12 | private function getLimitSql(Criteria $criteria) |
|||
857 | { |
||||
858 | 12 | $limit = $criteria->getMaxResults(); |
|||
859 | 12 | $offset = $criteria->getFirstResult(); |
|||
860 | 12 | if ($limit !== null || $offset !== null) { |
|||
861 | 3 | return $this->platform->modifyLimitQuery('', $limit, $offset ?? 0); |
|||
862 | } |
||||
863 | |||||
864 | 9 | return ''; |
|||
865 | } |
||||
866 | } |
||||
867 |