diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadata.php b/lib/Doctrine/ORM/Mapping/ClassMetadata.php
index 15112adbe..f1b374c5d 100644
--- a/lib/Doctrine/ORM/Mapping/ClassMetadata.php
+++ b/lib/Doctrine/ORM/Mapping/ClassMetadata.php
@@ -317,6 +317,10 @@ class ClassMetadata extends ClassMetadataInfo
$serialized[] = 'isMappedSuperclass';
}
+ if ($this->containsForeignIdentifier) {
+ $serialized[] = 'containsForeignIdentifier';
+ }
+
if ($this->isVersioned) {
$serialized[] = 'isVersioned';
$serialized[] = 'versionField';
diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
index 298d5c02d..255b59012 100644
--- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
+++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
@@ -255,7 +255,7 @@ class ClassMetadataInfo
* - scale (integer, optional, schema-only)
* The scale of a decimal column. Only valid if the column type is decimal.
*
- * - unique (string, optional, schema-only)
+ [* - 'unique'] (string, optional, schema-only)
* Whether a unique constraint should be generated for the column.
*
* @var array
@@ -392,6 +392,15 @@ class ClassMetadataInfo
*/
public $isIdentifierComposite = false;
+ /**
+ * READ-ONLY: Flag indicating wheather the identifier/primary key contains at least one foreign key association.
+ *
+ * This flag is necessary because some code blocks require special treatment of this cases.
+ *
+ * @var boolean
+ */
+ public $containsForeignIdentifier = false;
+
/**
* READ-ONLY: The ID generator used for generating IDs for this class.
*
@@ -712,6 +721,10 @@ class ClassMetadataInfo
// Complete id mapping
if (isset($mapping['id']) && $mapping['id'] === true) {
+ if (isset($mapping['orphanRemoval']) && $mapping['orphanRemoval'] == true) {
+ throw MappingException::illegalOrphanRemovalOnIdentifierAssociation($this->name, $mapping['fieldName']);
+ }
+
if ( ! in_array($mapping['fieldName'], $this->identifier)) {
if (count($mapping['joinColumns']) >= 2) {
throw MappingException::cannotMapCompositePrimaryKeyEntitiesAsForeignId(
@@ -720,6 +733,7 @@ class ClassMetadataInfo
}
$this->identifier[] = $mapping['fieldName'];
+ $this->containsForeignIdentifier = true;
}
// Check for composite key
if ( ! $this->isIdentifierComposite && count($this->identifier) > 1) {
@@ -747,6 +761,10 @@ class ClassMetadataInfo
} else {
$mapping['isOwningSide'] = false;
}
+
+ if (isset($mapping['id']) && $mapping['id'] === true && $mapping['type'] & ClassMetadata::TO_MANY) {
+ throw MappingException::illegalToManyIdentifierAssoaction($this->name, $mapping['fieldName']);
+ }
// Fetch mode. Default fetch mode to LAZY, if not set.
if ( ! isset($mapping['fetch'])) {
@@ -797,9 +815,15 @@ class ClassMetadataInfo
'referencedColumnName' => 'id'
));
}
+
+ $uniqueContraintColumns = array();
foreach ($mapping['joinColumns'] as $key => &$joinColumn) {
if ($mapping['type'] === self::ONE_TO_ONE) {
- $joinColumn['unique'] = true;
+ if (count($mapping['joinColumns']) == 1) {
+ $joinColumn['unique'] = true;
+ } else {
+ $uniqueContraintColumns[] = $joinColumn['name'];
+ }
}
if (empty($joinColumn['name'])) {
$joinColumn['name'] = $mapping['fieldName'] . '_id';
@@ -811,6 +835,16 @@ class ClassMetadataInfo
$mapping['joinColumnFieldNames'][$joinColumn['name']] = isset($joinColumn['fieldName'])
? $joinColumn['fieldName'] : $joinColumn['name'];
}
+
+ if ($uniqueContraintColumns) {
+ if (!$this->table) {
+ throw new \RuntimeException("ClassMetadataInfo::setTable() has to be called before defining a one to one relationship.");
+ }
+ $this->table['uniqueConstraints'][$mapping['fieldName']."_uniq"] = array(
+ 'columns' => $uniqueContraintColumns
+ );
+ }
+
$mapping['targetToSourceKeyColumns'] = array_flip($mapping['sourceToTargetKeyColumns']);
}
@@ -818,6 +852,10 @@ class ClassMetadataInfo
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ?
(bool) $mapping['orphanRemoval'] : false;
+ if (isset($mapping['id']) && $mapping['id'] === true && !$mapping['isOwningSide']) {
+ throw MappingException::illegalInverseIdentifierAssocation($this->name, $mapping['fieldName']);
+ }
+
return $mapping;
}
@@ -1547,6 +1585,74 @@ class ClassMetadataInfo
! ($this->associationMappings[$fieldName]['type'] & self::TO_ONE);
}
+ /**
+ * Is this an association that only has a single join column?
+ *
+ * @param string $fieldName
+ * @return bool
+ */
+ public function isAssociationWithSingleJoinColumn($fieldName)
+ {
+ return (
+ isset($this->associationMappings[$fieldName]) &&
+ isset($this->associationMappings[$fieldName]['joinColumns'][0]) &&
+ !isset($this->associationMappings[$fieldName]['joinColumns'][1])
+ );
+ }
+
+ /**
+ * Return the single association join column (if any).
+ *
+ * @param string $fieldName
+ * @return string
+ */
+ public function getSingleAssociationJoinColumnName($fieldName)
+ {
+ if (!$this->isAssociationWithSingleJoinColumn($fieldName)) {
+ throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName);
+ }
+ return $this->associationMappings[$fieldName]['joinColumns'][0]['name'];
+ }
+
+ /**
+ * Return the single association referenced join column name (if any).
+ *
+ * @param string $fieldName
+ * @return string
+ */
+ public function getSingleAssociationReferencedJoinColumnName($fieldName)
+ {
+ if (!$this->isAssociationWithSingleJoinColumn($fieldName)) {
+ throw MappingException::noSingleAssociationJoinColumnFound($this->name, $fieldName);
+ }
+ return $this->associationMappings[$fieldName]['joinColumns'][0]['referencedColumnName'];
+ }
+
+ /**
+ * Used to retrieve a fieldname for either field or association from a given column,
+ *
+ * This method is used in foreign-key as primary-key contexts.
+ *
+ * @param string $columnName
+ * @return string
+ */
+ public function getFieldForColumn($columnName)
+ {
+ if (isset($this->fieldNames[$columnName])) {
+ return $this->fieldNames[$columnName];
+ } else {
+ foreach ($this->associationMappings AS $assocName => $mapping) {
+ if ($this->isAssociationWithSingleJoinColumn($assocName) &&
+ $this->associationMappings[$assocName]['joinColumns'][0]['name'] == $columnName) {
+
+ return $assocName;
+ }
+ }
+
+ throw MappingException::noFieldNameFoundForColumn($this->name, $columnName);
+ }
+ }
+
/**
* Sets the ID generator used to generate IDs for instances of this class.
*
diff --git a/lib/Doctrine/ORM/Mapping/MappingException.php b/lib/Doctrine/ORM/Mapping/MappingException.php
index 3d0e5e1a9..adf8237b7 100644
--- a/lib/Doctrine/ORM/Mapping/MappingException.php
+++ b/lib/Doctrine/ORM/Mapping/MappingException.php
@@ -243,4 +243,31 @@ class MappingException extends \Doctrine\ORM\ORMException
return new self("It is not possible to map entity '".$className."' with a composite primary key ".
"as part of the primary key of another entity '".$targetEntity."#".$targetField."'.");
}
+
+ public static function noSingleAssociationJoinColumnFound($className, $field)
+ {
+ return new self("'$className#$field' is not an association with a single join column.");
+ }
+
+ public static function noFieldNameFoundForColumn($className, $column)
+ {
+ return new self("Cannot find a field on '$className' that is mapped to column '$column'. Either the ".
+ "field does not exist or an association exists but it has multiple join columns.");
+ }
+
+ public static function illegalOrphanRemovalOnIdentifierAssociation($className, $field)
+ {
+ return new self("The orphan removal option is not allowed on an association that is ".
+ "part of the identifier in '$className#$field'.");
+ }
+
+ public static function illegalInverseIdentifierAssocation($className, $field)
+ {
+ return new self("An inverse association is not allowed to be identifier in '$className#$field'.");
+ }
+
+ public static function illegalToManyIdentifierAssoaction($className, $field)
+ {
+ return new self("Many-to-many or one-to-many associations are not allowed to be identifier in '$className#$field'.");
+ }
}
\ No newline at end of file
diff --git a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php
index 1c7e14034..2673a1fd0 100644
--- a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php
+++ b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php
@@ -473,6 +473,8 @@ class BasicEntityPersister
foreach ($assoc['sourceToTargetKeyColumns'] as $sourceColumn => $targetColumn) {
if ($newVal === null) {
$result[$owningTable][$sourceColumn] = null;
+ } else if ($targetClass->containsForeignIdentifier) {
+ $result[$owningTable][$sourceColumn] = $newValId[$targetClass->getFieldForColumn($targetColumn)];
} else {
$result[$owningTable][$sourceColumn] = $newValId[$targetClass->fieldNames[$targetColumn]];
}
@@ -720,13 +722,21 @@ class BasicEntityPersister
* @param PersistentCollection $coll The collection to fill.
*/
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
- {
+ {
$criteria = array();
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
$joinTableConditions = array();
if ($assoc['isOwningSide']) {
foreach ($assoc['relationToSourceKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
- if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
+ if ($sourceClass->containsForeignIdentifier) {
+ $field = $sourceClass->getFieldForColumn($sourceKeyColumn);
+ $value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
+ if (isset($sourceClass->associationMappings[$field])) {
+ $value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
+ $value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
+ }
+ $criteria[$relationKeyColumn] = $value;
+ } else if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
$criteria[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
throw MappingException::joinColumnMustPointToMappedField(
@@ -738,7 +748,15 @@ class BasicEntityPersister
$owningAssoc = $this->_em->getClassMetadata($assoc['targetEntity'])->associationMappings[$assoc['mappedBy']];
// TRICKY: since the association is inverted source and target are flipped
foreach ($owningAssoc['relationToTargetKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
- if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
+ if ($sourceClass->containsForeignIdentifier) {
+ $field = $sourceClass->getFieldForColumn($sourceKeyColumn);
+ $value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
+ if (isset($sourceClass->associationMappings[$field])) {
+ $value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
+ $value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
+ }
+ $criteria[$relationKeyColumn] = $value;
+ } else if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
$criteria[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
throw MappingException::joinColumnMustPointToMappedField(
@@ -955,8 +973,15 @@ class BasicEntityPersister
$joinSql = '';
foreach ($joinClauses as $joinTableColumn => $sourceColumn) {
if ($joinSql != '') $joinSql .= ' AND ';
+
+ if ($this->_class->containsForeignIdentifier && !isset($this->_class->fieldNames[$sourceColumn])) {
+ $quotedColumn = $sourceColumn; // join columns cannot be quoted
+ } else {
+ $quotedColumn = $this->_class->getQuotedColumnName($this->_class->fieldNames[$sourceColumn], $this->_platform);
+ }
+
$joinSql .= $this->_getSQLTableAlias($this->_class->name) .
- '.' . $this->_class->getQuotedColumnName($this->_class->fieldNames[$sourceColumn], $this->_platform) . ' = '
+ '.' . $quotedColumn . ' = '
. $joinTableName . '.' . $joinTableColumn;
}
@@ -1160,7 +1185,17 @@ class BasicEntityPersister
$owningAssoc = $this->_class->associationMappings[$assoc['mappedBy']];
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) {
- $criteria[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
+ if ($sourceClass->containsForeignIdentifier) {
+ $field = $sourceClass->getFieldForColumn($sourceKeyColumn);
+ $value = $sourceClass->reflFields[$field]->getValue($sourceEntity);
+ if (isset($sourceClass->associationMappings[$field])) {
+ $value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
+ $value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
+ }
+ $criteria[$targetKeyColumn] = $value;
+ } else {
+ $criteria[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
+ }
}
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc);
diff --git a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php
index 27e9a57fd..5f24188ca 100644
--- a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php
+++ b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php
@@ -117,13 +117,21 @@ class ManyToManyPersister extends AbstractCollectionPersister
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
if (isset($mapping['relationToSourceKeyColumns'][$joinTableColumn])) {
if ($isComposite) {
- $params[] = $identifier1[$class1->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
+ if ($class1->containsForeignIdentifier) {
+ $params[] = $identifier1[$class1->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])];
+ } else {
+ $params[] = $identifier1[$class1->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
+ }
} else {
$params[] = array_pop($identifier1);
}
} else {
if ($isComposite) {
- $params[] = $identifier2[$class2->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
+ if ($class2->containsForeignIdentifier) {
+ $params[] = $identifier2[$class2->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])];
+ } else {
+ $params[] = $identifier2[$class2->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
+ }
} else {
$params[] = array_pop($identifier2);
}
diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php
index 1512da236..c745d56e6 100644
--- a/lib/Doctrine/ORM/Query/SqlWalker.php
+++ b/lib/Doctrine/ORM/Query/SqlWalker.php
@@ -738,7 +738,11 @@ class SqlWalker implements TreeWalker
}
}
+ // This condition is not checking ClassMetadata::MANY_TO_ONE, because by definition it cannot
+ // be the owning side and previously we ensured that $assoc is always the owning side of the associations.
+ // The owning side is necessary at this point because only it contains the JoinColumn information.
if ($assoc['type'] & ClassMetadata::TO_ONE) {
+
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
$first = true;
@@ -746,15 +750,19 @@ class SqlWalker implements TreeWalker
if ( ! $first) $sql .= ' AND '; else $first = false;
if ($relation['isOwningSide']) {
- $quotedTargetColumn = $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform);
- $sql .= $sourceTableAlias . '.' . $sourceColumn
- . ' = '
- . $targetTableAlias . '.' . $quotedTargetColumn;
+ if ($targetClass->containsForeignIdentifier && !isset($targetClass->fieldNames[$targetColumn])) {
+ $quotedTargetColumn = $targetColumn; // Join columns cannot be quoted.
+ } else {
+ $quotedTargetColumn = $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform);
+ }
+ $sql .= $sourceTableAlias . '.' . $sourceColumn . ' = ' . $targetTableAlias . '.' . $quotedTargetColumn;
} else {
- $quotedTargetColumn = $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform);
- $sql .= $sourceTableAlias . '.' . $quotedTargetColumn
- . ' = '
- . $targetTableAlias . '.' . $sourceColumn;
+ if ($sourceClass->containsForeignIdentifier && !isset($sourceClass->fieldNames[$targetColumn])) {
+ $quotedTargetColumn = $targetColumn; // Join columns cannot be quoted.
+ } else {
+ $quotedTargetColumn = $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform);
+ }
+ $sql .= $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn;
}
}
} else if ($assoc['type'] == ClassMetadata::MANY_TO_MANY) {
@@ -768,17 +776,25 @@ class SqlWalker implements TreeWalker
foreach ($assoc['relationToSourceKeyColumns'] as $relationColumn => $sourceColumn) {
if ( ! $first) $sql .= ' AND '; else $first = false;
- $sql .= $sourceTableAlias . '.' . $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$sourceColumn], $this->_platform)
- . ' = '
- . $joinTableAlias . '.' . $relationColumn;
+ if ($sourceClass->containsForeignIdentifier && !isset($sourceClass->fieldNames[$sourceColumn])) {
+ $quotedTargetColumn = $sourceColumn; // Join columns cannot be quoted.
+ } else {
+ $quotedTargetColumn = $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$sourceColumn], $this->_platform);
+ }
+
+ $sql .= $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $relationColumn;
}
} else {
foreach ($assoc['relationToTargetKeyColumns'] as $relationColumn => $targetColumn) {
if ( ! $first) $sql .= ' AND '; else $first = false;
- $sql .= $sourceTableAlias . '.' . $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform)
- . ' = '
- . $joinTableAlias . '.' . $relationColumn;
+ if ($sourceClass->containsForeignIdentifier && !isset($sourceClass->fieldNames[$targetColumn])) {
+ $quotedTargetColumn = $targetColumn; // Join columns cannot be quoted.
+ } else {
+ $quotedTargetColumn = $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform);
+ }
+
+ $sql .= $sourceTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $relationColumn;
}
}
@@ -792,17 +808,25 @@ class SqlWalker implements TreeWalker
foreach ($assoc['relationToTargetKeyColumns'] as $relationColumn => $targetColumn) {
if ( ! $first) $sql .= ' AND '; else $first = false;
- $sql .= $targetTableAlias . '.' . $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform)
- . ' = '
- . $joinTableAlias . '.' . $relationColumn;
+ if ($targetClass->containsForeignIdentifier && !isset($targetClass->fieldNames[$targetColumn])) {
+ $quotedTargetColumn = $targetColumn; // Join columns cannot be quoted.
+ } else {
+ $quotedTargetColumn = $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform);
+ }
+
+ $sql .= $targetTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $relationColumn;
}
} else {
foreach ($assoc['relationToSourceKeyColumns'] as $relationColumn => $sourceColumn) {
if ( ! $first) $sql .= ' AND '; else $first = false;
- $sql .= $targetTableAlias . '.' . $targetClass->getQuotedColumnName($targetClass->fieldNames[$sourceColumn], $this->_platform)
- . ' = '
- . $joinTableAlias . '.' . $relationColumn;
+ if ($targetClass->containsForeignIdentifier && !isset($targetClass->fieldNames[$sourceColumn])) {
+ $quotedTargetColumn = $sourceColumn; // Join columns cannot be quoted.
+ } else {
+ $quotedTargetColumn = $targetClass->getQuotedColumnName($targetClass->fieldNames[$sourceColumn], $this->_platform);
+ }
+
+ $sql .= $targetTableAlias . '.' . $quotedTargetColumn . ' = ' . $joinTableAlias . '.' . $relationColumn;
}
}
}
diff --git a/lib/Doctrine/ORM/Tools/SchemaTool.php b/lib/Doctrine/ORM/Tools/SchemaTool.php
index 16042d398..f28490e7d 100644
--- a/lib/Doctrine/ORM/Tools/SchemaTool.php
+++ b/lib/Doctrine/ORM/Tools/SchemaTool.php
@@ -444,10 +444,10 @@ class SchemaTool
} else if (in_array($referencedColumnName, $class->getIdentifierColumnNames())) {
// it seems to be an entity as foreign key
foreach ($class->getIdentifierFieldNames() AS $fieldName) {
- if ($class->hasAssociation($fieldName) && $class->associationMappings[$fieldName]['joinColumns'][0]['name'] == $referencedColumnName) {
+ if ($class->hasAssociation($fieldName) && $class->getSingleAssociationJoinColumnName($fieldName) == $referencedColumnName) {
return $this->getDefiningClass(
$this->_em->getClassMetadata($class->associationMappings[$fieldName]['targetEntity']),
- $class->associationMappings[$fieldName]['joinColumns'][0]['referencedColumnName']
+ $class->getSingleAssociationReferencedJoinColumnName($fieldName)
);
}
}
diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php
index 1f05cedf8..ead7e20b9 100644
--- a/lib/Doctrine/ORM/UnitOfWork.php
+++ b/lib/Doctrine/ORM/UnitOfWork.php
@@ -1902,7 +1902,11 @@ class UnitOfWork implements PropertyChangedListener
foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
$joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
if ($joinColumnValue !== null) {
- $associatedId[$targetClass->fieldNames[$targetColumn]] = $joinColumnValue;
+ if ($targetClass->containsForeignIdentifier) {
+ $associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue;
+ } else {
+ $associatedId[$targetClass->fieldNames[$targetColumn]] = $joinColumnValue;
+ }
}
}
if ( ! $associatedId) {
diff --git a/tests/Doctrine/Tests/Models/DDC117/DDC117ApproveChanges.php b/tests/Doctrine/Tests/Models/DDC117/DDC117ApproveChanges.php
new file mode 100644
index 000000000..0a65b62fa
--- /dev/null
+++ b/tests/Doctrine/Tests/Models/DDC117/DDC117ApproveChanges.php
@@ -0,0 +1,65 @@
+articleDetails = $details;
+ $this->reference = $reference;
+ $this->translation = $translation;
+ }
+
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ public function getArticleDetails()
+ {
+ return $this->articleDetails;
+ }
+
+ public function getReference()
+ {
+ return $this->reference;
+ }
+
+ public function getTranslation()
+ {
+ return $this->translation;
+ }
+}
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/Models/DDC117/DDC117Article.php b/tests/Doctrine/Tests/Models/DDC117/DDC117Article.php
new file mode 100644
index 000000000..111c4fabe
--- /dev/null
+++ b/tests/Doctrine/Tests/Models/DDC117/DDC117Article.php
@@ -0,0 +1,81 @@
+title = $title;
+ $this->references = new \Doctrine\Common\Collections\ArrayCollection();
+ $this->translations = new \Doctrine\Common\Collections\ArrayCollection();
+ }
+
+ public function setDetails($details)
+ {
+ $this->details = $details;
+ }
+
+ public function id()
+ {
+ return $this->id;
+ }
+
+ public function addReference($reference)
+ {
+ $this->references[] = $reference;
+ }
+
+ public function references()
+ {
+ return $this->references;
+ }
+
+ public function addTranslation($language, $title)
+ {
+ $this->translations[] = new DDC117Translation($this, $language, $title);
+ }
+
+ public function getText()
+ {
+ return $this->details->getText();
+ }
+
+ public function getDetails()
+ {
+ return $this->details;
+ }
+
+ public function resetText()
+ {
+ $this->details = null;
+ }
+
+ public function getTranslations()
+ {
+ return $this->translations;
+ }
+}
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/Models/DDC117/DDC117ArticleDetails.php b/tests/Doctrine/Tests/Models/DDC117/DDC117ArticleDetails.php
new file mode 100644
index 000000000..ae13df036
--- /dev/null
+++ b/tests/Doctrine/Tests/Models/DDC117/DDC117ArticleDetails.php
@@ -0,0 +1,39 @@
+article = $article;
+ $article->setDetails($this);
+
+ $this->update($text);
+ }
+
+ public function update($text)
+ {
+ $this->text = $text;
+ }
+
+ public function getText()
+ {
+ return $this->text;
+ }
+}
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/Models/DDC117/DDC117Editor.php b/tests/Doctrine/Tests/Models/DDC117/DDC117Editor.php
new file mode 100644
index 000000000..a323bb304
--- /dev/null
+++ b/tests/Doctrine/Tests/Models/DDC117/DDC117Editor.php
@@ -0,0 +1,54 @@
+name = $name;
+ $this->reviewingTranslations = new \Doctrine\Common\Collections\ArrayCollection();
+ }
+
+ public function addLastTranslation(DDC117Translation $t)
+ {
+ $this->lastTranslation = $t;
+ $t->lastTranslatedBy[] = $this;
+ }
+}
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/Models/DDC117/DDC117Reference.php b/tests/Doctrine/Tests/Models/DDC117/DDC117Reference.php
new file mode 100644
index 000000000..80cfb3a83
--- /dev/null
+++ b/tests/Doctrine/Tests/Models/DDC117/DDC117Reference.php
@@ -0,0 +1,64 @@
+addReference($this);
+ $target->addReference($this);
+
+ $this->source = $source;
+ $this->target = $target;
+ $this->description = $description;
+ $this->created = new \DateTime("now");
+ }
+
+ public function source()
+ {
+ return $this->source;
+ }
+
+ public function target()
+ {
+ return $this->target;
+ }
+
+ public function setDescription($desc)
+ {
+ $this->description = $desc;
+ }
+
+ public function getDescription()
+ {
+ return $this->description;
+ }
+}
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/Models/DDC117/DDC117Translation.php b/tests/Doctrine/Tests/Models/DDC117/DDC117Translation.php
new file mode 100644
index 000000000..1d38710c9
--- /dev/null
+++ b/tests/Doctrine/Tests/Models/DDC117/DDC117Translation.php
@@ -0,0 +1,65 @@
+article = $article;
+ $this->language = $language;
+ $this->title = $title;
+ $this->reviewedByEditors = new \Doctrine\Common\Collections\ArrayCollection();
+ $this->lastTranslatedBy = new \Doctrine\Common\Collections\ArrayCollection();
+ }
+
+ public function getArticleId()
+ {
+ return $this->article->id();
+ }
+
+ public function getLanguage()
+ {
+ return $this->language;
+ }
+
+ public function getLastTranslatedBy()
+ {
+ return $this->lastTranslatedBy;
+ }
+
+ public function getReviewedByEditors()
+ {
+ return $this->reviewedByEditors;
+ }
+}
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC117Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC117Test.php
index 64c75870f..309ebf339 100644
--- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC117Test.php
+++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC117Test.php
@@ -2,6 +2,13 @@
namespace Doctrine\Tests\ORM\Functional\Ticket;
+use Doctrine\Tests\Models\DDC117\DDC117ArticleDetails;
+use Doctrine\Tests\Models\DDC117\DDC117Article;
+use Doctrine\Tests\Models\DDC117\DDC117Reference;
+use Doctrine\Tests\Models\DDC117\DDC117Translation;
+use Doctrine\Tests\Models\DDC117\DDC117ApproveChanges;
+use Doctrine\Tests\Models\DDC117\DDC117Editor;
+
require_once __DIR__ . '/../../../TestInit.php';
class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
@@ -13,19 +20,9 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
private $articleDetails;
protected function setUp() {
+ $this->useModelSet('ddc117');
parent::setUp();
- try {
- $this->_schemaTool->createSchema(array(
- $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC117Article'),
- $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC117Reference'),
- $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC117Translation'),
- $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC117ArticleDetails'),
- ));
- } catch(\Exception $e) {
-
- }
-
$this->article1 = new DDC117Article("Foo");
$this->article2 = new DDC117Article("Bar");
@@ -53,33 +50,33 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
$idCriteria = array('source' => $this->article1->id(), 'target' => $this->article2->id());
- $mapRef = $this->_em->find(__NAMESPACE__."\DDC117Reference", $idCriteria);
- $this->assertType(__NAMESPACE__."\DDC117Reference", $mapRef);
- $this->assertType(__NAMESPACE__."\DDC117Article", $mapRef->target());
- $this->assertType(__NAMESPACE__."\DDC117Article", $mapRef->source());
- $this->assertSame($mapRef, $this->_em->find(__NAMESPACE__."\DDC117Reference", $idCriteria));
+ $mapRef = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria);
+ $this->assertType("Doctrine\Tests\Models\DDC117\DDC117Reference", $mapRef);
+ $this->assertType("Doctrine\Tests\Models\DDC117\DDC117Article", $mapRef->target());
+ $this->assertType("Doctrine\Tests\Models\DDC117\DDC117Article", $mapRef->source());
+ $this->assertSame($mapRef, $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria));
$this->_em->clear();
- $dql = "SELECT r, s FROM ".__NAMESPACE__."\DDC117Reference r JOIN r.source s WHERE r.source = ?1";
+ $dql = "SELECT r, s FROM "."Doctrine\Tests\Models\DDC117\DDC117Reference r JOIN r.source s WHERE r.source = ?1";
$dqlRef = $this->_em->createQuery($dql)->setParameter(1, 1)->getSingleResult();
- $this->assertType(__NAMESPACE__."\DDC117Reference", $mapRef);
- $this->assertType(__NAMESPACE__."\DDC117Article", $mapRef->target());
- $this->assertType(__NAMESPACE__."\DDC117Article", $mapRef->source());
- $this->assertSame($dqlRef, $this->_em->find(__NAMESPACE__."\DDC117Reference", $idCriteria));
+ $this->assertType("Doctrine\Tests\Models\DDC117\DDC117Reference", $mapRef);
+ $this->assertType("Doctrine\Tests\Models\DDC117\DDC117Article", $mapRef->target());
+ $this->assertType("Doctrine\Tests\Models\DDC117\DDC117Article", $mapRef->source());
+ $this->assertSame($dqlRef, $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria));
$this->_em->clear();
- $dql = "SELECT r, s FROM ".__NAMESPACE__."\DDC117Reference r JOIN r.source s WHERE s.title = ?1";
+ $dql = "SELECT r, s FROM "."Doctrine\Tests\Models\DDC117\DDC117Reference r JOIN r.source s WHERE s.title = ?1";
$dqlRef = $this->_em->createQuery($dql)->setParameter(1, 'Foo')->getSingleResult();
- $this->assertType(__NAMESPACE__."\DDC117Reference", $dqlRef);
- $this->assertType(__NAMESPACE__."\DDC117Article", $dqlRef->target());
- $this->assertType(__NAMESPACE__."\DDC117Article", $dqlRef->source());
- $this->assertSame($dqlRef, $this->_em->find(__NAMESPACE__."\DDC117Reference", $idCriteria));
+ $this->assertType("Doctrine\Tests\Models\DDC117\DDC117Reference", $dqlRef);
+ $this->assertType("Doctrine\Tests\Models\DDC117\DDC117Article", $dqlRef->target());
+ $this->assertType("Doctrine\Tests\Models\DDC117\DDC117Article", $dqlRef->source());
+ $this->assertSame($dqlRef, $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria));
- $dql = "SELECT r, s FROM ".__NAMESPACE__."\DDC117Reference r JOIN r.source s WHERE s.title = ?1";
+ $dql = "SELECT r, s FROM "."Doctrine\Tests\Models\DDC117\DDC117Reference r JOIN r.source s WHERE s.title = ?1";
$dqlRef = $this->_em->createQuery($dql)->setParameter(1, 'Foo')->getSingleResult();
$this->_em->contains($dqlRef);
@@ -92,13 +89,13 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
$idCriteria = array('source' => $this->article1->id(), 'target' => $this->article2->id());
- $mapRef = $this->_em->find(__NAMESPACE__."\DDC117Reference", $idCriteria);
+ $mapRef = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria);
$this->assertNotNull($mapRef);
$mapRef->setDescription("New Description!!");
$this->_em->flush();
$this->_em->clear();
- $mapRef = $this->_em->find(__NAMESPACE__."\DDC117Reference", $idCriteria);
+ $mapRef = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria);
$this->assertEquals('New Description!!', $mapRef->getDescription());
}
@@ -108,12 +105,12 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
*/
public function testFetchDql()
{
- $dql = "SELECT r, s FROM ".__NAMESPACE__."\DDC117Reference r JOIN r.source s WHERE s.title = ?1";
+ $dql = "SELECT r, s FROM "."Doctrine\Tests\Models\DDC117\DDC117Reference r JOIN r.source s WHERE s.title = ?1";
$refs = $this->_em->createQuery($dql)->setParameter(1, 'Foo')->getResult();
$this->assertTrue(count($refs) > 0, "Has to contain at least one Reference.");
foreach ($refs AS $ref) {
- $this->assertType(__NAMESPACE__."\DDC117Reference", $ref, "Contains only Reference instances.");
+ $this->assertType("Doctrine\Tests\Models\DDC117\DDC117Reference", $ref, "Contains only Reference instances.");
$this->assertTrue($this->_em->contains($ref), "Contains Reference in the IdentityMap.");
}
}
@@ -125,13 +122,13 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
$idCriteria = array('source' => $this->article1->id(), 'target' => $this->article2->id());
- $refRep = $this->_em->find(__NAMESPACE__."\DDC117Reference", $idCriteria);
+ $refRep = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria);
$this->_em->remove($refRep);
$this->_em->flush();
$this->_em->clear();
- $this->assertNull($this->_em->find(__NAMESPACE__."\DDC117Reference", $idCriteria));
+ $this->assertNull($this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria));
}
/**
@@ -141,13 +138,13 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
$idCriteria = array('source' => $this->article1->id(), 'target' => $this->article2->id());
- $dql = "DELETE ".__NAMESPACE__."\DDC117Reference r WHERE r.source = ?1 AND r.target = ?2";
+ $dql = "DELETE "."Doctrine\Tests\Models\DDC117\DDC117Reference r WHERE r.source = ?1 AND r.target = ?2";
$this->_em->createQuery($dql)
->setParameter(1, $this->article1->id())
->setParameter(2, $this->article2->id())
->execute();
- $this->assertNull($this->_em->find(__NAMESPACE__."\DDC117Reference", $idCriteria));
+ $this->assertNull($this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria));
}
/**
@@ -155,24 +152,24 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
*/
public function testInverseSideAccess()
{
- $this->article1 = $this->_em->find(__NAMESPACE__."\DDC117Article", $this->article1->id());
+ $this->article1 = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Article", $this->article1->id());
$this->assertEquals(1, count($this->article1->references()));
foreach ($this->article1->references() AS $this->reference) {
- $this->assertType(__NAMESPACE__."\DDC117Reference", $this->reference);
+ $this->assertType("Doctrine\Tests\Models\DDC117\DDC117Reference", $this->reference);
$this->assertSame($this->article1, $this->reference->source());
}
$this->_em->clear();
- $dql = 'SELECT a, r FROM '. __NAMESPACE__ . '\DDC117Article a INNER JOIN a.references r WHERE a.id = ?1';
+ $dql = 'SELECT a, r FROM '. 'Doctrine\Tests\Models\DDC117\DDC117Article a INNER JOIN a.references r WHERE a.id = ?1';
$articleDql = $this->_em->createQuery($dql)
->setParameter(1, $this->article1->id())
->getSingleResult();
$this->assertEquals(1, count($this->article1->references()));
foreach ($this->article1->references() AS $this->reference) {
- $this->assertType(__NAMESPACE__."\DDC117Reference", $this->reference);
+ $this->assertType("Doctrine\Tests\Models\DDC117\DDC117Reference", $this->reference);
$this->assertSame($this->article1, $this->reference->source());
}
}
@@ -184,20 +181,20 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
{
$idCriteria = array('article' => $this->article1->id(), 'language' => 'en');
- $this->translation = $this->_em->find(__NAMESPACE__ . '\DDC117Translation', $idCriteria);
- $this->assertType(__NAMESPACE__ . '\DDC117Translation', $this->translation);
+ $this->translation = $this->_em->find('Doctrine\Tests\Models\DDC117\DDC117Translation', $idCriteria);
+ $this->assertType('Doctrine\Tests\Models\DDC117\DDC117Translation', $this->translation);
- $this->assertSame($this->translation, $this->_em->find(__NAMESPACE__ . '\DDC117Translation', $idCriteria));
+ $this->assertSame($this->translation, $this->_em->find('Doctrine\Tests\Models\DDC117\DDC117Translation', $idCriteria));
$this->_em->clear();
- $dql = 'SELECT t, a FROM ' . __NAMESPACE__ . '\DDC117Translation t JOIN t.article a WHERE t.article = ?1 AND t.language = ?2';
+ $dql = 'SELECT t, a FROM ' . 'Doctrine\Tests\Models\DDC117\DDC117Translation t JOIN t.article a WHERE t.article = ?1 AND t.language = ?2';
$dqlTrans = $this->_em->createQuery($dql)
->setParameter(1, $this->article1->id())
->setParameter(2, 'en')
->getSingleResult();
- $this->assertType(__NAMESPACE__ . '\DDC117Translation', $this->translation);
+ $this->assertType('Doctrine\Tests\Models\DDC117\DDC117Translation', $this->translation);
}
/**
@@ -205,7 +202,7 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
*/
public function testMixedCompositeKeyViolateUniqueness()
{
- $this->article1 = $this->_em->find(__NAMESPACE__ . '\DDC117Article', $this->article1->id());
+ $this->article1 = $this->_em->find('Doctrine\Tests\Models\DDC117\DDC117Article', $this->article1->id());
$this->article1->addTranslation('en', 'Bar');
$this->article1->addTranslation('en', 'Baz');
@@ -235,6 +232,18 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->assertEquals('not so very long text!', $article->getText());
}
+ /**
+ * @group DDC-117
+ */
+ public function testOneToOneCascadeRemove()
+ {
+ $article = $this->_em->find(get_class($this->article1), $this->article1->id());
+ $this->_em->remove($article);
+ $this->_em->flush();
+
+ $this->assertFalse($this->_em->contains($article->getDetails()));
+ }
+
/**
* @group DDC-117
*/
@@ -251,194 +260,151 @@ class DDC117Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->persist($this->article1);
$this->_em->flush();
}
-}
-
-/**
- * @Entity
- */
-class DDC117Article
-{
- /** @Id @Column(type="integer", name="article_id") @GeneratedValue */
- private $id;
- /** @Column */
- private $title;
/**
- * @OneToMany(targetEntity="DDC117Reference", mappedBy="source")
+ * @group DDC-117
*/
- private $references;
+ public function testReferencesToForeignKeyEntities()
+ {
+ $idCriteria = array('source' => $this->article1->id(), 'target' => $this->article2->id());
+ $reference = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117Reference", $idCriteria);
+
+ $idCriteria = array('article' => $this->article1->id(), 'language' => 'en');
+ $translation = $this->_em->find('Doctrine\Tests\Models\DDC117\DDC117Translation', $idCriteria);
+
+ $approveChanges = new DDC117ApproveChanges($reference->source()->getDetails(), $reference, $translation);
+ $this->_em->persist($approveChanges);
+ $this->_em->flush();
+ $this->_em->clear();
+
+ $approveChanges = $this->_em->find("Doctrine\Tests\Models\DDC117\DDC117ApproveChanges", $approveChanges->getId());
+
+ $this->assertType('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails', $approveChanges->getArticleDetails());
+ $this->assertType('Doctrine\Tests\Models\DDC117\DDC117Reference', $approveChanges->getReference());
+ $this->assertType('Doctrine\Tests\Models\DDC117\DDC117Translation', $approveChanges->getTranslation());
+ }
/**
- * @OneToOne(targetEntity="DDC117ArticleDetails", mappedBy="article", cascade={"persist"})
+ * @group DDC-117
*/
- private $details;
+ public function testLoadOneToManyCollectionOfForeignKeyEntities()
+ {
+ /* @var $article DDC117Article */
+ $article = $this->_em->find(get_class($this->article1), $this->article1->id());
+
+ $translations = $article->getTranslations();
+ $this->assertFalse($translations->isInitialized());
+ $this->assertContainsOnly('Doctrine\Tests\Models\DDC117\DDC117Translation', $translations);
+ $this->assertTrue($translations->isInitialized());
+ }
/**
- * @OneToMany(targetEntity="DDC117Translation", mappedBy="article", cascade={"persist"})
+ * @group DDC-117
*/
- private $translations;
-
- public function __construct($title)
+ public function testLoadManyToManyCollectionOfForeignKeyEntities()
{
- $this->title = $title;
- $this->references = new \Doctrine\Common\Collections\ArrayCollection();
- $this->translations = new \Doctrine\Common\Collections\ArrayCollection();
+ $editor = $this->loadEditorFixture();
+
+ $this->assertFalse($editor->reviewingTranslations->isInitialized());
+ $this->assertContainsOnly("Doctrine\Tests\Models\DDC117\DDC117Translation", $editor->reviewingTranslations);
+ $this->assertTrue($editor->reviewingTranslations->isInitialized());
+
+ $this->_em->clear();
+
+ $dql = "SELECT e, t FROM Doctrine\Tests\Models\DDC117\DDC117Editor e JOIN e.reviewingTranslations t WHERE e.id = ?1";
+ $editor = $this->_em->createQuery($dql)->setParameter(1, $editor->id)->getSingleResult();
+ $this->assertTrue($editor->reviewingTranslations->isInitialized());
+ $this->assertContainsOnly("Doctrine\Tests\Models\DDC117\DDC117Translation", $editor->reviewingTranslations);
}
- public function setDetails($details)
+ /**
+ * @group DDC-117
+ */
+ public function testClearManyToManyCollectionOfForeignKeyEntities()
{
- $this->details = $details;
+ $editor = $this->loadEditorFixture();
+ $this->assertEquals(3, count($editor->reviewingTranslations));
+
+ $editor->reviewingTranslations->clear();
+ $this->_em->flush();
+ $this->_em->clear();
+
+ $editor = $this->_em->find(get_class($editor), $editor->id);
+ $this->assertEquals(0, count($editor->reviewingTranslations));
}
- public function id()
+ /**
+ * @group DDC-117
+ */
+ public function testLoadInverseManyToManyCollection()
{
- return $this->id;
+ $editor = $this->loadEditorFixture();
+
+ $this->assertType('Doctrine\Tests\Models\DDC117\DDC117Translation', $editor->reviewingTranslations[0]);
+
+ $reviewedBy = $editor->reviewingTranslations[0]->getReviewedByEditors();
+ $this->assertEquals(1, count($reviewedBy));
+ $this->assertSame($editor, $reviewedBy[0]);
+
+ $this->_em->clear();
+
+ $dql = "SELECT t, e FROM Doctrine\Tests\Models\DDC117\DDC117Translation t ".
+ "JOIN t.reviewedByEditors e WHERE t.article = ?1 AND t.language = ?2";
+ $trans = $this->_em->createQuery($dql)
+ ->setParameter(1, $this->translation->getArticleId())
+ ->setParameter(2, $this->translation->getLanguage())
+ ->getSingleResult();
+
+ $this->assertType('Doctrine\Tests\Models\DDC117\DDC117Translation', $trans);
+ $this->assertContainsOnly('Doctrine\Tests\Models\DDC117\DDC117Editor', $trans->reviewedByEditors);
+ $this->assertEquals(1, count($trans->reviewedByEditors));
}
- public function addReference($reference)
+ /**
+ * @group DDC-117
+ */
+ public function testLoadOneToManyOfSourceEntityWithAssociationIdentifier()
{
- $this->references[] = $reference;
+ $editor = $this->loadEditorFixture();
+
+ $editor->addLastTranslation($editor->reviewingTranslations[0]);
+ $this->_em->flush();
+ $this->_em->clear();
+
+ $editor = $this->_em->find(get_class($editor), $editor->id);
+ $lastTranslatedBy = $editor->reviewingTranslations[0]->getLastTranslatedBy();
+ $lastTranslatedBy->count();
+
+ $this->assertEquals(1, count($lastTranslatedBy));
}
- public function references()
+ /**
+ * @return DDC117Editor
+ */
+ private function loadEditorFixture()
{
- return $this->references;
- }
+ $editor = new DDC117Editor("beberlei");
- public function addTranslation($language, $title)
- {
- $this->translations[] = new DDC117Translation($this, $language, $title);
- }
+ /* @var $article1 DDC117Article */
+ $article1 = $this->_em->find(get_class($this->article1), $this->article1->id());
+ foreach ($article1->getTranslations() AS $translation) {
+ $editor->reviewingTranslations[] = $translation;
+ }
- public function getText()
- {
- return $this->details->getText();
+ /* @var $article2 DDC117Article */
+ $article2 = $this->_em->find(get_class($this->article2), $this->article2->id());
+ $article2->addTranslation("de", "Vanille-Krapferl"); // omnomnom
+ $article2->addTranslation("fr", "Sorry can't speak french!");
+
+ foreach ($article2->getTranslations() AS $translation) {
+ $this->_em->persist($translation); // otherwise persisting the editor won't work, reachability!
+ $editor->reviewingTranslations[] = $translation;
+ }
+
+ $this->_em->persist($editor);
+ $this->_em->flush();
+ $this->_em->clear();
+
+ return $this->_em->find(get_class($editor), $editor->id);
}
}
-
-/**
- * @Entity
- */
-class DDC117ArticleDetails
-{
- /**
- * @Id
- * @OneToOne(targetEntity="DDC117Article", inversedBy="details")
- * @JoinColumn(name="article_id", referencedColumnName="article_id")
- */
- private $article;
-
- /**
- * @Column(type="text")
- */
- private $text;
-
- public function __construct($article, $text)
- {
- $this->article = $article;
- $article->setDetails($this);
-
- $this->update($text);
- }
-
- public function update($text)
- {
- $this->text = $text;
- }
-
- public function getText()
- {
- return $this->text;
- }
-}
-
-/**
- * @Entity
- */
-class DDC117Reference
-{
- /**
- * @Id
- * @ManyToOne(targetEntity="DDC117Article", inversedBy="references")
- * @JoinColumn(name="source_id", referencedColumnName="article_id")
- */
- private $source;
-
- /**
- * @Id
- * @ManyToOne(targetEntity="DDC117Article", inversedBy="references")
- * @JoinColumn(name="target_id", referencedColumnName="article_id")
- */
- private $target;
-
- /**
- * @column(type="string")
- */
- private $description;
-
- /**
- * @column(type="datetime")
- */
- private $created;
-
- public function __construct($source, $target, $description)
- {
- $source->addReference($this);
- $target->addReference($this);
-
- $this->source = $source;
- $this->target = $target;
- $this->description = $description;
- $this->created = new \DateTime("now");
- }
-
- public function source()
- {
- return $this->source;
- }
-
- public function target()
- {
- return $this->target;
- }
-
- public function setDescription($desc)
- {
- $this->description = $desc;
- }
-
- public function getDescription()
- {
- return $this->description;
- }
-}
-
-/**
- * @Entity
- */
-class DDC117Translation
-{
- /**
- * @Id
- * @ManyToOne(targetEntity="DDC117Article")
- * @JoinColumn(name="article_id", referencedColumnName="article_id")
- */
- private $article;
-
- /**
- * @Id @column(type="string")
- */
- private $language;
-
- /**
- * @column(type="string")
- */
- private $title;
-
- public function __construct($article, $language, $title)
- {
- $this->article = $article;
- $this->language = $language;
- $this->title = $title;
- }
-}
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC881Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC881Test.php
index 8b8aba843..fc43c207a 100644
--- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC881Test.php
+++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC881Test.php
@@ -18,7 +18,7 @@ class DDC881Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC881Phonecall'),
));
} catch (\Exception $e) {
-
+
}
}
@@ -74,6 +74,22 @@ class DDC881Test extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->persist($call2);
$this->_em->flush();
+ $this->_em->clear();
+
+ // fetch-join that foreign-key/primary-key entity association
+ $dql = "SELECT c, p FROM " . __NAMESPACE__ . "\DDC881PhoneCall c JOIN c.phonenumber p";
+ $calls = $this->_em->createQuery($dql)->getResult();
+
+ $this->assertEquals(2, count($calls));
+ $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $calls[0]->getPhoneNumber());
+ $this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $calls[1]->getPhoneNumber());
+
+ $dql = "SELECT p, c FROM " . __NAMESPACE__ . "\DDC881PhoneNumber p JOIN p.calls c";
+ $numbers = $this->_em->createQuery($dql)->getResult();
+
+ $this->assertEquals(2, count($numbers));
+ $this->assertInstanceOf('Doctrine\ORM\PersistentCollection', $numbers[0]->getCalls());
+ $this->assertTrue($numbers[0]->getCalls()->isInitialized());
}
}
@@ -131,6 +147,16 @@ class DDC881PhoneNumber
*/
private $phonenumber;
+ /**
+ * @OneToMany(targetEntity="DDC881PhoneCall", mappedBy="phonenumber")
+ */
+ private $calls;
+
+ public function __construct()
+ {
+ $this->calls = new \Doctrine\Common\Collections\ArrayCollection();
+ }
+
public function setId($id)
{
$this->id = $id;
@@ -146,6 +172,10 @@ class DDC881PhoneNumber
$this->phonenumber = $phoneNumber;
}
+ public function getCalls()
+ {
+ return $this->calls;
+ }
}
/**
@@ -161,7 +191,7 @@ class DDC881PhoneCall
*/
private $id;
/**
- * @OneToOne(targetEntity="DDC881PhoneNumber",cascade={"all"})
+ * @ManyToOne(targetEntity="DDC881PhoneNumber", inversedBy="calls", cascade={"all"})
* @JoinColumns({
* @JoinColumn(name="phonenumber_id", referencedColumnName="id"),
* @JoinColumn(name="user_id", referencedColumnName="user_id")
@@ -178,4 +208,8 @@ class DDC881PhoneCall
$this->phonenumber = $phoneNumber;
}
+ public function getPhoneNumber()
+ {
+ return $this->phonenumber;
+ }
}
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php
index f8425b42f..f09d4d72c 100644
--- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php
+++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php
@@ -300,4 +300,71 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException', "No mapping found for field 'foo' on class 'Doctrine\Tests\Models\CMS\CmsUser'.");
$cm->getFieldMapping('foo');
}
+
+ /**
+ * @group DDC-117
+ */
+ public function testMapIdentifierAssociation()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails');
+ $cm->mapOneToOne(array(
+ 'fieldName' => 'article',
+ 'id' => true,
+ 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article',
+ 'joinColumns' => array(),
+ ));
+
+ $this->assertTrue($cm->containsForeignIdentifier, "Identifier Association should set 'containsForeignIdentifier' boolean flag.");
+ $this->assertEquals(array("article"), $cm->identifier);
+ }
+
+ /**
+ * @group DDC-117
+ */
+ public function testOrphanRemovalIdentifierAssociation()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails');
+
+ $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', 'The orphan removal option is not allowed on an association that');
+ $cm->mapOneToOne(array(
+ 'fieldName' => 'article',
+ 'id' => true,
+ 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article',
+ 'orphanRemoval' => true,
+ 'joinColumns' => array(),
+ ));
+ }
+
+ /**
+ * @group DDC-117
+ */
+ public function testInverseIdentifierAssocation()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails');
+
+ $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', 'An inverse association is not allowed to be identifier in');
+ $cm->mapOneToOne(array(
+ 'fieldName' => 'article',
+ 'id' => true,
+ 'mappedBy' => 'details', // INVERSE!
+ 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article',
+ 'joinColumns' => array(),
+ ));
+ }
+
+ /**
+ * @group DDC-117
+ */
+ public function testIdentifierAssocationManyToMany()
+ {
+ $cm = new ClassMetadata('Doctrine\Tests\Models\DDC117\DDC117ArticleDetails');
+
+ $this->setExpectedException('Doctrine\ORM\Mapping\MappingException', 'Many-to-many or one-to-many associations are not allowed to be identifier in');
+ $cm->mapManyToMany(array(
+ 'fieldName' => 'article',
+ 'id' => true,
+ 'targetEntity' => 'Doctrine\Tests\Models\DDC117\DDC117Article',
+ 'joinColumns' => array(),
+ ));
+ }
}
\ No newline at end of file
diff --git a/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php b/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php
index 0ebe1aafe..fae0d7350 100644
--- a/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php
+++ b/tests/Doctrine/Tests/ORM/Query/LanguageRecognitionTest.php
@@ -495,6 +495,22 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
{
$this->assertInvalidDQL('SELECT g FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.groups g');
}
+
+ /**
+ * @group DDC-117
+ */
+ public function testSizeOfForeignKeyOneToManyPrimaryKeyEntity()
+ {
+ $this->assertValidDQL("SELECT a, t FROM Doctrine\Tests\Models\DDC117\DDC117Article a JOIN a.translations t WHERE SIZE(a.translations) > 0");
+ }
+
+ /**
+ * @group DDC-117
+ */
+ public function testSizeOfForeignKeyManyToManyPrimaryKeyEntity()
+ {
+ $this->assertValidDQL("SELECT e, t FROM Doctrine\Tests\Models\DDC117\DDC117Editor e JOIN e.reviewingTranslations t WHERE SIZE(e.reviewingTranslations) > 0");
+ }
}
/** @Entity */
diff --git a/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/tests/Doctrine/Tests/OrmFunctionalTestCase.php
index f7674ed4e..abf04efab 100644
--- a/tests/Doctrine/Tests/OrmFunctionalTestCase.php
+++ b/tests/Doctrine/Tests/OrmFunctionalTestCase.php
@@ -91,6 +91,14 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
'Doctrine\Tests\Models\DirectoryTree\File',
'Doctrine\Tests\Models\DirectoryTree\Directory',
),
+ 'ddc117' => array(
+ 'Doctrine\Tests\Models\DDC117\DDC117Article',
+ 'Doctrine\Tests\Models\DDC117\DDC117Reference',
+ 'Doctrine\Tests\Models\DDC117\DDC117Translation',
+ 'Doctrine\Tests\Models\DDC117\DDC117ArticleDetails',
+ 'Doctrine\Tests\Models\DDC117\DDC117ApproveChanges',
+ 'Doctrine\Tests\Models\DDC117\DDC117Editor',
+ ),
);
protected function useModelSet($setName)
@@ -173,6 +181,16 @@ abstract class OrmFunctionalTestCase extends OrmTestCase
$conn->executeUpdate('DELETE FROM Directory WHERE parentDirectory_id IS NOT NULL');
$conn->executeUpdate('DELETE FROM Directory');
}
+ if (isset($this->_usedModelSets['ddc117'])) {
+ return;
+ $conn->executeUpdate('DELETE FROM ddc117editor_ddc117translation');
+ $conn->executeUpdate('DELETE FROM DDC117Editor');
+ $conn->executeUpdate('DELETE FROM DDC117ApproveChanges');
+ $conn->executeUpdate('DELETE FROM DDC117Reference');
+ $conn->executeUpdate('DELETE FROM DDC117ArticleDetails');
+ $conn->executeUpdate('DELETE FROM DDC117Translation');
+ $conn->executeUpdate('DELETE FROM DDC117Article');
+ }
$this->_em->clear();
}
diff --git a/tests/Doctrine/Tests/TestUtil.php b/tests/Doctrine/Tests/TestUtil.php
index 185bb65a7..5a187e595 100644
--- a/tests/Doctrine/Tests/TestUtil.php
+++ b/tests/Doctrine/Tests/TestUtil.php
@@ -93,6 +93,10 @@ class TestUtil
'driver' => 'pdo_sqlite',
'memory' => true
);
+ if (isset($GLOBALS['db_path'])) {
+ $params['path'] = $GLOBALS['db_path'];
+ unlink($GLOBALS['db_path']);
+ }
$conn = \Doctrine\DBAL\DriverManager::getConnection($params);
}