diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index 769b80f25..bbfae15f0 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -1998,7 +1998,10 @@ class ClassMetadataInfo implements ClassMetadata * * @param string $columnName * - * @return \Doctrine\DBAL\Types\Type + * @return \Doctrine\DBAL\Types\Type|string|null + * + * @deprecated this method is bogous and unreliable, since it cannot resolve the type of a column that is + * derived by a referenced field on a different entity. */ public function getTypeOfColumn($columnName) { diff --git a/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php b/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php index 40b1be958..a421b9112 100644 --- a/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php @@ -25,6 +25,7 @@ use Doctrine\ORM\Persisters\SqlExpressionVisitor; use Doctrine\ORM\Persisters\SqlValueVisitor; use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\Query; +use Doctrine\ORM\Utility\PersisterHelper; /** * Persister for many-to-many collections. @@ -61,15 +62,23 @@ class ManyToManyPersister extends AbstractCollectionPersister return; // ignore inverse side } - $insertSql = $this->getInsertRowSQL($collection); - $deleteSql = $this->getDeleteRowSQL($collection); + list($deleteSql, $deleteTypes) = $this->getDeleteRowSQL($collection); + list($insertSql, $insertTypes) = $this->getInsertRowSQL($collection); foreach ($collection->getDeleteDiff() as $element) { - $this->conn->executeUpdate($deleteSql, $this->getDeleteRowSQLParameters($collection, $element)); + $this->conn->executeUpdate( + $deleteSql, + $this->getDeleteRowSQLParameters($collection, $element), + $deleteTypes + ); } foreach ($collection->getInsertDiff() as $element) { - $this->conn->executeUpdate($insertSql, $this->getInsertRowSQLParameters($collection, $element)); + $this->conn->executeUpdate( + $insertSql, + $this->getInsertRowSQLParameters($collection, $element), + $insertTypes + ); } } @@ -99,6 +108,7 @@ class ManyToManyPersister extends AbstractCollectionPersister { $conditions = array(); $params = array(); + $types = array(); $mapping = $collection->getMapping(); $id = $this->uow->getEntityIdentifier($collection->getOwner()); $sourceClass = $this->em->getClassMetadata($mapping['sourceEntity']); @@ -117,6 +127,7 @@ class ManyToManyPersister extends AbstractCollectionPersister $referencedName = $joinColumn['referencedColumnName']; $conditions[] = 't.' . $columnName . ' = ?'; $params[] = $id[$sourceClass->getFieldForColumn($referencedName)]; + $types[] = PersisterHelper::getTypeOfColumn($referencedName, $sourceClass, $this->em); } list($joinTargetEntitySQL, $filterSql) = $this->getFilterSql($mapping); @@ -147,7 +158,7 @@ class ManyToManyPersister extends AbstractCollectionPersister . $joinTargetEntitySQL . ' WHERE ' . implode(' AND ', $conditions); - return $this->conn->fetchColumn($sql, $params); + return $this->conn->fetchColumn($sql, $params, 0, $types); } /** @@ -171,11 +182,11 @@ class ManyToManyPersister extends AbstractCollectionPersister throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); } - list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictionsWithKey($collection, $key, true); + list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictionsWithKey($collection, $key, true); $sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses); - return (bool) $this->conn->fetchColumn($sql, $params); + return (bool) $this->conn->fetchColumn($sql, $params, 0, $types); } /** @@ -187,11 +198,11 @@ class ManyToManyPersister extends AbstractCollectionPersister return false; } - list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictions($collection, $element, true); + list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictions($collection, $element, true); $sql = 'SELECT 1 FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses); - return (bool) $this->conn->fetchColumn($sql, $params); + return (bool) $this->conn->fetchColumn($sql, $params, 0, $types); } /** @@ -203,11 +214,11 @@ class ManyToManyPersister extends AbstractCollectionPersister return false; } - list($quotedJoinTable, $whereClauses, $params) = $this->getJoinTableRestrictions($collection, $element, false); + list($quotedJoinTable, $whereClauses, $params, $types) = $this->getJoinTableRestrictions($collection, $element, false); $sql = 'DELETE FROM ' . $quotedJoinTable . ' WHERE ' . implode(' AND ', $whereClauses); - return (bool) $this->conn->executeUpdate($sql, $params); + return (bool) $this->conn->executeUpdate($sql, $params, $types); } /** @@ -397,24 +408,32 @@ class ManyToManyPersister extends AbstractCollectionPersister * * @param \Doctrine\ORM\PersistentCollection $collection * - * @return string + * @return string[]|string[][] ordered tuple containing the SQL to be executed and an array + * of types for bound parameters */ protected function getDeleteRowSQL(PersistentCollection $collection) { - $mapping = $collection->getMapping(); - $class = $this->em->getClassMetadata($mapping['sourceEntity']); - $columns = array(); + $mapping = $collection->getMapping(); + $class = $this->em->getClassMetadata($mapping['sourceEntity']); + $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); + $columns = array(); + $types = array(); foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); + $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $class, $this->em); } foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) { - $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); + $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); + $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em); } - return 'DELETE FROM ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform) - . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?'; + return array( + 'DELETE FROM ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform) + . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?', + $types, + ); } /** @@ -438,26 +457,34 @@ class ManyToManyPersister extends AbstractCollectionPersister * * @param \Doctrine\ORM\PersistentCollection $collection * - * @return string + * @return string[]|string[][] ordered tuple containing the SQL to be executed and an array + * of types for bound parameters */ protected function getInsertRowSQL(PersistentCollection $collection) { - $columns = array(); - $mapping = $collection->getMapping(); - $class = $this->em->getClassMetadata($mapping['sourceEntity']); + $columns = array(); + $types = array(); + $mapping = $collection->getMapping(); + $class = $this->em->getClassMetadata($mapping['sourceEntity']); + $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) { - $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); + $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); + $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $class, $this->em); } foreach ($mapping['joinTable']['inverseJoinColumns'] as $joinColumn) { - $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $class, $this->platform); + $columns[] = $this->quoteStrategy->getJoinColumnName($joinColumn, $targetClass, $this->platform); + $types[] = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em); } - return 'INSERT INTO ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform) + return array( + 'INSERT INTO ' . $this->quoteStrategy->getJoinTableName($mapping, $class, $this->platform) . ' (' . implode(', ', $columns) . ')' . ' VALUES' - . ' (' . implode(', ', array_fill(0, count($columns), '?')) . ')'; + . ' (' . implode(', ', array_fill(0, count($columns), '?')) . ')', + $types, + ); } /** @@ -525,33 +552,40 @@ class ManyToManyPersister extends AbstractCollectionPersister * @param string $key * @param boolean $addFilters Whether the filter SQL should be included or not. * - * @return array + * @return array ordered vector: + * - quoted join table name + * - where clauses to be added for filtering + * - parameters to be bound for filtering + * - types of the parameters to be bound for filtering */ private function getJoinTableRestrictionsWithKey(PersistentCollection $collection, $key, $addFilters) { - $filterMapping = $collection->getMapping(); - $mapping = $filterMapping; - $indexBy = $mapping['indexBy']; - $id = $this->uow->getEntityIdentifier($collection->getOwner()); - - $targetEntity = $this->em->getClassMetadata($mapping['targetEntity']); + $filterMapping = $collection->getMapping(); + $mapping = $filterMapping; + $indexBy = $mapping['indexBy']; + $id = $this->uow->getEntityIdentifier($collection->getOwner()); + $sourceClass = $this->em->getClassMetadata($mapping['sourceEntity']); + $targetClass = $this->em->getClassMetadata($mapping['targetEntity']); if (! $mapping['isOwningSide']) { $associationSourceClass = $this->em->getClassMetadata($mapping['targetEntity']); - $mapping = $associationSourceClass->associationMappings[$mapping['mappedBy']]; - $joinColumns = $mapping['joinTable']['joinColumns']; - $relationMode = 'relationToTargetKeyColumns'; + $mapping = $associationSourceClass->associationMappings[$mapping['mappedBy']]; + $joinColumns = $mapping['joinTable']['joinColumns']; + $sourceRelationMode = 'relationToTargetKeyColumns'; + $targetRelationMode = 'relationToSourceKeyColumns'; } else { - $joinColumns = $mapping['joinTable']['inverseJoinColumns']; $associationSourceClass = $this->em->getClassMetadata($mapping['sourceEntity']); - $relationMode = 'relationToSourceKeyColumns'; + $joinColumns = $mapping['joinTable']['inverseJoinColumns']; + $sourceRelationMode = 'relationToSourceKeyColumns'; + $targetRelationMode = 'relationToTargetKeyColumns'; } $quotedJoinTable = $this->quoteStrategy->getJoinTableName($mapping, $associationSourceClass, $this->platform). ' t'; $whereClauses = array(); $params = array(); + $types = array(); - $joinNeeded = !in_array($indexBy, $targetEntity->identifier); + $joinNeeded = ! in_array($indexBy, $targetClass->identifier); if ($joinNeeded) { // extra join needed if indexBy is not a @id $joinConditions = array(); @@ -559,21 +593,30 @@ class ManyToManyPersister extends AbstractCollectionPersister foreach ($joinColumns as $joinTableColumn) { $joinConditions[] = 't.' . $joinTableColumn['name'] . ' = tr.' . $joinTableColumn['referencedColumnName']; } - $tableName = $this->quoteStrategy->getTableName($targetEntity, $this->platform); + + $tableName = $this->quoteStrategy->getTableName($targetClass, $this->platform); $quotedJoinTable .= ' JOIN ' . $tableName . ' tr ON ' . implode(' AND ', $joinConditions); + $columnName = $targetClass->getColumnName($indexBy); - $whereClauses[] = 'tr.' . $targetEntity->getColumnName($indexBy) . ' = ?'; - $params[] = $key; - + $whereClauses[] = 'tr.' . $columnName . ' = ?'; + $params[] = $key; + $types[] = PersisterHelper::getTypeOfColumn($columnName, $targetClass, $this->em); } foreach ($mapping['joinTableColumns'] as $joinTableColumn) { - if (isset($mapping[$relationMode][$joinTableColumn])) { + if (isset($mapping[$sourceRelationMode][$joinTableColumn])) { + $column = $mapping[$sourceRelationMode][$joinTableColumn]; $whereClauses[] = 't.' . $joinTableColumn . ' = ?'; - $params[] = $id[$targetEntity->getFieldForColumn($mapping[$relationMode][$joinTableColumn])]; - } elseif (!$joinNeeded) { + $params[] = $sourceClass->containsForeignIdentifier + ? $id[$sourceClass->getFieldForColumn($column)] + : $id[$sourceClass->fieldNames[$column]]; + $types[] = PersisterHelper::getTypeOfColumn($column, $sourceClass, $this->em); + } elseif ( ! $joinNeeded) { + $column = $mapping[$targetRelationMode][$joinTableColumn]; + $whereClauses[] = 't.' . $joinTableColumn . ' = ?'; - $params[] = $key; + $params[] = $key; + $types[] = PersisterHelper::getTypeOfColumn($column, $targetClass, $this->em); } } @@ -586,7 +629,7 @@ class ManyToManyPersister extends AbstractCollectionPersister } } - return array($quotedJoinTable, $whereClauses, $params); + return array($quotedJoinTable, $whereClauses, $params, $types); } /** @@ -594,7 +637,11 @@ class ManyToManyPersister extends AbstractCollectionPersister * @param object $element * @param boolean $addFilters Whether the filter SQL should be included or not. * - * @return array + * @return array ordered vector: + * - quoted join table name + * - where clauses to be added for filtering + * - parameters to be bound for filtering + * - types of the parameters to be bound for filtering */ private function getJoinTableRestrictions(PersistentCollection $collection, $element, $addFilters) { @@ -618,18 +665,23 @@ class ManyToManyPersister extends AbstractCollectionPersister $quotedJoinTable = $this->quoteStrategy->getJoinTableName($mapping, $sourceClass, $this->platform); $whereClauses = array(); $params = array(); + $types = array(); foreach ($mapping['joinTableColumns'] as $joinTableColumn) { $whereClauses[] = ($addFilters ? 't.' : '') . $joinTableColumn . ' = ?'; if (isset($mapping['relationToTargetKeyColumns'][$joinTableColumn])) { - $params[] = $targetId[$targetClass->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])]; + $targetColumn = $mapping['relationToTargetKeyColumns'][$joinTableColumn]; + $params[] = $targetId[$targetClass->getFieldForColumn($targetColumn)]; + $types[] = PersisterHelper::getTypeOfColumn($targetColumn, $targetClass, $this->em); continue; } // relationToSourceKeyColumns - $params[] = $sourceId[$sourceClass->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])]; + $targetColumn = $mapping['relationToSourceKeyColumns'][$joinTableColumn]; + $params[] = $sourceId[$sourceClass->getFieldForColumn($targetColumn)]; + $types[] = PersisterHelper::getTypeOfColumn($targetColumn, $sourceClass, $this->em); } if ($addFilters) { @@ -643,7 +695,7 @@ class ManyToManyPersister extends AbstractCollectionPersister } } - return array($quotedJoinTable, $whereClauses, $params); + return array($quotedJoinTable, $whereClauses, $params, $types); } /** diff --git a/lib/Doctrine/ORM/Persisters/Collection/OneToManyPersister.php b/lib/Doctrine/ORM/Persisters/Collection/OneToManyPersister.php index ee550a922..9b14afde5 100644 --- a/lib/Doctrine/ORM/Persisters/Collection/OneToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/Collection/OneToManyPersister.php @@ -67,7 +67,17 @@ class OneToManyPersister extends AbstractCollectionPersister $persister = $this->uow->getEntityPersister($mapping['targetEntity']); - return $persister->load(array($mapping['mappedBy'] => $collection->getOwner(), $mapping['indexBy'] => $index), null, $mapping, array(), null, 1); + return $persister->load( + array( + $mapping['mappedBy'] => $collection->getOwner(), + $mapping['indexBy'] => $index + ), + null, + $mapping, + array(), + null, + 1 + ); } /** diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index 537961420..c53e817c1 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -36,6 +36,7 @@ use Doctrine\ORM\Persisters\SqlValueVisitor; use Doctrine\ORM\Query; use Doctrine\ORM\UnitOfWork; use Doctrine\ORM\Utility\IdentifierFlattener; +use Doctrine\ORM\Utility\PersisterHelper; /** * A BasicEntityPersister maps an entity to a single table in a relational database. @@ -610,15 +611,16 @@ class BasicEntityPersister implements EntityPersister */ protected function prepareUpdateData($entity) { - $result = array(); - $uow = $this->em->getUnitOfWork(); + $versionField = null; + $result = array(); + $uow = $this->em->getUnitOfWork(); if (($versioned = $this->class->isVersioned) != false) { $versionField = $this->class->versionField; } foreach ($uow->getEntityChangeSet($entity) as $field => $change) { - if ($versioned && $versionField == $field) { + if (isset($versionField) && $versionField == $field) { continue; } @@ -668,7 +670,7 @@ class BasicEntityPersister implements EntityPersister $quotedColumn = $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform); $this->quotedColumns[$sourceColumn] = $quotedColumn; - $this->columnTypes[$sourceColumn] = $targetClass->getTypeOfColumn($targetColumn); + $this->columnTypes[$sourceColumn] = PersisterHelper::getTypeOfColumn($targetColumn, $targetClass, $this->em); $result[$owningTable][$sourceColumn] = $newValId ? $newValId[$targetClass->getFieldForColumn($targetColumn)] : null; @@ -862,12 +864,12 @@ class BasicEntityPersister implements EntityPersister list($params, $types) = $valueVisitor->getParamsAndTypes(); foreach ($params as $param) { - $sqlParams[] = $this->getValue($param); + $sqlParams[] = PersisterHelper::getIdentifierValues($param, $this->em); } foreach ($types as $type) { list($field, $value) = $type; - $sqlTypes[] = $this->getType($field, $value); + $sqlTypes[] = $this->getType($field, $value, $this->class); } return array($sqlParams, $sqlTypes); @@ -969,7 +971,7 @@ class BasicEntityPersister implements EntityPersister $class = $sourceClass; $association = $assoc; $criteria = array(); - + $parameters = array(); if ( ! $assoc['isOwningSide']) { $class = $this->em->getClassMetadata($assoc['targetEntity']); @@ -1012,10 +1014,15 @@ class BasicEntityPersister implements EntityPersister } $criteria[$quotedJoinTable . '.' . $quotedKeyColumn] = $value; + $parameters[] = array( + 'value' => $value, + 'field' => $field, + 'class' => $sourceClass, + ); } $sql = $this->getSelectSQL($criteria, $assoc, null, $limit, $offset); - list($params, $types) = $this->expandParameters($criteria); + list($params, $types) = $this->expandToManyParameters($parameters); return $this->conn->executeQuery($sql, $params, $types); } @@ -1309,10 +1316,7 @@ class BasicEntityPersister implements EntityPersister $resultColumnName = $this->getSQLColumnAlias($joinColumn['name']); $columnList[] = $this->getSQLTableAlias($class->name, ($alias == 'r' ? '' : $alias) ) . '.' . $quotedColumn . ' AS ' . $resultColumnName; - - if (isset($targetClass->fieldNames[$joinColumn['referencedColumnName']])) { - $type = $targetClass->fieldMappings[$targetClass->fieldNames[$joinColumn['referencedColumnName']]]['type']; - } + $type = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em); $this->rsm->addMetaResult($alias, $resultColumnName, $quotedColumn, $isIdentifier, $type); } @@ -1426,7 +1430,7 @@ class BasicEntityPersister implements EntityPersister } if ($this->class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $this->class->identifier[0] != $name) { - $columns[] = $this->quoteStrategy->getColumnName($name, $this->class, $this->platform); + $columns[] = $this->quoteStrategy->getColumnName($name, $this->class, $this->platform); $this->columnTypes[$name] = $this->class->fieldMappings[$name]['type']; } } @@ -1713,7 +1717,8 @@ class BasicEntityPersister implements EntityPersister */ private function getOneToManyStatement(array $assoc, $sourceEntity, $offset = null, $limit = null) { - $criteria = array(); + $criteria = array(); + $parameters = array(); $owningAssoc = $this->class->associationMappings[$assoc['mappedBy']]; $sourceClass = $this->em->getClassMetadata($assoc['sourceEntity']); @@ -1730,15 +1735,29 @@ class BasicEntityPersister implements EntityPersister } $criteria[$tableAlias . "." . $targetKeyColumn] = $value; + $parameters[] = array( + 'value' => $value, + 'field' => $field, + 'class' => $sourceClass, + ); continue; } - $criteria[$tableAlias . "." . $targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity); + $field = $sourceClass->fieldNames[$sourceKeyColumn]; + $value = $sourceClass->reflFields[$field]->getValue($sourceEntity); + + $criteria[$tableAlias . "." . $targetKeyColumn] = $value; + $parameters[] = array( + 'value' => $value, + 'field' => $field, + 'class' => $sourceClass, + ); + } - $sql = $this->getSelectSQL($criteria, $assoc, null, $limit, $offset); - list($params, $types) = $this->expandParameters($criteria); + $sql = $this->getSelectSQL($criteria, $assoc, null, $limit, $offset); + list($params, $types) = $this->expandToManyParameters($parameters); return $this->conn->executeQuery($sql, $params, $types); } @@ -1756,72 +1775,56 @@ class BasicEntityPersister implements EntityPersister continue; // skip null values. } - $types[] = $this->getType($field, $value); + $types[] = $this->getType($field, $value, $this->class); $params[] = $this->getValue($value); } return array($params, $types); } + /** + * Expands the parameters from the given criteria and use the correct binding types if found, + * specialized for OneToMany or ManyToMany associations. + * + * @param mixed[][] $criteria an array of arrays containing following: + * - field to which each criterion will be bound + * - value to be bound + * - class to which the field belongs to + * + * + * @return array + */ + private function expandToManyParameters($criteria) + { + $params = array(); + $types = array(); + + foreach ($criteria as $criterion) { + if ($criterion['value'] === null) { + continue; // skip null values. + } + + $types[] = $this->getType($criterion['field'], $criterion['value'], $criterion['class']); + $params[] = PersisterHelper::getIdentifierValues($criterion['value'], $this->em); + } + + return array($params, $types); + } + /** * Infers field type to be used by parameter type casting. * - * @param string $field - * @param mixed $value + * @param string $fieldName + * @param mixed $value + * @param ClassMetadata $class * * @return integer * * @throws \Doctrine\ORM\Query\QueryException */ - private function getType($field, $value) + private function getType($fieldName, $value, ClassMetadata $class) { - switch (true) { - case (isset($this->class->fieldMappings[$field])): - $type = $this->class->fieldMappings[$field]['type']; - break; - - case (isset($this->class->associationMappings[$field]) && $this->class->associationMappings[$field]['type'] === ClassMetadata::MANY_TO_MANY): - $assoc = $this->class->associationMappings[$field]; - $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); - - if ( ! $assoc['isOwningSide']) { - $assoc = $targetClass->associationMappings[$assoc['mappedBy']]; - } - - if (count($assoc['relationToTargetKeyColumns']) > 1) { - throw Query\QueryException::associationPathCompositeKeyNotSupported(); - } - - $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); - $targetColumn = $assoc['joinTable']['inverseJoinColumns'][0]['referencedColumnName']; - $type = null; - - if (isset($targetClass->fieldNames[$targetColumn])) { - $type = $targetClass->fieldMappings[$targetClass->fieldNames[$targetColumn]]['type']; - } - - break; - - case (isset($this->class->associationMappings[$field])): - $assoc = $this->class->associationMappings[$field]; - - if (count($assoc['sourceToTargetKeyColumns']) > 1) { - throw Query\QueryException::associationPathCompositeKeyNotSupported(); - } - - $targetClass = $this->em->getClassMetadata($assoc['targetEntity']); - $targetColumn = $assoc['joinColumns'][0]['referencedColumnName']; - $type = null; - - if (isset($targetClass->fieldNames[$targetColumn])) { - $type = $targetClass->fieldMappings[$targetClass->fieldNames[$targetColumn]]['type']; - } - - break; - - default: - $type = null; - } + $type = PersisterHelper::getTypeOfField($fieldName, $class, $this->em); if (is_array($value)) { $type = Type::getType($type)->getBindingType(); @@ -1886,20 +1889,21 @@ class BasicEntityPersister implements EntityPersister . $this->getLockTablesSql(null) . ' WHERE ' . $this->getSelectConditionSQL($criteria); - list($params) = $this->expandParameters($criteria); + list($params, $types) = $this->expandParameters($criteria); if (null !== $extraConditions) { - $sql .= ' AND ' . $this->getSelectConditionCriteriaSQL($extraConditions); - list($criteriaParams, $values) = $this->expandCriteriaParameters($extraConditions); + $sql .= ' AND ' . $this->getSelectConditionCriteriaSQL($extraConditions); + list($criteriaParams, $criteriaTypes) = $this->expandCriteriaParameters($extraConditions); $params = array_merge($params, $criteriaParams); + $types = array_merge($types, $criteriaTypes); } if ($filterSql = $this->generateFilterConditionSQL($this->class, $alias)) { $sql .= ' AND ' . $filterSql; } - return (bool) $this->conn->fetchColumn($sql, $params); + return (bool) $this->conn->fetchColumn($sql, $params, 0, $types); } /** diff --git a/lib/Doctrine/ORM/Utility/PersisterHelper.php b/lib/Doctrine/ORM/Utility/PersisterHelper.php new file mode 100644 index 000000000..6c3af11da --- /dev/null +++ b/lib/Doctrine/ORM/Utility/PersisterHelper.php @@ -0,0 +1,172 @@ +. + */ + +namespace Doctrine\ORM\Utility; + +use Doctrine\Common\Util\ClassUtils; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Query\QueryException; + +/** + * The PersisterHelper contains logic to infer binding types which is used in + * several persisters. + * + * @link www.doctrine-project.org + * @since 2.5 + * @author Jasper N. Brouwer + */ +class PersisterHelper +{ + /** + * @param string $fieldName + * @param ClassMetadata $class + * @param EntityManagerInterface $em + * + * @return string|null + * + * @throws QueryException + */ + public static function getTypeOfField($fieldName, ClassMetadata $class, EntityManagerInterface $em) + { + if (isset($class->fieldMappings[$fieldName])) { + return $class->fieldMappings[$fieldName]['type']; + } + + if ( ! isset($class->associationMappings[$fieldName])) { + return null; + } + + $assoc = $class->associationMappings[$fieldName]; + + if (! $assoc['isOwningSide']) { + return self::getTypeOfField($assoc['mappedBy'], $em->getClassMetadata($assoc['targetEntity']), $em); + } + + if (($assoc['type'] & ClassMetadata::MANY_TO_MANY) > 0) { + $joinData = $assoc['joinTable']; + } else { + $joinData = $assoc; + } + + if (count($joinData['joinColumns']) > 1) { + throw QueryException::associationPathCompositeKeyNotSupported(); + } + + $targetColumnName = $joinData['joinColumns'][0]['referencedColumnName']; + $targetClass = $em->getClassMetadata($assoc['targetEntity']); + + return self::getTypeOfColumn($targetColumnName, $targetClass, $em); + } + + /** + * @param string $columnName + * @param ClassMetadata $class + * @param EntityManagerInterface $em + * + * @return string + * + * @throws \RuntimeException + */ + public static function getTypeOfColumn($columnName, ClassMetadata $class, EntityManagerInterface $em) + { + if (isset($class->fieldNames[$columnName])) { + $fieldName = $class->fieldNames[$columnName]; + + if (isset($class->fieldMappings[$fieldName])) { + return $class->fieldMappings[$fieldName]['type']; + } + } + + // iterate over to-one association mappings + foreach ($class->associationMappings as $assoc) { + if ( ! isset($assoc['joinColumns'])) { + continue; + } + + foreach ($assoc['joinColumns'] as $joinColumn) { + if ($joinColumn['name'] == $columnName) { + $targetColumnName = $joinColumn['referencedColumnName']; + $targetClass = $em->getClassMetadata($assoc['targetEntity']); + + return self::getTypeOfColumn($targetColumnName, $targetClass, $em); + } + } + } + + // iterate over to-many association mappings + foreach ($class->associationMappings as $assoc) { + if ( ! (isset($assoc['joinTable']) && isset($assoc['joinTable']['joinColumns']))) { + continue; + } + + foreach ($assoc['joinTable']['joinColumns'] as $joinColumn) { + if ($joinColumn['name'] == $columnName) { + $targetColumnName = $joinColumn['referencedColumnName']; + $targetClass = $em->getClassMetadata($assoc['targetEntity']); + + return self::getTypeOfColumn($targetColumnName, $targetClass, $em); + } + } + } + + throw new \RuntimeException(sprintf( + 'Could not resolve type of column "%s" of class "%s"', + $columnName, + $class->getName() + )); + } + + /** + * @param mixed $value + * @param EntityManagerInterface $em + * + * @return mixed + */ + public static function getIdentifierValues($value, EntityManagerInterface $em) + { + if ( ! is_array($value)) { + return self::getIndividualValue($value, $em); + } + + $newValue = array(); + + foreach ($value as $fieldName => $fieldValue) { + $newValue[$fieldName] = self::getIndividualValue($fieldValue, $em); + } + + return $newValue; + } + + /** + * @param mixed $value + * @param EntityManagerInterface $em + * + * @return mixed + */ + private static function getIndividualValue($value, EntityManagerInterface $em) + { + if ( ! is_object($value) || ! $em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) { + return $value; + } + + return $em->getUnitOfWork()->getSingleIdentifierValue($value); + } +} diff --git a/tests/Doctrine/Tests/DbalTypes/Rot13Type.php b/tests/Doctrine/Tests/DbalTypes/Rot13Type.php new file mode 100644 index 000000000..6403b9ebe --- /dev/null +++ b/tests/Doctrine/Tests/DbalTypes/Rot13Type.php @@ -0,0 +1,81 @@ +getVarcharTypeDeclarationSQL($fieldDeclaration); + } + + /** + * {@inheritdoc} + * + * @param AbstractPlatform $platform + * + * @return int|null + */ + public function getDefaultLength(AbstractPlatform $platform) + { + return $platform->getVarcharDefaultLength(); + } + + /** + * {@inheritdoc} + * + * @return string + */ + public function getName() + { + return 'rot13'; + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/AuxiliaryEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/AuxiliaryEntity.php new file mode 100644 index 000000000..89025605b --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/AuxiliaryEntity.php @@ -0,0 +1,16 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/InversedManyToManyCompositeIdForeignKeyEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/InversedManyToManyCompositeIdForeignKeyEntity.php new file mode 100644 index 000000000..9cc1a1207 --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/InversedManyToManyCompositeIdForeignKeyEntity.php @@ -0,0 +1,35 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/InversedManyToManyEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/InversedManyToManyEntity.php new file mode 100644 index 000000000..3b0157655 --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/InversedManyToManyEntity.php @@ -0,0 +1,28 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/InversedManyToManyExtraLazyEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/InversedManyToManyExtraLazyEntity.php new file mode 100644 index 000000000..b139fa407 --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/InversedManyToManyExtraLazyEntity.php @@ -0,0 +1,33 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToManyCompositeIdEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToManyCompositeIdEntity.php new file mode 100644 index 000000000..01892c1aa --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToManyCompositeIdEntity.php @@ -0,0 +1,39 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToManyCompositeIdForeignKeyEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToManyCompositeIdForeignKeyEntity.php new file mode 100644 index 000000000..e2212812e --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToManyCompositeIdForeignKeyEntity.php @@ -0,0 +1,40 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToManyEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToManyEntity.php new file mode 100644 index 000000000..ff8ec73a0 --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToManyEntity.php @@ -0,0 +1,33 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToManyExtraLazyEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToManyExtraLazyEntity.php new file mode 100644 index 000000000..26d0a58d0 --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToManyExtraLazyEntity.php @@ -0,0 +1,33 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToOneCompositeIdEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToOneCompositeIdEntity.php new file mode 100644 index 000000000..631b22b8b --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/InversedOneToOneCompositeIdEntity.php @@ -0,0 +1,32 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToManyCompositeIdForeignKeyEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToManyCompositeIdForeignKeyEntity.php new file mode 100644 index 000000000..abbb32d8a --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToManyCompositeIdForeignKeyEntity.php @@ -0,0 +1,36 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToManyEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToManyEntity.php new file mode 100644 index 000000000..292ff7835 --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToManyEntity.php @@ -0,0 +1,33 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToManyExtraLazyEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToManyExtraLazyEntity.php new file mode 100644 index 000000000..dda25b27d --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToManyExtraLazyEntity.php @@ -0,0 +1,38 @@ +associatedEntities = new ArrayCollection(); + } +} diff --git a/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToOneCompositeIdEntity.php b/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToOneCompositeIdEntity.php new file mode 100644 index 000000000..b06b2188b --- /dev/null +++ b/tests/Doctrine/Tests/Models/ValueConversionType/OwningManyToOneCompositeIdEntity.php @@ -0,0 +1,25 @@ +useModelSet('vct_manytomany_compositeid_foreignkey'); + + parent::setUp(); + + $auxiliary = new Entity\AuxiliaryEntity(); + $auxiliary->id4 = 'abc'; + + $inversed = new Entity\InversedManyToManyCompositeIdForeignKeyEntity(); + $inversed->id1 = 'def'; + $inversed->foreignEntity = $auxiliary; + + $owning = new Entity\OwningManyToManyCompositeIdForeignKeyEntity(); + $owning->id2 = 'ghi'; + + $inversed->associatedEntities->add($owning); + $owning->associatedEntities->add($inversed); + + $this->_em->persist($auxiliary); + $this->_em->persist($inversed); + $this->_em->persist($owning); + + $this->_em->flush(); + $this->_em->clear(); + } + + public static function tearDownAfterClass() + { + $conn = static::$_sharedConn; + + $conn->executeUpdate('DROP TABLE vct_xref_manytomany_compositeid_foreignkey'); + $conn->executeUpdate('DROP TABLE vct_owning_manytomany_compositeid_foreignkey'); + $conn->executeUpdate('DROP TABLE vct_inversed_manytomany_compositeid_foreignkey'); + $conn->executeUpdate('DROP TABLE vct_auxiliary'); + } + + public function testThatTheValueOfIdentifiersAreConvertedInTheDatabase() + { + $conn = $this->_em->getConnection(); + + $this->assertEquals('nop', $conn->fetchColumn('SELECT id4 FROM vct_auxiliary LIMIT 1')); + + $this->assertEquals('qrs', $conn->fetchColumn('SELECT id1 FROM vct_inversed_manytomany_compositeid_foreignkey LIMIT 1')); + $this->assertEquals('nop', $conn->fetchColumn('SELECT foreign_id FROM vct_inversed_manytomany_compositeid_foreignkey LIMIT 1')); + + $this->assertEquals('tuv', $conn->fetchColumn('SELECT id2 FROM vct_owning_manytomany_compositeid_foreignkey LIMIT 1')); + + $this->assertEquals('qrs', $conn->fetchColumn('SELECT associated_id FROM vct_xref_manytomany_compositeid_foreignkey LIMIT 1')); + $this->assertEquals('nop', $conn->fetchColumn('SELECT associated_foreign_id FROM vct_xref_manytomany_compositeid_foreignkey LIMIT 1')); + $this->assertEquals('tuv', $conn->fetchColumn('SELECT owning_id FROM vct_xref_manytomany_compositeid_foreignkey LIMIT 1')); + } + + /** + * @depends testThatTheValueOfIdentifiersAreConvertedInTheDatabase + */ + public function testThatEntitiesAreFetchedFromTheDatabase() + { + $auxiliary = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', + 'abc' + ); + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdForeignKeyEntity', + array('id1' => 'def', 'foreignEntity' => 'abc') + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyCompositeIdForeignKeyEntity', + 'ghi' + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', $auxiliary); + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdForeignKeyEntity', $inversed); + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\OwningManyToManyCompositeIdForeignKeyEntity', $owning); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheValueOfIdentifiersAreConvertedBackAfterBeingFetchedFromTheDatabase() + { + $auxiliary = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', + 'abc' + ); + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdForeignKeyEntity', + array('id1' => 'def', 'foreignEntity' => 'abc') + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyCompositeIdForeignKeyEntity', + 'ghi' + ); + + $this->assertEquals('abc', $auxiliary->id4); + $this->assertEquals('def', $inversed->id1); + $this->assertEquals('abc', $inversed->foreignEntity->id4); + $this->assertEquals('ghi', $owning->id2); + } + + /** + * @depends testThatTheValueOfIdentifiersAreConvertedBackAfterBeingFetchedFromTheDatabase + */ + public function testThatInversedEntityIsFetchedFromTheDatabaseUsingAuxiliaryEntityAsId() + { + $auxiliary = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', + 'abc' + ); + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdForeignKeyEntity', + array('id1' => 'def', 'foreignEntity' => $auxiliary) + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdForeignKeyEntity', $inversed); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheCollectionFromOwningToInversedIsLoaded() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyCompositeIdForeignKeyEntity', + 'ghi' + ); + + $this->assertCount(1, $owning->associatedEntities); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheCollectionFromInversedToOwningIsLoaded() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdForeignKeyEntity', + array('id1' => 'def', 'foreignEntity' => 'abc') + ); + + $this->assertCount(1, $inversed->associatedEntities); + } + + /** + * @depends testThatTheCollectionFromOwningToInversedIsLoaded + * @depends testThatTheCollectionFromInversedToOwningIsLoaded + */ + public function testThatTheJoinTableRowsAreRemovedWhenRemovingTheAssociation() + { + $conn = $this->_em->getConnection(); + + // remove association + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdForeignKeyEntity', + array('id1' => 'def', 'foreignEntity' => 'abc') + ); + + foreach ($inversed->associatedEntities as $owning) { + $inversed->associatedEntities->removeElement($owning); + $owning->associatedEntities->removeElement($inversed); + } + + $this->_em->flush(); + $this->_em->clear(); + + // test association is removed + + $this->assertEquals(0, $conn->fetchColumn('SELECT COUNT(*) FROM vct_xref_manytomany_compositeid_foreignkey')); + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/ManyToManyCompositeIdTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/ManyToManyCompositeIdTest.php new file mode 100644 index 000000000..6b56073a3 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/ManyToManyCompositeIdTest.php @@ -0,0 +1,157 @@ +useModelSet('vct_manytomany_compositeid'); + + parent::setUp(); + + $inversed = new Entity\InversedManyToManyCompositeIdEntity(); + $inversed->id1 = 'abc'; + $inversed->id2 = 'def'; + + $owning = new Entity\OwningManyToManyCompositeIdEntity(); + $owning->id3 = 'ghi'; + + $inversed->associatedEntities->add($owning); + $owning->associatedEntities->add($inversed); + + $this->_em->persist($inversed); + $this->_em->persist($owning); + + $this->_em->flush(); + $this->_em->clear(); + } + + public static function tearDownAfterClass() + { + $conn = static::$_sharedConn; + + $conn->executeUpdate('DROP TABLE vct_xref_manytomany_compositeid'); + $conn->executeUpdate('DROP TABLE vct_owning_manytomany_compositeid'); + $conn->executeUpdate('DROP TABLE vct_inversed_manytomany_compositeid'); + } + + public function testThatTheValueOfIdentifiersAreConvertedInTheDatabase() + { + $conn = $this->_em->getConnection(); + + $this->assertEquals('nop', $conn->fetchColumn('SELECT id1 FROM vct_inversed_manytomany_compositeid LIMIT 1')); + $this->assertEquals('qrs', $conn->fetchColumn('SELECT id2 FROM vct_inversed_manytomany_compositeid LIMIT 1')); + + $this->assertEquals('tuv', $conn->fetchColumn('SELECT id3 FROM vct_owning_manytomany_compositeid LIMIT 1')); + + $this->assertEquals('nop', $conn->fetchColumn('SELECT inversed_id1 FROM vct_xref_manytomany_compositeid LIMIT 1')); + $this->assertEquals('qrs', $conn->fetchColumn('SELECT inversed_id2 FROM vct_xref_manytomany_compositeid LIMIT 1')); + $this->assertEquals('tuv', $conn->fetchColumn('SELECT owning_id FROM vct_xref_manytomany_compositeid LIMIT 1')); + } + + /** + * @depends testThatTheValueOfIdentifiersAreConvertedInTheDatabase + */ + public function testThatEntitiesAreFetchedFromTheDatabase() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdEntity', + array('id1' => 'abc', 'id2' => 'def') + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyCompositeIdEntity', + 'ghi' + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdEntity', $inversed); + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\OwningManyToManyCompositeIdEntity', $owning); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheValueOfIdentifiersAreConvertedBackAfterBeingFetchedFromTheDatabase() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdEntity', + array('id1' => 'abc', 'id2' => 'def') + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyCompositeIdEntity', + 'ghi' + ); + + $this->assertEquals('abc', $inversed->id1); + $this->assertEquals('def', $inversed->id2); + $this->assertEquals('ghi', $owning->id3); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheCollectionFromOwningToInversedIsLoaded() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyCompositeIdEntity', + 'ghi' + ); + + $this->assertCount(1, $owning->associatedEntities); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheCollectionFromInversedToOwningIsLoaded() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdEntity', + array('id1' => 'abc', 'id2' => 'def') + ); + + $this->assertCount(1, $inversed->associatedEntities); + } + + /** + * @depends testThatTheCollectionFromOwningToInversedIsLoaded + * @depends testThatTheCollectionFromInversedToOwningIsLoaded + */ + public function testThatTheJoinTableRowsAreRemovedWhenRemovingTheAssociation() + { + $conn = $this->_em->getConnection(); + + // remove association + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdEntity', + array('id1' => 'abc', 'id2' => 'def') + ); + + foreach ($inversed->associatedEntities as $owning) { + $inversed->associatedEntities->removeElement($owning); + $owning->associatedEntities->removeElement($inversed); + } + + $this->_em->flush(); + $this->_em->clear(); + + // test association is removed + + $this->assertEquals(0, $conn->fetchColumn('SELECT COUNT(*) FROM vct_xref_manytomany_compositeid')); + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/ManyToManyExtraLazyTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/ManyToManyExtraLazyTest.php new file mode 100644 index 000000000..3d1df24b8 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/ManyToManyExtraLazyTest.php @@ -0,0 +1,154 @@ +useModelSet('vct_manytomany_extralazy'); + parent::setUp(); + + $inversed1 = new Entity\InversedManyToManyExtraLazyEntity(); + $inversed1->id1 = 'abc'; + + $inversed2 = new Entity\InversedManyToManyExtraLazyEntity(); + $inversed2->id1 = 'def'; + + $owning1 = new Entity\OwningManyToManyExtraLazyEntity(); + $owning1->id2 = 'ghi'; + + $owning2 = new Entity\OwningManyToManyExtraLazyEntity(); + $owning2->id2 = 'jkl'; + + $inversed1->associatedEntities->add($owning1); + $owning1->associatedEntities->add($inversed1); + $inversed1->associatedEntities->add($owning2); + $owning2->associatedEntities->add($inversed1); + + $inversed2->associatedEntities->add($owning1); + $owning1->associatedEntities->add($inversed2); + $inversed2->associatedEntities->add($owning2); + $owning2->associatedEntities->add($inversed2); + + $this->_em->persist($inversed1); + $this->_em->persist($inversed2); + $this->_em->persist($owning1); + $this->_em->persist($owning2); + + $this->_em->flush(); + $this->_em->clear(); + } + + public static function tearDownAfterClass() + { + $conn = static::$_sharedConn; + + $conn->executeUpdate('DROP TABLE vct_xref_manytomany_extralazy'); + $conn->executeUpdate('DROP TABLE vct_owning_manytomany_extralazy'); + $conn->executeUpdate('DROP TABLE vct_inversed_manytomany_extralazy'); + } + + public function testThatTheExtraLazyCollectionFromOwningToInversedIsCounted() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyExtraLazyEntity', + 'ghi' + ); + + $this->assertEquals(2, $owning->associatedEntities->count()); + } + + public function testThatTheExtraLazyCollectionFromInversedToOwningIsCounted() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyExtraLazyEntity', + 'abc' + ); + + $this->assertEquals(2, $inversed->associatedEntities->count()); + } + + public function testThatTheExtraLazyCollectionFromOwningToInversedContainsAnEntity() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyExtraLazyEntity', + 'ghi' + ); + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyExtraLazyEntity', + 'abc' + ); + + $this->assertTrue($owning->associatedEntities->contains($inversed)); + } + + public function testThatTheExtraLazyCollectionFromInversedToOwningContainsAnEntity() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyExtraLazyEntity', + 'abc' + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyExtraLazyEntity', + 'ghi' + ); + + $this->assertTrue($inversed->associatedEntities->contains($owning)); + } + + public function testThatTheExtraLazyCollectionFromOwningToInversedContainsAnIndexByKey() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyExtraLazyEntity', + 'ghi' + ); + + $this->assertTrue($owning->associatedEntities->containsKey('abc')); + } + + public function testThatTheExtraLazyCollectionFromInversedToOwningContainsAnIndexByKey() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyExtraLazyEntity', + 'abc' + ); + + $this->assertTrue($inversed->associatedEntities->containsKey('ghi')); + } + + public function testThatASliceOfTheExtraLazyCollectionFromOwningToInversedIsLoaded() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyExtraLazyEntity', + 'ghi' + ); + + $this->assertCount(1, $owning->associatedEntities->slice(0, 1)); + } + + public function testThatASliceOfTheExtraLazyCollectionFromInversedToOwningIsLoaded() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyExtraLazyEntity', + 'abc' + ); + + $this->assertCount(1, $inversed->associatedEntities->slice(1, 1)); + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/ManyToManyTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/ManyToManyTest.php new file mode 100644 index 000000000..66193fb14 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/ManyToManyTest.php @@ -0,0 +1,153 @@ +useModelSet('vct_manytomany'); + + parent::setUp(); + + $inversed = new Entity\InversedManyToManyEntity(); + $inversed->id1 = 'abc'; + + $owning = new Entity\OwningManyToManyEntity(); + $owning->id2 = 'def'; + + $inversed->associatedEntities->add($owning); + $owning->associatedEntities->add($inversed); + + $this->_em->persist($inversed); + $this->_em->persist($owning); + + $this->_em->flush(); + $this->_em->clear(); + } + + public static function tearDownAfterClass() + { + $conn = static::$_sharedConn; + + $conn->executeUpdate('DROP TABLE vct_xref_manytomany'); + $conn->executeUpdate('DROP TABLE vct_owning_manytomany'); + $conn->executeUpdate('DROP TABLE vct_inversed_manytomany'); + } + + public function testThatTheValueOfIdentifiersAreConvertedInTheDatabase() + { + $conn = $this->_em->getConnection(); + + $this->assertEquals('nop', $conn->fetchColumn('SELECT id1 FROM vct_inversed_manytomany LIMIT 1')); + + $this->assertEquals('qrs', $conn->fetchColumn('SELECT id2 FROM vct_owning_manytomany LIMIT 1')); + + $this->assertEquals('nop', $conn->fetchColumn('SELECT inversed_id FROM vct_xref_manytomany LIMIT 1')); + $this->assertEquals('qrs', $conn->fetchColumn('SELECT owning_id FROM vct_xref_manytomany LIMIT 1')); + } + + /** + * @depends testThatTheValueOfIdentifiersAreConvertedInTheDatabase + */ + public function testThatEntitiesAreFetchedFromTheDatabase() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyEntity', + 'abc' + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyEntity', + 'def' + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\InversedManyToManyEntity', $inversed); + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\OwningManyToManyEntity', $owning); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheValueOfIdentifiersAreConvertedBackAfterBeingFetchedFromTheDatabase() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyEntity', + 'abc' + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyEntity', + 'def' + ); + + $this->assertEquals('abc', $inversed->id1); + $this->assertEquals('def', $owning->id2); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheCollectionFromOwningToInversedIsLoaded() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyEntity', + 'def' + ); + + $this->assertCount(1, $owning->associatedEntities); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheCollectionFromInversedToOwningIsLoaded() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyEntity', + 'abc' + ); + + $this->assertCount(1, $inversed->associatedEntities); + } + + /** + * @depends testThatTheCollectionFromOwningToInversedIsLoaded + * @depends testThatTheCollectionFromInversedToOwningIsLoaded + */ + public function testThatTheJoinTableRowsAreRemovedWhenRemovingTheAssociation() + { + $conn = $this->_em->getConnection(); + + // remove association + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyEntity', + 'abc' + ); + + foreach ($inversed->associatedEntities as $owning) { + $inversed->associatedEntities->removeElement($owning); + $owning->associatedEntities->removeElement($inversed); + } + + $this->_em->flush(); + $this->_em->clear(); + + // test association is removed + + $this->assertEquals(0, $conn->fetchColumn('SELECT COUNT(*) FROM vct_xref_manytomany')); + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToManyCompositeIdForeignKeyTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToManyCompositeIdForeignKeyTest.php new file mode 100644 index 000000000..17a8ea873 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToManyCompositeIdForeignKeyTest.php @@ -0,0 +1,169 @@ +useModelSet('vct_onetomany_compositeid_foreignkey'); + + parent::setUp(); + + $auxiliary = new Entity\AuxiliaryEntity(); + $auxiliary->id4 = 'abc'; + + $inversed = new Entity\InversedOneToManyCompositeIdForeignKeyEntity(); + $inversed->id1 = 'def'; + $inversed->foreignEntity = $auxiliary; + $inversed->someProperty = 'some value to be loaded'; + + $owning = new Entity\OwningManyToOneCompositeIdForeignKeyEntity(); + $owning->id2 = 'ghi'; + + $inversed->associatedEntities->add($owning); + $owning->associatedEntity = $inversed; + + $this->_em->persist($auxiliary); + $this->_em->persist($inversed); + $this->_em->persist($owning); + + $this->_em->flush(); + $this->_em->clear(); + } + + public static function tearDownAfterClass() + { + $conn = static::$_sharedConn; + + $conn->executeUpdate('DROP TABLE vct_owning_manytoone_compositeid_foreignkey'); + $conn->executeUpdate('DROP TABLE vct_inversed_onetomany_compositeid_foreignkey'); + $conn->executeUpdate('DROP TABLE vct_auxiliary'); + } + + public function testThatTheValueOfIdentifiersAreConvertedInTheDatabase() + { + $conn = $this->_em->getConnection(); + + $this->assertEquals('nop', $conn->fetchColumn('SELECT id4 FROM vct_auxiliary LIMIT 1')); + + $this->assertEquals('qrs', $conn->fetchColumn('SELECT id1 FROM vct_inversed_onetomany_compositeid_foreignkey LIMIT 1')); + $this->assertEquals('nop', $conn->fetchColumn('SELECT foreign_id FROM vct_inversed_onetomany_compositeid_foreignkey LIMIT 1')); + + $this->assertEquals('tuv', $conn->fetchColumn('SELECT id2 FROM vct_owning_manytoone_compositeid_foreignkey LIMIT 1')); + $this->assertEquals('qrs', $conn->fetchColumn('SELECT associated_id FROM vct_owning_manytoone_compositeid_foreignkey LIMIT 1')); + $this->assertEquals('nop', $conn->fetchColumn('SELECT associated_foreign_id FROM vct_owning_manytoone_compositeid_foreignkey LIMIT 1')); + } + + /** + * @depends testThatTheValueOfIdentifiersAreConvertedInTheDatabase + */ + public function testThatEntitiesAreFetchedFromTheDatabase() + { + $auxiliary = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', + 'abc' + ); + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyCompositeIdForeignKeyEntity', + array('id1' => 'def', 'foreignEntity' => 'abc') + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneCompositeIdForeignKeyEntity', + 'ghi' + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', $auxiliary); + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\InversedOneToManyCompositeIdForeignKeyEntity', $inversed); + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\OwningManyToOneCompositeIdForeignKeyEntity', $owning); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheValueOfIdentifiersAreConvertedBackAfterBeingFetchedFromTheDatabase() + { + $auxiliary = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', + 'abc' + ); + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyCompositeIdForeignKeyEntity', + array('id1' => 'def', 'foreignEntity' => 'abc') + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneCompositeIdForeignKeyEntity', + 'ghi' + ); + + $this->assertEquals('abc', $auxiliary->id4); + $this->assertEquals('def', $inversed->id1); + $this->assertEquals('abc', $inversed->foreignEntity->id4); + $this->assertEquals('ghi', $owning->id2); + } + + /** + * @depends testThatTheValueOfIdentifiersAreConvertedBackAfterBeingFetchedFromTheDatabase + */ + public function testThatInversedEntityIsFetchedFromTheDatabaseUsingAuxiliaryEntityAsId() + { + $auxiliary = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', + 'abc' + ); + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyCompositeIdForeignKeyEntity', + array('id1' => 'def', 'foreignEntity' => $auxiliary) + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\InversedOneToManyCompositeIdForeignKeyEntity', $inversed); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheProxyFromOwningToInversedIsLoaded() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneCompositeIdForeignKeyEntity', + 'ghi' + ); + + $inversedProxy = $owning->associatedEntity; + + $this->assertSame('def', $inversedProxy->id1, 'Proxy identifier is converted'); + + $this->assertEquals('some value to be loaded', $inversedProxy->someProperty); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheCollectionFromInversedToOwningIsLoaded() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyCompositeIdForeignKeyEntity', + array('id1' => 'def', 'foreignEntity' => 'abc') + ); + + $this->assertCount(1, $inversed->associatedEntities); + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToManyCompositeIdTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToManyCompositeIdTest.php new file mode 100644 index 000000000..c094afa78 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToManyCompositeIdTest.php @@ -0,0 +1,129 @@ +useModelSet('vct_onetomany_compositeid'); + + parent::setUp(); + + $inversed = new Entity\InversedOneToManyCompositeIdEntity(); + $inversed->id1 = 'abc'; + $inversed->id2 = 'def'; + $inversed->someProperty = 'some value to be loaded'; + + $owning = new Entity\OwningManyToOneCompositeIdEntity(); + $owning->id3 = 'ghi'; + + $inversed->associatedEntities->add($owning); + $owning->associatedEntity = $inversed; + + $this->_em->persist($inversed); + $this->_em->persist($owning); + + $this->_em->flush(); + $this->_em->clear(); + } + + public static function tearDownAfterClass() + { + $conn = static::$_sharedConn; + + $conn->executeUpdate('DROP TABLE vct_owning_manytoone_compositeid'); + $conn->executeUpdate('DROP TABLE vct_inversed_onetomany_compositeid'); + } + + public function testThatTheValueOfIdentifiersAreConvertedInTheDatabase() + { + $conn = $this->_em->getConnection(); + + $this->assertEquals('nop', $conn->fetchColumn('SELECT id1 FROM vct_inversed_onetomany_compositeid LIMIT 1')); + $this->assertEquals('qrs', $conn->fetchColumn('SELECT id2 FROM vct_inversed_onetomany_compositeid LIMIT 1')); + + $this->assertEquals('tuv', $conn->fetchColumn('SELECT id3 FROM vct_owning_manytoone_compositeid LIMIT 1')); + $this->assertEquals('nop', $conn->fetchColumn('SELECT associated_id1 FROM vct_owning_manytoone_compositeid LIMIT 1')); + $this->assertEquals('qrs', $conn->fetchColumn('SELECT associated_id2 FROM vct_owning_manytoone_compositeid LIMIT 1')); + } + + /** + * @depends testThatTheValueOfIdentifiersAreConvertedInTheDatabase + */ + public function testThatEntitiesAreFetchedFromTheDatabase() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyCompositeIdEntity', + array('id1' => 'abc', 'id2' => 'def') + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneCompositeIdEntity', + 'ghi' + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\InversedOneToManyCompositeIdEntity', $inversed); + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\OwningManyToOneCompositeIdEntity', $owning); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheValueOfIdentifiersAreConvertedBackAfterBeingFetchedFromTheDatabase() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyCompositeIdEntity', + array('id1' => 'abc', 'id2' => 'def') + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneCompositeIdEntity', + 'ghi' + ); + + $this->assertEquals('abc', $inversed->id1); + $this->assertEquals('def', $inversed->id2); + $this->assertEquals('ghi', $owning->id3); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheProxyFromOwningToInversedIsLoaded() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneCompositeIdEntity', + 'ghi' + ); + + $inversedProxy = $owning->associatedEntity; + + $this->assertEquals('some value to be loaded', $inversedProxy->someProperty); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheCollectionFromInversedToOwningIsLoaded() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyCompositeIdEntity', + array('id1' => 'abc', 'id2' => 'def') + ); + + $this->assertCount(1, $inversed->associatedEntities); + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToManyExtraLazyTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToManyExtraLazyTest.php new file mode 100644 index 000000000..bb9006782 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToManyExtraLazyTest.php @@ -0,0 +1,106 @@ +useModelSet('vct_onetomany_extralazy'); + + parent::setUp(); + + $inversed = new Entity\InversedOneToManyExtraLazyEntity(); + $inversed->id1 = 'abc'; + + $owning1 = new Entity\OwningManyToOneExtraLazyEntity(); + $owning1->id2 = 'def'; + + $owning2 = new Entity\OwningManyToOneExtraLazyEntity(); + $owning2->id2 = 'ghi'; + + $owning3 = new Entity\OwningManyToOneExtraLazyEntity(); + $owning3->id2 = 'jkl'; + + $inversed->associatedEntities->add($owning1); + $owning1->associatedEntity = $inversed; + $inversed->associatedEntities->add($owning2); + $owning2->associatedEntity = $inversed; + $inversed->associatedEntities->add($owning3); + $owning3->associatedEntity = $inversed; + + $this->_em->persist($inversed); + $this->_em->persist($owning1); + $this->_em->persist($owning2); + $this->_em->persist($owning3); + + $this->_em->flush(); + $this->_em->clear(); + } + + public static function tearDownAfterClass() + { + $conn = static::$_sharedConn; + + $conn->executeUpdate('DROP TABLE vct_owning_manytoone_extralazy'); + $conn->executeUpdate('DROP TABLE vct_inversed_onetomany_extralazy'); + } + + public function testThatExtraLazyCollectionIsCounted() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyExtraLazyEntity', + 'abc' + ); + + $this->assertEquals(3, $inversed->associatedEntities->count()); + } + + public function testThatExtraLazyCollectionContainsAnEntity() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyExtraLazyEntity', + 'abc' + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneExtraLazyEntity', + 'def' + ); + + $this->assertTrue($inversed->associatedEntities->contains($owning)); + } + + public function testThatExtraLazyCollectionContainsAnIndexbyKey() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyExtraLazyEntity', + 'abc' + ); + + $this->assertTrue($inversed->associatedEntities->containsKey('def')); + } + + public function testThatASliceOfTheExtraLazyCollectionIsLoaded() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyExtraLazyEntity', + 'abc' + ); + + $this->assertCount(2, $inversed->associatedEntities->slice(0, 2)); + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToManyTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToManyTest.php new file mode 100644 index 000000000..e83453714 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToManyTest.php @@ -0,0 +1,125 @@ +useModelSet('vct_onetomany'); + + parent::setUp(); + + $inversed = new Entity\InversedOneToManyEntity(); + $inversed->id1 = 'abc'; + $inversed->someProperty = 'some value to be loaded'; + + $owning = new Entity\OwningManyToOneEntity(); + $owning->id2 = 'def'; + + $inversed->associatedEntities->add($owning); + $owning->associatedEntity = $inversed; + + $this->_em->persist($inversed); + $this->_em->persist($owning); + + $this->_em->flush(); + $this->_em->clear(); + } + + public static function tearDownAfterClass() + { + $conn = static::$_sharedConn; + + $conn->executeUpdate('DROP TABLE vct_owning_manytoone'); + $conn->executeUpdate('DROP TABLE vct_inversed_onetomany'); + } + + public function testThatTheValueOfIdentifiersAreConvertedInTheDatabase() + { + $conn = $this->_em->getConnection(); + + $this->assertEquals('nop', $conn->fetchColumn('SELECT id1 FROM vct_inversed_onetomany LIMIT 1')); + + $this->assertEquals('qrs', $conn->fetchColumn('SELECT id2 FROM vct_owning_manytoone LIMIT 1')); + $this->assertEquals('nop', $conn->fetchColumn('SELECT associated_id FROM vct_owning_manytoone LIMIT 1')); + } + + /** + * @depends testThatTheValueOfIdentifiersAreConvertedInTheDatabase + */ + public function testThatEntitiesAreFetchedFromTheDatabase() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyEntity', + 'abc' + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneEntity', + 'def' + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\InversedOneToManyEntity', $inversed); + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\OwningManyToOneEntity', $owning); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheValueOfIdentifiersAreConvertedBackAfterBeingFetchedFromTheDatabase() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyEntity', + 'abc' + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneEntity', + 'def' + ); + + $this->assertEquals('abc', $inversed->id1); + $this->assertEquals('def', $owning->id2); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheProxyFromOwningToInversedIsLoaded() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneEntity', + 'def' + ); + + $inversedProxy = $owning->associatedEntity; + + $this->assertEquals('some value to be loaded', $inversedProxy->someProperty); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheCollectionFromInversedToOwningIsLoaded() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyEntity', + 'abc' + ); + + $this->assertCount(1, $inversed->associatedEntities); + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToOneCompositeIdForeignKeyTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToOneCompositeIdForeignKeyTest.php new file mode 100644 index 000000000..4a595c21f --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToOneCompositeIdForeignKeyTest.php @@ -0,0 +1,166 @@ +useModelSet('vct_onetoone_compositeid_foreignkey'); + parent::setUp(); + + $auxiliary = new Entity\AuxiliaryEntity(); + $auxiliary->id4 = 'abc'; + + $inversed = new Entity\InversedOneToOneCompositeIdForeignKeyEntity(); + $inversed->id1 = 'def'; + $inversed->foreignEntity = $auxiliary; + $inversed->someProperty = 'some value to be loaded'; + + $owning = new Entity\OwningOneToOneCompositeIdForeignKeyEntity(); + $owning->id2 = 'ghi'; + + $inversed->associatedEntity = $owning; + $owning->associatedEntity = $inversed; + + $this->_em->persist($auxiliary); + $this->_em->persist($inversed); + $this->_em->persist($owning); + + $this->_em->flush(); + $this->_em->clear(); + } + + public static function tearDownAfterClass() + { + $conn = static::$_sharedConn; + + $conn->executeUpdate('DROP TABLE vct_owning_onetoone_compositeid_foreignkey'); + $conn->executeUpdate('DROP TABLE vct_inversed_onetoone_compositeid_foreignkey'); + $conn->executeUpdate('DROP TABLE vct_auxiliary'); + } + + public function testThatTheValueOfIdentifiersAreConvertedInTheDatabase() + { + $conn = $this->_em->getConnection(); + + $this->assertEquals('nop', $conn->fetchColumn('SELECT id4 FROM vct_auxiliary LIMIT 1')); + + $this->assertEquals('qrs', $conn->fetchColumn('SELECT id1 FROM vct_inversed_onetoone_compositeid_foreignkey LIMIT 1')); + $this->assertEquals('nop', $conn->fetchColumn('SELECT foreign_id FROM vct_inversed_onetoone_compositeid_foreignkey LIMIT 1')); + + $this->assertEquals('tuv', $conn->fetchColumn('SELECT id2 FROM vct_owning_onetoone_compositeid_foreignkey LIMIT 1')); + $this->assertEquals('qrs', $conn->fetchColumn('SELECT associated_id FROM vct_owning_onetoone_compositeid_foreignkey LIMIT 1')); + $this->assertEquals('nop', $conn->fetchColumn('SELECT associated_foreign_id FROM vct_owning_onetoone_compositeid_foreignkey LIMIT 1')); + } + + /** + * @depends testThatTheValueOfIdentifiersAreConvertedInTheDatabase + */ + public function testThatEntitiesAreFetchedFromTheDatabase() + { + $auxiliary = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', + 'abc' + ); + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToOneCompositeIdForeignKeyEntity', + array('id1' => 'def', 'foreignEntity' => 'abc') + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningOneToOneCompositeIdForeignKeyEntity', + 'ghi' + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', $auxiliary); + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\InversedOneToOneCompositeIdForeignKeyEntity', $inversed); + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\OwningOneToOneCompositeIdForeignKeyEntity', $owning); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheValueOfIdentifiersAreConvertedBackAfterBeingFetchedFromTheDatabase() + { + $auxiliary = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', + 'abc' + ); + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToOneCompositeIdForeignKeyEntity', + array('id1' => 'def', 'foreignEntity' => 'abc') + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningOneToOneCompositeIdForeignKeyEntity', + 'ghi' + ); + + $this->assertEquals('abc', $auxiliary->id4); + $this->assertEquals('def', $inversed->id1); + $this->assertEquals('abc', $inversed->foreignEntity->id4); + $this->assertEquals('ghi', $owning->id2); + } + + /** + * @depends testThatTheValueOfIdentifiersAreConvertedBackAfterBeingFetchedFromTheDatabase + */ + public function testThatInversedEntityIsFetchedFromTheDatabaseUsingAuxiliaryEntityAsId() + { + $auxiliary = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', + 'abc' + ); + + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToOneCompositeIdForeignKeyEntity', + array('id1' => 'def', 'foreignEntity' => $auxiliary) + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\InversedOneToOneCompositeIdForeignKeyEntity', $inversed); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheProxyFromOwningToInversedIsLoaded() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningOneToOneCompositeIdForeignKeyEntity', + 'ghi' + ); + + $inversedProxy = $owning->associatedEntity; + + $this->assertEquals('some value to be loaded', $inversedProxy->someProperty); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheEntityFromInversedToOwningIsEagerLoaded() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToOneCompositeIdForeignKeyEntity', + array('id1' => 'def', 'foreignEntity' => 'abc') + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\OwningOneToOneCompositeIdForeignKeyEntity', $inversed->associatedEntity); + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToOneCompositeIdTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToOneCompositeIdTest.php new file mode 100644 index 000000000..96daa6016 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToOneCompositeIdTest.php @@ -0,0 +1,128 @@ +useModelSet('vct_onetoone_compositeid'); + parent::setUp(); + + $inversed = new Entity\InversedOneToOneCompositeIdEntity(); + $inversed->id1 = 'abc'; + $inversed->id2 = 'def'; + $inversed->someProperty = 'some value to be loaded'; + + $owning = new Entity\OwningOneToOneCompositeIdEntity(); + $owning->id3 = 'ghi'; + + $inversed->associatedEntity = $owning; + $owning->associatedEntity = $inversed; + + $this->_em->persist($inversed); + $this->_em->persist($owning); + + $this->_em->flush(); + $this->_em->clear(); + } + + public static function tearDownAfterClass() + { + $conn = static::$_sharedConn; + + $conn->executeUpdate('DROP TABLE vct_owning_onetoone_compositeid'); + $conn->executeUpdate('DROP TABLE vct_inversed_onetoone_compositeid'); + } + + public function testThatTheValueOfIdentifiersAreConvertedInTheDatabase() + { + $conn = $this->_em->getConnection(); + + $this->assertEquals('nop', $conn->fetchColumn('SELECT id1 FROM vct_inversed_onetoone_compositeid LIMIT 1')); + $this->assertEquals('qrs', $conn->fetchColumn('SELECT id2 FROM vct_inversed_onetoone_compositeid LIMIT 1')); + + $this->assertEquals('tuv', $conn->fetchColumn('SELECT id3 FROM vct_owning_onetoone_compositeid LIMIT 1')); + $this->assertEquals('nop', $conn->fetchColumn('SELECT associated_id1 FROM vct_owning_onetoone_compositeid LIMIT 1')); + $this->assertEquals('qrs', $conn->fetchColumn('SELECT associated_id2 FROM vct_owning_onetoone_compositeid LIMIT 1')); + } + + /** + * @depends testThatTheValueOfIdentifiersAreConvertedInTheDatabase + */ + public function testThatEntitiesAreFetchedFromTheDatabase() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToOneCompositeIdEntity', + array('id1' => 'abc', 'id2' => 'def') + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningOneToOneCompositeIdEntity', + 'ghi' + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\InversedOneToOneCompositeIdEntity', $inversed); + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\OwningOneToOneCompositeIdEntity', $owning); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheValueOfIdentifiersAreConvertedBackAfterBeingFetchedFromTheDatabase() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToOneCompositeIdEntity', + array('id1' => 'abc', 'id2' => 'def') + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningOneToOneCompositeIdEntity', + 'ghi' + ); + + $this->assertEquals('abc', $inversed->id1); + $this->assertEquals('def', $inversed->id2); + $this->assertEquals('ghi', $owning->id3); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheProxyFromOwningToInversedIsLoaded() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningOneToOneCompositeIdEntity', + 'ghi' + ); + + $inversedProxy = $owning->associatedEntity; + + $this->assertEquals('some value to be loaded', $inversedProxy->someProperty); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheEntityFromInversedToOwningIsEagerLoaded() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToOneCompositeIdEntity', + array('id1' => 'abc', 'id2' => 'def') + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\OwningOneToOneCompositeIdEntity', $inversed->associatedEntity); + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToOneTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToOneTest.php new file mode 100644 index 000000000..15e45f9fe --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/ValueConversionType/OneToOneTest.php @@ -0,0 +1,125 @@ +useModelSet('vct_onetoone'); + + parent::setUp(); + + $inversed = new Entity\InversedOneToOneEntity(); + $inversed->id1 = 'abc'; + $inversed->someProperty = 'some value to be loaded'; + + $owning = new Entity\OwningOneToOneEntity(); + $owning->id2 = 'def'; + + $inversed->associatedEntity = $owning; + $owning->associatedEntity = $inversed; + + $this->_em->persist($inversed); + $this->_em->persist($owning); + + $this->_em->flush(); + $this->_em->clear(); + } + + public static function tearDownAfterClass() + { + $conn = static::$_sharedConn; + + $conn->executeUpdate('DROP TABLE vct_owning_onetoone'); + $conn->executeUpdate('DROP TABLE vct_inversed_onetoone'); + } + + public function testThatTheValueOfIdentifiersAreConvertedInTheDatabase() + { + $conn = $this->_em->getConnection(); + + $this->assertEquals('nop', $conn->fetchColumn('SELECT id1 FROM vct_inversed_onetoone LIMIT 1')); + + $this->assertEquals('qrs', $conn->fetchColumn('SELECT id2 FROM vct_owning_onetoone LIMIT 1')); + $this->assertEquals('nop', $conn->fetchColumn('SELECT associated_id FROM vct_owning_onetoone LIMIT 1')); + } + + /** + * @depends testThatTheValueOfIdentifiersAreConvertedInTheDatabase + */ + public function testThatEntitiesAreFetchedFromTheDatabase() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToOneEntity', + 'abc' + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningOneToOneEntity', + 'def' + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\InversedOneToOneEntity', $inversed); + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\OwningOneToOneEntity', $owning); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheValueOfIdentifiersAreConvertedBackAfterBeingFetchedFromTheDatabase() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToOneEntity', + 'abc' + ); + + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningOneToOneEntity', + 'def' + ); + + $this->assertEquals('abc', $inversed->id1); + $this->assertEquals('def', $owning->id2); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheProxyFromOwningToInversedIsLoaded() + { + $owning = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\OwningOneToOneEntity', + 'def' + ); + + $inversedProxy = $owning->associatedEntity; + + $this->assertEquals('some value to be loaded', $inversedProxy->someProperty); + } + + /** + * @depends testThatEntitiesAreFetchedFromTheDatabase + */ + public function testThatTheEntityFromInversedToOwningIsEagerLoaded() + { + $inversed = $this->_em->find( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToOneEntity', + 'abc' + ); + + $this->assertInstanceOf('Doctrine\Tests\Models\ValueConversionType\OwningOneToOneEntity', $inversed->associatedEntity); + } +} diff --git a/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/tests/Doctrine/Tests/OrmFunctionalTestCase.php index bc301ecfb..cfced6d61 100644 --- a/tests/Doctrine/Tests/OrmFunctionalTestCase.php +++ b/tests/Doctrine/Tests/OrmFunctionalTestCase.php @@ -2,6 +2,7 @@ namespace Doctrine\Tests; +use Doctrine\DBAL\Types\Type; use Doctrine\Tests\EventListener\CacheMetadataListener; use Doctrine\ORM\Cache\Logging\StatisticsCacheLogger; use Doctrine\ORM\Cache\DefaultCacheFactory; @@ -199,6 +200,53 @@ abstract class OrmFunctionalTestCase extends OrmTestCase 'Doctrine\Tests\Models\Quote\Phone', 'Doctrine\Tests\Models\Quote\User' ), + 'vct_onetoone' => array( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToOneEntity', + 'Doctrine\Tests\Models\ValueConversionType\OwningOneToOneEntity' + ), + 'vct_onetoone_compositeid' => array( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToOneCompositeIdEntity', + 'Doctrine\Tests\Models\ValueConversionType\OwningOneToOneCompositeIdEntity' + ), + 'vct_onetoone_compositeid_foreignkey' => array( + 'Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToOneCompositeIdForeignKeyEntity', + 'Doctrine\Tests\Models\ValueConversionType\OwningOneToOneCompositeIdForeignKeyEntity' + ), + 'vct_onetomany' => array( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyEntity', + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneEntity' + ), + 'vct_onetomany_compositeid' => array( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyCompositeIdEntity', + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneCompositeIdEntity' + ), + 'vct_onetomany_compositeid_foreignkey' => array( + 'Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyCompositeIdForeignKeyEntity', + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneCompositeIdForeignKeyEntity' + ), + 'vct_onetomany_extralazy' => array( + 'Doctrine\Tests\Models\ValueConversionType\InversedOneToManyExtraLazyEntity', + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToOneExtraLazyEntity' + ), + 'vct_manytomany' => array( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyEntity', + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyEntity' + ), + 'vct_manytomany_compositeid' => array( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdEntity', + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyCompositeIdEntity' + ), + 'vct_manytomany_compositeid_foreignkey' => array( + 'Doctrine\Tests\Models\ValueConversionType\AuxiliaryEntity', + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyCompositeIdForeignKeyEntity', + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyCompositeIdForeignKeyEntity' + ), + 'vct_manytomany_extralazy' => array( + 'Doctrine\Tests\Models\ValueConversionType\InversedManyToManyExtraLazyEntity', + 'Doctrine\Tests\Models\ValueConversionType\OwningManyToManyExtraLazyEntity' + ), ); /** @@ -358,6 +406,68 @@ abstract class OrmFunctionalTestCase extends OrmTestCase $conn->executeUpdate('DELETE FROM ' . $platform->quoteIdentifier("quote-user")); } + if (isset($this->_usedModelSets['vct_onetoone'])) { + $conn->executeUpdate('DELETE FROM vct_owning_onetoone'); + $conn->executeUpdate('DELETE FROM vct_inversed_onetoone'); + } + + if (isset($this->_usedModelSets['vct_onetoone_compositeid'])) { + $conn->executeUpdate('DELETE FROM vct_owning_onetoone_compositeid'); + $conn->executeUpdate('DELETE FROM vct_inversed_onetoone_compositeid'); + } + + if (isset($this->_usedModelSets['vct_onetoone_compositeid_foreignkey'])) { + $conn->executeUpdate('DELETE FROM vct_owning_onetoone_compositeid_foreignkey'); + $conn->executeUpdate('DELETE FROM vct_inversed_onetoone_compositeid_foreignkey'); + $conn->executeUpdate('DELETE FROM vct_auxiliary'); + } + + if (isset($this->_usedModelSets['vct_onetomany'])) { + $conn->executeUpdate('DELETE FROM vct_owning_manytoone'); + $conn->executeUpdate('DELETE FROM vct_inversed_onetomany'); + } + + if (isset($this->_usedModelSets['vct_onetomany_compositeid'])) { + $conn->executeUpdate('DELETE FROM vct_owning_manytoone_compositeid'); + $conn->executeUpdate('DELETE FROM vct_inversed_onetomany_compositeid'); + } + + if (isset($this->_usedModelSets['vct_onetomany_compositeid_foreignkey'])) { + $conn->executeUpdate('DELETE FROM vct_owning_manytoone_compositeid_foreignkey'); + $conn->executeUpdate('DELETE FROM vct_inversed_onetomany_compositeid_foreignkey'); + $conn->executeUpdate('DELETE FROM vct_auxiliary'); + } + + if (isset($this->_usedModelSets['vct_onetomany_extralazy'])) { + $conn->executeUpdate('DELETE FROM vct_owning_manytoone_extralazy'); + $conn->executeUpdate('DELETE FROM vct_inversed_onetomany_extralazy'); + } + + if (isset($this->_usedModelSets['vct_manytomany'])) { + $conn->executeUpdate('DELETE FROM vct_xref_manytomany'); + $conn->executeUpdate('DELETE FROM vct_owning_manytomany'); + $conn->executeUpdate('DELETE FROM vct_inversed_manytomany'); + } + + if (isset($this->_usedModelSets['vct_manytomany_compositeid'])) { + $conn->executeUpdate('DELETE FROM vct_xref_manytomany_compositeid'); + $conn->executeUpdate('DELETE FROM vct_owning_manytomany_compositeid'); + $conn->executeUpdate('DELETE FROM vct_inversed_manytomany_compositeid'); + } + + if (isset($this->_usedModelSets['vct_manytomany_compositeid_foreignkey'])) { + $conn->executeUpdate('DELETE FROM vct_xref_manytomany_compositeid_foreignkey'); + $conn->executeUpdate('DELETE FROM vct_owning_manytomany_compositeid_foreignkey'); + $conn->executeUpdate('DELETE FROM vct_inversed_manytomany_compositeid_foreignkey'); + $conn->executeUpdate('DELETE FROM vct_auxiliary'); + } + + if (isset($this->_usedModelSets['vct_manytomany_extralazy'])) { + $conn->executeUpdate('DELETE FROM vct_xref_manytomany_extralazy'); + $conn->executeUpdate('DELETE FROM vct_owning_manytomany_extralazy'); + $conn->executeUpdate('DELETE FROM vct_inversed_manytomany_extralazy'); + } + $this->_em->clear(); } @@ -395,6 +505,8 @@ abstract class OrmFunctionalTestCase extends OrmTestCase */ protected function setUp() { + $this->setUpDBALTypes(); + $forceCreateTables = false; if ( ! isset(static::$_sharedConn)) { @@ -582,4 +694,16 @@ abstract class OrmFunctionalTestCase extends OrmTestCase { return count($this->_sqlLoggerStack->queries); } + + /** + * Configures DBAL types required in tests + */ + protected function setUpDBALTypes() + { + if (Type::hasType('rot13')) { + Type::overrideType('rot13', 'Doctrine\Tests\DbalTypes\Rot13Type'); + } else { + Type::addType('rot13', 'Doctrine\Tests\DbalTypes\Rot13Type'); + } + } }