Complex classes like ManyToManyPersister often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use ManyToManyPersister, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
40 | class ManyToManyPersister extends AbstractCollectionPersister |
||
41 | { |
||
42 | /** |
||
43 | * {@inheritdoc} |
||
44 | */ |
||
45 | 17 | public function delete(PersistentCollection $collection) |
|
46 | { |
||
47 | 17 | $mapping = $collection->getMapping(); |
|
48 | |||
49 | 17 | if ( ! $mapping['isOwningSide']) { |
|
50 | return; // ignore inverse side |
||
51 | } |
||
52 | |||
53 | 17 | $types = array(); |
|
54 | 17 | $class = $this->em->getClassMetadata($mapping['sourceEntity']); |
|
55 | |||
56 | 17 | foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { |
|
57 | 17 | $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $class, $this->em); |
|
|
|||
58 | } |
||
59 | |||
60 | 17 | $this->conn->executeUpdate($this->getDeleteSQL($collection), $this->getDeleteSQLParameters($collection), $types); |
|
61 | 17 | } |
|
62 | |||
63 | /** |
||
64 | * {@inheritdoc} |
||
65 | */ |
||
66 | 339 | public function update(PersistentCollection $collection) |
|
67 | { |
||
68 | 339 | $mapping = $collection->getMapping(); |
|
69 | |||
70 | 339 | if ( ! $mapping['isOwningSide']) { |
|
71 | 241 | return; // ignore inverse side |
|
72 | } |
||
73 | |||
74 | 338 | list($deleteSql, $deleteTypes) = $this->getDeleteRowSQL($collection); |
|
75 | 338 | list($insertSql, $insertTypes) = $this->getInsertRowSQL($collection); |
|
76 | |||
77 | 338 | foreach ($collection->getDeleteDiff() as $element) { |
|
78 | 12 | $this->conn->executeUpdate( |
|
79 | $deleteSql, |
||
80 | 12 | $this->getDeleteRowSQLParameters($collection, $element), |
|
81 | $deleteTypes |
||
82 | ); |
||
83 | } |
||
84 | |||
85 | 338 | foreach ($collection->getInsertDiff() as $element) { |
|
86 | 338 | $this->conn->executeUpdate( |
|
87 | $insertSql, |
||
88 | 338 | $this->getInsertRowSQLParameters($collection, $element), |
|
89 | $insertTypes |
||
90 | ); |
||
91 | } |
||
92 | 338 | } |
|
93 | |||
94 | /** |
||
95 | * {@inheritdoc} |
||
96 | */ |
||
97 | 3 | public function get(PersistentCollection $collection, $index) |
|
98 | { |
||
99 | 3 | $mapping = $collection->getMapping(); |
|
100 | |||
101 | 3 | if ( ! isset($mapping['indexBy'])) { |
|
102 | throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); |
||
103 | } |
||
104 | |||
105 | 3 | $persister = $this->uow->getEntityPersister($mapping['targetEntity']); |
|
106 | 3 | $mappedKey = $mapping['isOwningSide'] |
|
107 | 2 | ? $mapping['inversedBy'] |
|
108 | 3 | : $mapping['mappedBy']; |
|
109 | |||
110 | 3 | return $persister->load(array($mappedKey => $collection->getOwner(), $mapping['indexBy'] => $index), null, $mapping, array(), 0, 1); |
|
111 | } |
||
112 | |||
113 | /** |
||
114 | * {@inheritdoc} |
||
115 | */ |
||
116 | 18 | public function count(PersistentCollection $collection) |
|
117 | { |
||
118 | 18 | $conditions = array(); |
|
119 | 18 | $params = array(); |
|
120 | 18 | $types = array(); |
|
121 | 18 | $mapping = $collection->getMapping(); |
|
122 | 18 | $id = $this->uow->getEntityIdentifier($collection->getOwner()); |
|
123 | 18 | $sourceClass = $this->em->getClassMetadata($mapping['sourceEntity']); |
|
124 | 18 | $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); |
|
125 | 18 | $association = ( ! $mapping['isOwningSide']) |
|
126 | 4 | ? $targetClass->associationMappings[$mapping['mappedBy']] |
|
127 | 18 | : $mapping; |
|
128 | |||
129 | 18 | $joinTableName = $this->quoteStrategy->getJoinTableName($association, $sourceClass, $this->platform); |
|
130 | 18 | $joinColumns = ( ! $mapping['isOwningSide']) |
|
131 | 4 | ? $association['joinTable']['inverseJoinColumns'] |
|
132 | 18 | : $association['joinTable']['joinColumns']; |
|
133 | |||
134 | 18 | foreach ($joinColumns as $joinColumn) { |
|
135 | 18 | $columnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $sourceClass, $this->platform); |
|
136 | 18 | $referencedName = $joinColumn['referencedColumnName']; |
|
137 | 18 | $conditions[] = 't.' . $columnName . ' = ?'; |
|
138 | 18 | $params[] = $id[$sourceClass->getFieldForColumn($referencedName)]; |
|
139 | 18 | $types[] = PersisterHelper::getTypeOfColumn($referencedName, $sourceClass, $this->em); |
|
140 | } |
||
141 | |||
142 | 18 | list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping); |
|
143 | |||
144 | 18 | if ($filterSql) { |
|
145 | 3 | $conditions[] = $filterSql; |
|
146 | } |
||
147 | |||
148 | // If there is a provided criteria, make part of conditions |
||
149 | // @todo Fix this. Current SQL returns something like: |
||
150 | // |
||
151 | /*if ($criteria && ($expression = $criteria->getWhereExpression()) !== null) { |
||
152 | // A join is needed on the target entity |
||
153 | $targetTableName = $this->quoteStrategy->getTableName($targetClass, $this->platform); |
||
154 | $targetJoinSql = ' JOIN ' . $targetTableName . ' te' |
||
155 | . ' ON' . implode(' AND ', $this->getOnConditionSQL($association)); |
||
156 | |||
157 | // And criteria conditions needs to be added |
||
158 | $persister = $this->uow->getEntityPersister($targetClass->name); |
||
159 | $visitor = new SqlExpressionVisitor($persister, $targetClass); |
||
160 | $conditions[] = $visitor->dispatch($expression); |
||
161 | |||
162 | $joinTargetEntitySQL = $targetJoinSql . $joinTargetEntitySQL; |
||
163 | }*/ |
||
164 | |||
165 | $sql = 'SELECT COUNT(*)' |
||
166 | 18 | . ' FROM ' . $joinTableName . ' t' |
|
167 | 18 | . $joinTargetEntitySQL |
|
168 | 18 | . ' WHERE ' . implode(' AND ', $conditions); |
|
169 | |||
170 | 18 | return $this->conn->fetchColumn($sql, $params, 0, $types); |
|
171 | } |
||
172 | |||
173 | /** |
||
174 | * {@inheritDoc} |
||
175 | */ |
||
176 | 8 | public function slice(PersistentCollection $collection, $offset, $length = null) |
|
177 | { |
||
178 | 8 | $mapping = $collection->getMapping(); |
|
179 | 8 | $persister = $this->uow->getEntityPersister($mapping['targetEntity']); |
|
180 | |||
181 | 8 | return $persister->getManyToManyCollection($mapping, $collection->getOwner(), $offset, $length); |
|
182 | } |
||
183 | /** |
||
184 | * {@inheritdoc} |
||
185 | */ |
||
186 | 7 | public function containsKey(PersistentCollection $collection, $key) |
|
187 | { |
||
188 | 7 | $mapping = $collection->getMapping(); |
|
189 | |||
190 | 7 | if ( ! isset($mapping['indexBy'])) { |
|
191 | throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); |
||
192 | } |
||
193 | |||
194 | 7 | list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictionsWithKey($collection, $key, true); |
|
195 | |||
196 | 7 | $sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses); |
|
197 | |||
198 | 7 | return (bool) $this->conn->fetchColumn($sql, $params, 0, $types); |
|
199 | } |
||
200 | |||
201 | /** |
||
202 | * {@inheritDoc} |
||
203 | */ |
||
204 | 7 | public function contains(PersistentCollection $collection, $element) |
|
205 | { |
||
206 | 7 | if ( ! $this->isValidEntityState($element)) { |
|
207 | 2 | return false; |
|
208 | } |
||
209 | |||
210 | 7 | list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictions($collection, $element, true); |
|
211 | |||
212 | 7 | $sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses); |
|
213 | |||
214 | 7 | return (bool) $this->conn->fetchColumn($sql, $params, 0, $types); |
|
215 | } |
||
216 | |||
217 | /** |
||
218 | * {@inheritDoc} |
||
219 | */ |
||
220 | 2 | public function removeElement(PersistentCollection $collection, $element) |
|
221 | { |
||
222 | 2 | if ( ! $this->isValidEntityState($element)) { |
|
223 | 2 | return false; |
|
224 | } |
||
225 | |||
226 | 2 | list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictions($collection, $element, false); |
|
227 | |||
228 | 2 | $sql = 'DELETE FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses); |
|
1 ignored issue
–
show
|
|||
229 | |||
230 | 2 | return (bool) $this->conn->executeUpdate($sql, $params, $types); |
|
231 | } |
||
232 | |||
233 | /** |
||
234 | * {@inheritDoc} |
||
235 | */ |
||
236 | 17 | public function loadCriteria(PersistentCollection $collection, Criteria $criteria) |
|
237 | { |
||
238 | 17 | $mapping = $collection->getMapping(); |
|
239 | 17 | $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); |
|
240 | |||
241 | 17 | $queryBuilder = $this->createQueryBuilderForAssociation($collection); |
|
242 | |||
243 | 17 | if ($whereExpr = $criteria->getWhereExpression()) { |
|
244 | 12 | $mappingVisitor = new MappingVisitor( |
|
245 | 12 | $this->quoteStrategy, |
|
246 | $targetClass, |
||
247 | 12 | $this->platform |
|
248 | ); |
||
249 | |||
250 | 12 | $mappedExpr = $mappingVisitor->dispatch($criteria->getWhereExpression()); |
|
251 | |||
252 | 12 | $whereClauseExpressionVisitor = new QueryExpressionVisitor(['te']); |
|
253 | 12 | $whereExpr = $whereClauseExpressionVisitor->dispatch($mappedExpr); |
|
254 | 12 | $queryBuilder->where($whereExpr . ''); |
|
255 | |||
256 | /** @var Parameter $parameter */ |
||
257 | 12 | foreach($whereClauseExpressionVisitor->getParameters() as $parameter) { |
|
258 | 11 | $queryBuilder->setParameter($parameter->getName(), $parameter->getValue(), $parameter->getType()); |
|
259 | } |
||
260 | } |
||
261 | |||
262 | 17 | $this->applyCriteriaOrdering($queryBuilder, $criteria, $targetClass); |
|
263 | |||
264 | 17 | $this->applyCriteriaLimit($queryBuilder, $criteria); |
|
265 | |||
266 | 17 | $rsm = new Query\ResultSetMappingBuilder($this->em); |
|
267 | 17 | $rsm->addRootEntityFromClassMetadata($targetClass->name, 'te'); |
|
268 | |||
269 | 17 | $stmt = $queryBuilder->execute(); |
|
270 | |||
271 | return $this |
||
272 | 17 | ->em |
|
273 | 17 | ->newHydrator(Query::HYDRATE_OBJECT) |
|
274 | 17 | ->hydrateAll($stmt, $rsm); |
|
275 | } |
||
276 | |||
277 | /** |
||
278 | * Generates the filter SQL for a given mapping. |
||
279 | * |
||
280 | * This method is not used for actually grabbing the related entities |
||
281 | * but when the extra-lazy collection methods are called on a filtered |
||
282 | * association. This is why besides the many to many table we also |
||
283 | * have to join in the actual entities table leading to additional |
||
284 | * JOIN. |
||
285 | * |
||
286 | * @param array $mapping Array containing mapping information. |
||
287 | * |
||
288 | * @return string[] ordered tuple: |
||
289 | * - JOIN condition to add to the SQL |
||
290 | * - WHERE condition to add to the SQL |
||
291 | */ |
||
292 | 32 | public function getFilterSql($mapping) |
|
293 | { |
||
294 | 32 | $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); |
|
295 | 32 | $rootClass = $this->em->getClassMetadata($targetClass->rootEntityName); |
|
296 | 32 | $filterSql = $this->generateFilterConditionSQL($rootClass, 'te'); |
|
297 | |||
298 | 32 | if ('' === $filterSql) { |
|
299 | 32 | return array('', ''); |
|
300 | } |
||
301 | |||
302 | // A join is needed if there is filtering on the target entity |
||
303 | 6 | $tableName = $this->quoteStrategy->getTableName($rootClass, $this->platform); |
|
304 | 6 | $joinSql = ' JOIN ' . $tableName . ' te' |
|
305 | 6 | . ' ON' . implode(' AND ', $this->getOnConditionSQL($mapping)); |
|
306 | |||
307 | 6 | return array($joinSql, $filterSql); |
|
308 | } |
||
309 | |||
310 | /** |
||
311 | * Generates the filter SQL for a given entity and table alias. |
||
312 | * |
||
313 | * @param ClassMetadata $targetEntity Metadata of the target entity. |
||
314 | * @param string $targetTableAlias The table alias of the joined/selected table. |
||
315 | * |
||
316 | * @return string The SQL query part to add to a query. |
||
317 | */ |
||
318 | 32 | protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias) |
|
332 | |||
333 | /** |
||
334 | * Generate ON condition |
||
335 | * |
||
336 | * @param array $mapping |
||
337 | * |
||
338 | * @return array |
||
339 | */ |
||
340 | 23 | protected function getOnConditionSQL($mapping) |
|
341 | { |
||
342 | 23 | $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); |
|
343 | 23 | $association = ( ! $mapping['isOwningSide']) |
|
344 | 3 | ? $targetClass->associationMappings[$mapping['mappedBy']] |
|
345 | 23 | : $mapping; |
|
346 | |||
347 | 23 | $joinColumns = $mapping['isOwningSide'] |
|
348 | 20 | ? $association['joinTable']['inverseJoinColumns'] |
|
349 | 23 | : $association['joinTable']['joinColumns']; |
|
350 | |||
351 | 23 | $conditions = array(); |
|
352 | |||
353 | 23 | foreach ($joinColumns as $joinColumn) { |
|
354 | 23 | $joinColumnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); |
|
355 | 23 | $refColumnName = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform); |
|
356 | |||
357 | 23 | $conditions[] = ' t.' . $joinColumnName . ' = ' . 'te.' . $refColumnName; |
|
358 | } |
||
359 | |||
360 | 23 | return $conditions; |
|
361 | } |
||
362 | |||
363 | /** |
||
364 | * {@inheritdoc} |
||
365 | * |
||
366 | * @override |
||
367 | */ |
||
368 | 17 | protected function getDeleteSQL(PersistentCollection $collection) |
|
369 | { |
||
370 | 17 | $columns = array(); |
|
371 | 17 | $mapping = $collection->getMapping(); |
|
372 | 17 | $class = $this->em->getClassMetadata(get_class($collection->getOwner())); |
|
373 | 17 | $joinTable = $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform); |
|
374 | |||
375 | 17 | foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { |
|
376 | 17 | $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); |
|
377 | } |
||
378 | |||
379 | 17 | return 'DELETE FROM ' . $joinTable |
|
380 | 17 | . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?'; |
|
381 | } |
||
382 | |||
383 | /** |
||
384 | * {@inheritdoc} |
||
385 | * |
||
386 | * Internal note: Order of the parameters must be the same as the order of the columns in getDeleteSql. |
||
387 | * @override |
||
388 | */ |
||
389 | 17 | protected function getDeleteSQLParameters(PersistentCollection $collection) |
|
390 | { |
||
391 | 17 | $mapping = $collection->getMapping(); |
|
392 | 17 | $identifier = $this->uow->getEntityIdentifier($collection->getOwner()); |
|
393 | |||
394 | // Optimization for single column identifier |
||
395 | 17 | if (count($mapping['relationToSourceKeyColumns']) === 1) { |
|
396 | 15 | return array(reset($identifier)); |
|
397 | } |
||
398 | |||
399 | // Composite identifier |
||
400 | 2 | $sourceClass = $this->em->getClassMetadata($mapping['sourceEntity']); |
|
401 | 2 | $params = array(); |
|
402 | |||
403 | 2 | foreach ($mapping['relationToSourceKeyColumns'] as $columnName => $refColumnName) { |
|
404 | 2 | $params[] = isset($sourceClass->fieldNames[$refColumnName]) |
|
405 | 1 | ? $identifier[$sourceClass->fieldNames[$refColumnName]] |
|
406 | 2 | : $identifier[$sourceClass->getFieldForColumn($columnName)]; |
|
407 | } |
||
408 | |||
409 | 2 | return $params; |
|
410 | } |
||
411 | |||
412 | /** |
||
413 | * Gets the SQL statement used for deleting a row from the collection. |
||
414 | * |
||
415 | * @param \Doctrine\ORM\PersistentCollection $collection |
||
416 | * |
||
417 | * @return string[]|string[][] ordered tuple containing the SQL to be executed and an array |
||
418 | * of types for bound parameters |
||
419 | */ |
||
420 | 338 | protected function getDeleteRowSQL(PersistentCollection $collection) |
|
421 | { |
||
422 | 338 | $mapping = $collection->getMapping(); |
|
423 | 338 | $class = $this->em->getClassMetadata($mapping['sourceEntity']); |
|
424 | 338 | $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); |
|
425 | 338 | $columns = array(); |
|
426 | 338 | $types = array(); |
|
427 | |||
428 | 338 | foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { |
|
429 | 338 | $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); |
|
430 | 338 | $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $class, $this->em); |
|
431 | } |
||
432 | |||
433 | 338 | foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) { |
|
434 | 338 | $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); |
|
435 | 338 | $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em); |
|
436 | } |
||
437 | |||
438 | return array( |
||
439 | 338 | 'DELETE FROM ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform) |
|
440 | 338 | . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?', |
|
441 | 338 | $types, |
|
442 | ); |
||
443 | } |
||
444 | |||
445 | /** |
||
446 | * Gets the SQL parameters for the corresponding SQL statement to delete the given |
||
447 | * element from the given collection. |
||
448 | * |
||
449 | * Internal note: Order of the parameters must be the same as the order of the columns in getDeleteRowSql. |
||
450 | * |
||
451 | * @param \Doctrine\ORM\PersistentCollection $collection |
||
452 | * @param mixed $element |
||
453 | * |
||
454 | * @return array |
||
455 | */ |
||
456 | 12 | protected function getDeleteRowSQLParameters(PersistentCollection $collection, $element) |
|
460 | |||
461 | /** |
||
462 | * Gets the SQL statement used for inserting a row in the collection. |
||
463 | * |
||
464 | * @param \Doctrine\ORM\PersistentCollection $collection |
||
465 | * |
||
466 | * @return string[]|string[][] ordered tuple containing the SQL to be executed and an array |
||
467 | * of types for bound parameters |
||
468 | */ |
||
469 | 338 | protected function getInsertRowSQL(PersistentCollection $collection) |
|
470 | { |
||
471 | 338 | $columns = array(); |
|
472 | 338 | $types = array(); |
|
473 | 338 | $mapping = $collection->getMapping(); |
|
474 | 338 | $class = $this->em->getClassMetadata($mapping['sourceEntity']); |
|
475 | 338 | $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); |
|
476 | |||
477 | 338 | foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { |
|
478 | 338 | $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); |
|
479 | 338 | $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $class, $this->em); |
|
480 | } |
||
481 | |||
482 | 338 | foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) { |
|
483 | 338 | $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); |
|
484 | 338 | $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em); |
|
485 | } |
||
486 | |||
487 | return array( |
||
488 | 338 | 'INSERT INTO ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform) |
|
489 | 338 | . ' (' . implode(', ', $columns) . ')' |
|
490 | 338 | . ' VALUES' |
|
491 | 338 | . ' (' . implode(', ', array_fill(0, count($columns), '?')) . ')', |
|
492 | 338 | $types, |
|
493 | ); |
||
494 | } |
||
495 | |||
496 | /** |
||
497 | * Gets the SQL parameters for the corresponding SQL statement to insert the given |
||
498 | * element of the given collection into the database. |
||
499 | * |
||
500 | * Internal note: Order of the parameters must be the same as the order of the columns in getInsertRowSql. |
||
501 | * |
||
502 | * @param \Doctrine\ORM\PersistentCollection $collection |
||
503 | * @param mixed $element |
||
504 | * |
||
505 | * @return array |
||
506 | */ |
||
507 | 338 | protected function getInsertRowSQLParameters(PersistentCollection $collection, $element) |
|
511 | |||
512 | /** |
||
513 | * Collects the parameters for inserting/deleting on the join table in the order |
||
514 | * of the join table columns as specified in ManyToManyMapping#joinTableColumns. |
||
515 | * |
||
516 | * @param \Doctrine\ORM\PersistentCollection $collection |
||
517 | * @param object $element |
||
518 | * |
||
519 | * @return array |
||
520 | */ |
||
521 | 338 | private function collectJoinTableColumnParameters(PersistentCollection $collection, $element) |
|
555 | |||
556 | /** |
||
557 | * @param \Doctrine\ORM\PersistentCollection $collection |
||
558 | * @param string $key |
||
559 | * @param boolean $addFilters Whether the filter SQL should be included or not. |
||
560 | * |
||
561 | * @return array ordered vector: |
||
562 | * - quoted join table name |
||
563 | * - where clauses to be added for filtering |
||
564 | * - parameters to be bound for filtering |
||
565 | * - types of the parameters to be bound for filtering |
||
566 | */ |
||
567 | 7 | private function getJoinTableRestrictionsWithKey(PersistentCollection $collection, $key, $addFilters) |
|
640 | |||
641 | /** |
||
642 | * @param \Doctrine\ORM\PersistentCollection $collection |
||
643 | * @param object $element |
||
644 | * @param boolean $addFilters Whether the filter SQL should be included or not. |
||
645 | * |
||
646 | * @return array ordered vector: |
||
647 | * - quoted join table name |
||
648 | * - where clauses to be added for filtering |
||
649 | * - parameters to be bound for filtering |
||
650 | * - types of the parameters to be bound for filtering |
||
651 | */ |
||
652 | 9 | private function getJoinTableRestrictions(PersistentCollection $collection, $element, $addFilters) |
|
706 | |||
707 | /** |
||
708 | * @param QueryBuilder $queryBuilder |
||
709 | * @param Criteria $criteria |
||
710 | * @param ClassMetadata $targetClass |
||
711 | */ |
||
712 | 17 | private function applyCriteriaOrdering(QueryBuilder $queryBuilder, Criteria $criteria, ClassMetadata $targetClass) |
|
727 | |||
728 | /** |
||
729 | * @param QueryBuilder $queryBuilder |
||
730 | * @param Criteria $criteria |
||
731 | */ |
||
732 | 17 | private function applyCriteriaLimit(QueryBuilder $queryBuilder, Criteria $criteria) |
|
737 | |||
738 | /** |
||
739 | * @param PersistentCollection $collection |
||
740 | * @return \Doctrine\DBAL\Query\QueryBuilder |
||
741 | */ |
||
742 | 17 | private function createQueryBuilderForAssociation(PersistentCollection $collection) |
|
783 | } |
||
784 |
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.
Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.