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 | 17 | * {@inheritdoc} |
|
| 44 | */ |
||
| 45 | 17 | public function delete(PersistentCollection $collection) |
|
| 46 | { |
||
| 47 | 17 | $mapping = $collection->getMapping(); |
|
| 48 | |||
| 49 | if ( ! $mapping['isOwningSide']) { |
||
| 50 | return; // ignore inverse side |
||
| 51 | 17 | } |
|
| 52 | 17 | ||
| 53 | $types = array(); |
||
| 54 | 17 | $class = $this->em->getClassMetadata($mapping['sourceEntity']); |
|
| 55 | 17 | ||
| 56 | foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { |
||
| 57 | $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $class, $this->em); |
||
|
|
|||
| 58 | 17 | } |
|
| 59 | 17 | ||
| 60 | $this->conn->executeUpdate($this->getDeleteSQL($collection), $this->getDeleteSQLParameters($collection), $types); |
||
| 61 | } |
||
| 62 | |||
| 63 | /** |
||
| 64 | 329 | * {@inheritdoc} |
|
| 65 | */ |
||
| 66 | 329 | public function update(PersistentCollection $collection) |
|
| 67 | { |
||
| 68 | 329 | $mapping = $collection->getMapping(); |
|
| 69 | 231 | ||
| 70 | if ( ! $mapping['isOwningSide']) { |
||
| 71 | return; // ignore inverse side |
||
| 72 | 328 | } |
|
| 73 | 328 | ||
| 74 | list($deleteSql, $deleteTypes) = $this->getDeleteRowSQL($collection); |
||
| 75 | 328 | list($insertSql, $insertTypes) = $this->getInsertRowSQL($collection); |
|
| 76 | 12 | ||
| 77 | foreach ($collection->getDeleteDiff() as $element) { |
||
| 78 | 12 | $this->conn->executeUpdate( |
|
| 79 | $deleteSql, |
||
| 80 | $this->getDeleteRowSQLParameters($collection, $element), |
||
| 81 | $deleteTypes |
||
| 82 | ); |
||
| 83 | 328 | } |
|
| 84 | 328 | ||
| 85 | foreach ($collection->getInsertDiff() as $element) { |
||
| 86 | 328 | $this->conn->executeUpdate( |
|
| 87 | $insertSql, |
||
| 88 | $this->getInsertRowSQLParameters($collection, $element), |
||
| 89 | $insertTypes |
||
| 90 | 328 | ); |
|
| 91 | } |
||
| 92 | } |
||
| 93 | |||
| 94 | /** |
||
| 95 | 3 | * {@inheritdoc} |
|
| 96 | */ |
||
| 97 | 3 | public function get(PersistentCollection $collection, $index) |
|
| 98 | { |
||
| 99 | 3 | $mapping = $collection->getMapping(); |
|
| 100 | |||
| 101 | if ( ! isset($mapping['indexBy'])) { |
||
| 102 | throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); |
||
| 103 | 3 | } |
|
| 104 | 3 | ||
| 105 | 2 | $persister = $this->uow->getEntityPersister($mapping['targetEntity']); |
|
| 106 | 3 | $mappedKey = $mapping['isOwningSide'] |
|
| 107 | ? $mapping['inversedBy'] |
||
| 108 | 3 | : $mapping['mappedBy']; |
|
| 109 | |||
| 110 | return $persister->load(array($mappedKey => $collection->getOwner(), $mapping['indexBy'] => $index), null, $mapping, array(), 0, 1); |
||
| 111 | } |
||
| 112 | |||
| 113 | /** |
||
| 114 | 18 | * {@inheritdoc} |
|
| 115 | */ |
||
| 116 | 18 | public function count(PersistentCollection $collection) |
|
| 117 | 18 | { |
|
| 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 | 4 | $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); |
|
| 125 | 18 | $association = ( ! $mapping['isOwningSide']) |
|
| 126 | ? $targetClass->associationMappings[$mapping['mappedBy']] |
||
| 127 | 18 | : $mapping; |
|
| 128 | 18 | ||
| 129 | 4 | $joinTableName = $this->quoteStrategy->getJoinTableName($association, $sourceClass, $this->platform); |
|
| 130 | 18 | $joinColumns = ( ! $mapping['isOwningSide']) |
|
| 131 | ? $association['joinTable']['inverseJoinColumns'] |
||
| 132 | 18 | : $association['joinTable']['joinColumns']; |
|
| 133 | 18 | ||
| 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 | $params[] = $id[$sourceClass->getFieldForColumn($referencedName)]; |
||
| 139 | $types[] = PersisterHelper::getTypeOfColumn($referencedName, $sourceClass, $this->em); |
||
| 140 | 18 | } |
|
| 141 | |||
| 142 | 18 | list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping); |
|
| 143 | 3 | ||
| 144 | if ($filterSql) { |
||
| 145 | $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 | 18 | ||
| 165 | 18 | $sql = 'SELECT COUNT(*)' |
|
| 166 | 18 | . ' FROM ' . $joinTableName . ' t' |
|
| 167 | . $joinTargetEntitySQL |
||
| 168 | 18 | . ' WHERE ' . implode(' AND ', $conditions); |
|
| 169 | |||
| 170 | return $this->conn->fetchColumn($sql, $params, 0, $types); |
||
| 171 | } |
||
| 172 | |||
| 173 | /** |
||
| 174 | 8 | * {@inheritDoc} |
|
| 175 | */ |
||
| 176 | 8 | public function slice(PersistentCollection $collection, $offset, $length = null) |
|
| 177 | 8 | { |
|
| 178 | $mapping = $collection->getMapping(); |
||
| 179 | 8 | $persister = $this->uow->getEntityPersister($mapping['targetEntity']); |
|
| 180 | |||
| 181 | return $persister->getManyToManyCollection($mapping, $collection->getOwner(), $offset, $length); |
||
| 182 | } |
||
| 183 | /** |
||
| 184 | 7 | * {@inheritdoc} |
|
| 185 | */ |
||
| 186 | 7 | public function containsKey(PersistentCollection $collection, $key) |
|
| 187 | { |
||
| 188 | 7 | $mapping = $collection->getMapping(); |
|
| 189 | |||
| 190 | if ( ! isset($mapping['indexBy'])) { |
||
| 191 | throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); |
||
| 192 | 7 | } |
|
| 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 | return (bool) $this->conn->fetchColumn($sql, $params, 0, $types); |
||
| 199 | } |
||
| 200 | |||
| 201 | /** |
||
| 202 | 7 | * {@inheritDoc} |
|
| 203 | */ |
||
| 204 | 7 | public function contains(PersistentCollection $collection, $element) |
|
| 205 | 2 | { |
|
| 206 | if ( ! $this->isValidEntityState($element)) { |
||
| 207 | return false; |
||
| 208 | 7 | } |
|
| 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 | return (bool) $this->conn->fetchColumn($sql, $params, 0, $types); |
||
| 215 | } |
||
| 216 | |||
| 217 | /** |
||
| 218 | 2 | * {@inheritDoc} |
|
| 219 | */ |
||
| 220 | 2 | public function removeElement(PersistentCollection $collection, $element) |
|
| 221 | 2 | { |
|
| 222 | if ( ! $this->isValidEntityState($element)) { |
||
| 223 | return false; |
||
| 224 | 2 | } |
|
| 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 | return (bool) $this->conn->executeUpdate($sql, $params, $types); |
||
| 231 | } |
||
| 232 | |||
| 233 | /** |
||
| 234 | 7 | * {@inheritDoc} |
|
| 235 | */ |
||
| 236 | 7 | public function loadCriteria(PersistentCollection $collection, Criteria $criteria) |
|
| 237 | 7 | { |
|
| 238 | 7 | $mapping = $collection->getMapping(); |
|
| 239 | 7 | $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); |
|
| 240 | 7 | ||
| 241 | 7 | $queryBuilder = $this->createQueryBuilderForAssociation($collection); |
|
| 242 | 7 | ||
| 243 | if ($whereExpr = $criteria->getWhereExpression()) { |
||
| 244 | 7 | $mappingVisitor = new MappingVisitor( |
|
| 245 | 1 | $this->quoteStrategy, |
|
| 246 | 1 | $targetClass, |
|
| 247 | 1 | $this->platform |
|
| 248 | ); |
||
| 249 | 6 | ||
| 250 | 6 | $mappedExpr = $mappingVisitor->dispatch($criteria->getWhereExpression()); |
|
| 251 | |||
| 252 | $whereClauseExpressionVisitor = new QueryExpressionVisitor(['te']); |
||
| 253 | 7 | $whereExpr = $whereClauseExpressionVisitor->dispatch($mappedExpr); |
|
| 254 | 7 | $queryBuilder->where($whereExpr . ''); |
|
| 255 | 7 | ||
| 256 | /** @var Parameter $parameter */ |
||
| 257 | 7 | foreach($whereClauseExpressionVisitor->getParameters() as $parameter) { |
|
| 258 | $queryBuilder->setParameter($parameter->getName(), $parameter->getValue(), $parameter->getType()); |
||
| 259 | } |
||
| 260 | 7 | } |
|
| 261 | |||
| 262 | 7 | $this->applyCriteriaOrdering($queryBuilder, $criteria, $targetClass); |
|
| 263 | 2 | ||
| 264 | 2 | $this->applyCriteriaLimit($queryBuilder, $criteria); |
|
| 265 | 2 | ||
| 266 | 2 | $rsm = new Query\ResultSetMappingBuilder($this->em); |
|
| 267 | $rsm->addRootEntityFromClassMetadata($targetClass->name, 'te'); |
||
| 268 | |||
| 269 | 7 | $stmt = $queryBuilder->execute(); |
|
| 270 | 7 | ||
| 271 | return $this |
||
| 272 | 7 | ->em |
|
| 273 | 7 | ->newHydrator(Query::HYDRATE_OBJECT) |
|
| 274 | ->hydrateAll($stmt, $rsm); |
||
| 275 | 7 | } |
|
| 276 | 7 | ||
| 277 | 7 | /** |
|
| 278 | 7 | * Generates the filter SQL for a given mapping. |
|
| 279 | 7 | * |
|
| 280 | * This method is not used for actually grabbing the related entities |
||
| 281 | 7 | * 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 | 7 | * have to join in the actual entities table leading to additional |
|
| 284 | * JOIN. |
||
| 285 | 7 | * |
|
| 286 | * @param array $mapping Array containing mapping information. |
||
| 287 | * |
||
| 288 | 7 | * @return string[] ordered tuple: |
|
| 289 | 7 | * - JOIN condition to add to the SQL |
|
| 290 | 7 | * - WHERE condition to add to the SQL |
|
| 291 | */ |
||
| 292 | public function getFilterSql($mapping) |
||
| 293 | { |
||
| 294 | $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); |
||
| 295 | $rootClass = $this->em->getClassMetadata($targetClass->rootEntityName); |
||
| 296 | $filterSql = $this->generateFilterConditionSQL($rootClass, 'te'); |
||
| 297 | |||
| 298 | if ('' === $filterSql) { |
||
| 299 | return array('', ''); |
||
| 300 | } |
||
| 301 | |||
| 302 | // A join is needed if there is filtering on the target entity |
||
| 303 | $tableName = $this->quoteStrategy->getTableName($rootClass, $this->platform); |
||
| 304 | $joinSql = ' JOIN ' . $tableName . ' te' |
||
| 305 | . ' ON' . implode(' AND ', $this->getOnConditionSQL($mapping)); |
||
| 306 | |||
| 307 | return array($joinSql, $filterSql); |
||
| 308 | 32 | } |
|
| 309 | |||
| 310 | 32 | /** |
|
| 311 | 32 | * Generates the filter SQL for a given entity and table alias. |
|
| 312 | 32 | * |
|
| 313 | * @param ClassMetadata $targetEntity Metadata of the target entity. |
||
| 314 | 32 | * @param string $targetTableAlias The table alias of the joined/selected table. |
|
| 315 | 32 | * |
|
| 316 | * @return string The SQL query part to add to a query. |
||
| 317 | */ |
||
| 318 | protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias) |
||
| 319 | 6 | { |
|
| 320 | 6 | $filterClauses = array(); |
|
| 321 | 6 | ||
| 322 | foreach ($this->em->getFilters()->getEnabledFilters() as $filter) { |
||
| 323 | 6 | if ($filterExpr = $filter->addFilterConstraint($targetEntity, $targetTableAlias)) { |
|
| 324 | $filterClauses[] = '(' . $filterExpr . ')'; |
||
| 325 | } |
||
| 326 | } |
||
| 327 | |||
| 328 | return $filterClauses |
||
| 329 | ? '(' . implode(' AND ', $filterClauses) . ')' |
||
| 330 | : ''; |
||
| 331 | } |
||
| 332 | |||
| 333 | /** |
||
| 334 | 32 | * Generate ON condition |
|
| 335 | * |
||
| 336 | 32 | * @param array $mapping |
|
| 337 | * |
||
| 338 | 32 | * @return array |
|
| 339 | 6 | */ |
|
| 340 | 6 | protected function getOnConditionSQL($mapping) |
|
| 341 | { |
||
| 342 | $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); |
||
| 343 | $association = ( ! $mapping['isOwningSide']) |
||
| 344 | 32 | ? $targetClass->associationMappings[$mapping['mappedBy']] |
|
| 345 | 6 | : $mapping; |
|
| 346 | 32 | ||
| 347 | $joinColumns = $mapping['isOwningSide'] |
||
| 348 | ? $association['joinTable']['inverseJoinColumns'] |
||
| 349 | : $association['joinTable']['joinColumns']; |
||
| 350 | |||
| 351 | $conditions = array(); |
||
| 352 | |||
| 353 | foreach ($joinColumns as $joinColumn) { |
||
| 354 | $joinColumnName = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); |
||
| 355 | $refColumnName = $this->quoteStrategy->getReferencedJoinColumnName($joinColumn, $targetClass, $this->platform); |
||
| 356 | 13 | ||
| 357 | $conditions[] = ' t.' . $joinColumnName . ' = ' . 'te.' . $refColumnName; |
||
| 358 | 13 | } |
|
| 359 | 13 | ||
| 360 | 3 | return $conditions; |
|
| 361 | 13 | } |
|
| 362 | |||
| 363 | 13 | /** |
|
| 364 | 10 | * {@inheritdoc} |
|
| 365 | 13 | * |
|
| 366 | * @override |
||
| 367 | 13 | */ |
|
| 368 | protected function getDeleteSQL(PersistentCollection $collection) |
||
| 369 | 13 | { |
|
| 370 | 13 | $columns = array(); |
|
| 371 | 13 | $mapping = $collection->getMapping(); |
|
| 372 | $class = $this->em->getClassMetadata(get_class($collection->getOwner())); |
||
| 373 | 13 | $joinTable = $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform); |
|
| 374 | |||
| 375 | foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { |
||
| 376 | 13 | $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); |
|
| 377 | } |
||
| 378 | |||
| 379 | return 'DELETE FROM ' . $joinTable |
||
| 380 | . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?'; |
||
| 381 | } |
||
| 382 | |||
| 383 | /** |
||
| 384 | 17 | * {@inheritdoc} |
|
| 385 | * |
||
| 386 | 17 | * Internal note: Order of the parameters must be the same as the order of the columns in getDeleteSql. |
|
| 387 | 17 | * @override |
|
| 388 | 17 | */ |
|
| 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 | 17 | return array(reset($identifier)); |
|
| 397 | } |
||
| 398 | |||
| 399 | // Composite identifier |
||
| 400 | $sourceClass = $this->em->getClassMetadata($mapping['sourceEntity']); |
||
| 401 | $params = array(); |
||
| 402 | |||
| 403 | foreach ($mapping['relationToSourceKeyColumns'] as $columnName => $refColumnName) { |
||
| 404 | $params[] = isset($sourceClass->fieldNames[$refColumnName]) |
||
| 405 | 17 | ? $identifier[$sourceClass->fieldNames[$refColumnName]] |
|
| 406 | : $identifier[$sourceClass->getFieldForColumn($columnName)]; |
||
| 407 | 17 | } |
|
| 408 | 17 | ||
| 409 | return $params; |
||
| 410 | } |
||
| 411 | 17 | ||
| 412 | 15 | /** |
|
| 413 | * Gets the SQL statement used for deleting a row from the collection. |
||
| 414 | * |
||
| 415 | * @param \Doctrine\ORM\PersistentCollection $collection |
||
| 416 | 2 | * |
|
| 417 | 2 | * @return string[]|string[][] ordered tuple containing the SQL to be executed and an array |
|
| 418 | * of types for bound parameters |
||
| 419 | 2 | */ |
|
| 420 | 2 | protected function getDeleteRowSQL(PersistentCollection $collection) |
|
| 421 | 1 | { |
|
| 422 | 2 | $mapping = $collection->getMapping(); |
|
| 423 | $class = $this->em->getClassMetadata($mapping['sourceEntity']); |
||
| 424 | $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); |
||
| 425 | 2 | $columns = array(); |
|
| 426 | $types = array(); |
||
| 427 | |||
| 428 | foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { |
||
| 429 | $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); |
||
| 430 | $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $class, $this->em); |
||
| 431 | } |
||
| 432 | |||
| 433 | foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) { |
||
| 434 | $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); |
||
| 435 | $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em); |
||
| 436 | 328 | } |
|
| 437 | |||
| 438 | 328 | return array( |
|
| 439 | 328 | 'DELETE FROM ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform) |
|
| 440 | 328 | . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?', |
|
| 441 | 328 | $types, |
|
| 442 | 328 | ); |
|
| 443 | } |
||
| 444 | 328 | ||
| 445 | 328 | /** |
|
| 446 | 328 | * Gets the SQL parameters for the corresponding SQL statement to delete the given |
|
| 447 | * element from the given collection. |
||
| 448 | * |
||
| 449 | 328 | * Internal note: Order of the parameters must be the same as the order of the columns in getDeleteRowSql. |
|
| 450 | 328 | * |
|
| 451 | 328 | * @param \Doctrine\ORM\PersistentCollection $collection |
|
| 452 | * @param mixed $element |
||
| 453 | * |
||
| 454 | * @return array |
||
| 455 | 328 | */ |
|
| 456 | 328 | 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 | protected function getInsertRowSQL(PersistentCollection $collection) |
||
| 470 | { |
||
| 471 | $columns = array(); |
||
| 472 | 12 | $types = array(); |
|
| 473 | $mapping = $collection->getMapping(); |
||
| 474 | 12 | $class = $this->em->getClassMetadata($mapping['sourceEntity']); |
|
| 475 | $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); |
||
| 476 | |||
| 477 | foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { |
||
| 478 | $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); |
||
| 479 | $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $class, $this->em); |
||
| 480 | } |
||
| 481 | |||
| 482 | foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) { |
||
| 483 | $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); |
||
| 484 | $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em); |
||
| 485 | 328 | } |
|
| 486 | |||
| 487 | 328 | return array( |
|
| 488 | 328 | 'INSERT INTO ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform) |
|
| 489 | 328 | . ' (' . implode(', ', $columns) . ')' |
|
| 490 | 328 | . ' VALUES' |
|
| 491 | 328 | . ' (' . implode(', ', array_fill(0, count($columns), '?')) . ')', |
|
| 492 | $types, |
||
| 493 | 328 | ); |
|
| 494 | 328 | } |
|
| 495 | 328 | ||
| 496 | /** |
||
| 497 | * Gets the SQL parameters for the corresponding SQL statement to insert the given |
||
| 498 | 328 | * element of the given collection into the database. |
|
| 499 | 328 | * |
|
| 500 | 328 | * 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 | 328 | * |
|
| 505 | 328 | * @return array |
|
| 506 | 328 | */ |
|
| 507 | 328 | 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 | private function collectJoinTableColumnParameters(PersistentCollection $collection, $element) |
||
| 522 | { |
||
| 523 | 328 | $params = array(); |
|
| 524 | $mapping = $collection->getMapping(); |
||
| 525 | 328 | $isComposite = count($mapping['joinTableColumns']) > 2; |
|
| 526 | |||
| 527 | $identifier1 = $this->uow->getEntityIdentifier($collection->getOwner()); |
||
| 555 | 307 | ||
| 556 | /** |
||
| 557 | 307 | * @param \Doctrine\ORM\PersistentCollection $collection |
|
| 558 | * @param string $key |
||
| 559 | * @param boolean $addFilters Whether the filter SQL should be included or not. |
||
| 560 | 21 | * |
|
| 561 | 21 | * @return array ordered vector: |
|
| 562 | * - quoted join table name |
||
| 563 | 21 | * - 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 | 21 | */ |
|
| 567 | private function getJoinTableRestrictionsWithKey(PersistentCollection $collection, $key, $addFilters) |
||
| 640 | 4 | ||
| 641 | 7 | /** |
|
| 642 | * @param \Doctrine\ORM\PersistentCollection $collection |
||
| 643 | * @param object $element |
||
| 644 | * @param boolean $addFilters Whether the filter SQL should be included or not. |
||
| 645 | 7 | * |
|
| 646 | 7 | * @return array ordered vector: |
|
| 647 | * - quoted join table name |
||
| 648 | 7 | * - 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 | private function getJoinTableRestrictions(PersistentCollection $collection, $element, $addFilters) |
||
| 706 | 9 | ||
| 707 | /** |
||
| 708 | * @param QueryBuilder $queryBuilder |
||
| 709 | 9 | * @param Criteria $criteria |
|
| 710 | 7 | * @param ClassMetadata $targetClass |
|
| 711 | */ |
||
| 712 | 7 | private function applyCriteriaOrdering(QueryBuilder $queryBuilder, Criteria $criteria, ClassMetadata $targetClass) |
|
| 727 | |||
| 728 | /** |
||
| 729 | * @param QueryBuilder $queryBuilder |
||
| 730 | * @param Criteria $criteria |
||
| 731 | 7 | */ |
|
| 732 | private function applyCriteriaLimit(QueryBuilder $queryBuilder, Criteria $criteria) |
||
| 737 | |||
| 738 | /** |
||
| 739 | 2 | * @param PersistentCollection $collection |
|
| 740 | * @return \Doctrine\DBAL\Query\QueryBuilder |
||
| 741 | 2 | */ |
|
| 742 | 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.