1
0
mirror of synced 2024-12-13 22:56:04 +03:00

Merge branch 'DDC-626'

This commit is contained in:
Roman S. Borschel 2010-08-09 22:50:21 +02:00
commit 139f8b52ab
49 changed files with 823 additions and 1545 deletions

View File

@ -19,7 +19,7 @@
namespace Doctrine\ORM\Internal\Hydration;
use PDO, Doctrine\DBAL\Connection;
use PDO, Doctrine\DBAL\Connection, Doctrine\ORM\Mapping\ClassMetadata;
/**
* The ArrayHydrator produces a nested array "graph" that is often (not always)
@ -109,7 +109,7 @@ class ArrayHydrator extends AbstractHydrator
$relation = $this->_getClassMetadata($this->_rsm->aliasMap[$parent])->associationMappings[$relationAlias];
// Check the type of the relation (many or single-valued)
if ( ! $relation->isOneToOne()) {
if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
$oneToOne = false;
if (isset($nonemptyComponents[$dqlAlias])) {
if ( ! isset($baseElement[$relationAlias])) {

View File

@ -20,6 +20,7 @@
namespace Doctrine\ORM\Internal\Hydration;
use PDO,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\PersistentCollection,
Doctrine\ORM\Query,
Doctrine\Common\Collections\ArrayCollection,
@ -74,24 +75,24 @@ class ObjectHydrator extends AbstractHydrator
$sourceClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]];
$sourceClass = $this->_getClassMetadata($sourceClassName);
$assoc = $sourceClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]];
$this->_hints['fetched'][$sourceClassName][$assoc->sourceFieldName] = true;
$this->_hints['fetched'][$sourceClassName][$assoc['fieldName']] = true;
if ($sourceClass->subClasses) {
foreach ($sourceClass->subClasses as $sourceSubclassName) {
$this->_hints['fetched'][$sourceSubclassName][$assoc->sourceFieldName] = true;
$this->_hints['fetched'][$sourceSubclassName][$assoc['fieldName']] = true;
}
}
if ( ! $assoc->isManyToMany()) {
if ($assoc['type'] != ClassMetadata::MANY_TO_MANY) {
// Mark any non-collection opposite sides as fetched, too.
if ($assoc->mappedBy) {
$this->_hints['fetched'][$className][$assoc->mappedBy] = true;
if ($assoc['mappedBy']) {
$this->_hints['fetched'][$className][$assoc['mappedBy']] = true;
} else {
if ($assoc->inversedBy) {
$inverseAssoc = $class->associationMappings[$assoc->inversedBy];
if ($inverseAssoc->isOneToOne()) {
$this->_hints['fetched'][$className][$inverseAssoc->sourceFieldName] = true;
if ($assoc['inversedBy']) {
$inverseAssoc = $class->associationMappings[$assoc['inversedBy']];
if ($inverseAssoc['type'] & ClassMetadata::TO_ONE) {
$this->_hints['fetched'][$className][$inverseAssoc['fieldName']] = true;
if ($class->subClasses) {
foreach ($class->subClasses as $targetSubclassName) {
$this->_hints['fetched'][$targetSubclassName][$inverseAssoc->sourceFieldName] = true;
$this->_hints['fetched'][$targetSubclassName][$inverseAssoc['fieldName']] = true;
}
}
}
@ -153,7 +154,7 @@ class ObjectHydrator extends AbstractHydrator
if ( ! $value instanceof PersistentCollection) {
$value = new PersistentCollection(
$this->_em,
$this->_ce[$relation->targetEntityName],
$this->_ce[$relation['targetEntity']],
$value
);
$value->setOwner($entity, $relation);
@ -285,9 +286,9 @@ class ObjectHydrator extends AbstractHydrator
$relationField = $this->_rsm->relationMap[$dqlAlias];
$relation = $parentClass->associationMappings[$relationField];
$reflField = $parentClass->reflFields[$relationField];
// Check the type of the relation (many or single-valued)
if ( ! $relation->isOneToOne()) {
if ( ! ($relation['type'] & ClassMetadata::TO_ONE)) {
// PATH A: Collection-valued association
if (isset($nonemptyComponents[$dqlAlias])) {
$collKey = $oid . $relationField;
@ -342,24 +343,24 @@ class ObjectHydrator extends AbstractHydrator
$element = $this->_getEntity($data, $dqlAlias);
$reflField->setValue($parentObject, $element);
$this->_uow->setOriginalEntityProperty($oid, $relationField, $element);
$targetClass = $this->_ce[$relation->targetEntityName];
if ($relation->isOwningSide) {
$targetClass = $this->_ce[$relation['targetEntity']];
if ($relation['isOwningSide']) {
//TODO: Just check hints['fetched'] here?
// If there is an inverse mapping on the target class its bidirectional
if ($relation->inversedBy) {
$inverseAssoc = $targetClass->associationMappings[$relation->inversedBy];
if ($inverseAssoc->isOneToOne()) {
$targetClass->reflFields[$inverseAssoc->sourceFieldName]->setValue($element, $parentObject);
$this->_uow->setOriginalEntityProperty(spl_object_hash($element), $inverseAssoc->sourceFieldName, $parentObject);
if ($relation['inversedBy']) {
$inverseAssoc = $targetClass->associationMappings[$relation['inversedBy']];
if ($inverseAssoc['type'] & ClassMetadata::TO_ONE) {
$targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($element, $parentObject);
$this->_uow->setOriginalEntityProperty(spl_object_hash($element), $inverseAssoc['fieldName'], $parentObject);
}
} else if ($parentClass === $targetClass && $relation->mappedBy) {
} else if ($parentClass === $targetClass && $relation['mappedBy']) {
// Special case: bi-directional self-referencing one-one on the same class
$targetClass->reflFields[$relationField]->setValue($element, $parentObject);
}
} else {
// For sure bidirectional, as there is no inverse side in unidirectional mappings
$targetClass->reflFields[$relation->mappedBy]->setValue($element, $parentObject);
$this->_uow->setOriginalEntityProperty(spl_object_hash($element), $relation->mappedBy, $parentObject);
$targetClass->reflFields[$relation['mappedBy']]->setValue($element, $parentObject);
$this->_uow->setOriginalEntityProperty(spl_object_hash($element), $relation['mappedBy'], $parentObject);
}
// Update result pointer
$this->_resultPointers[$dqlAlias] = $element;

View File

@ -1,399 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* Base class for association mappings.
*
* <b>IMPORTANT NOTE:</b>
*
* The fields of this class are only public for 2 reasons:
* 1) To allow fast, internal READ access.
* 2) To drastically reduce the size of a serialized instance (private/protected members
* get the whole class name, namespace inclusive, prepended to every property in
* the serialized representation).
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
* @todo Potentially remove if assoc mapping objects get replaced by simple arrays.
*/
abstract class AssociationMapping
{
/**
* Specifies that an association is to be fetched when it is first accessed.
*
* @var integer
*/
const FETCH_LAZY = 2;
/**
* Specifies that an association is to be fetched when the owner of the
* association is fetched.
*
* @var integer
*/
const FETCH_EAGER = 3;
/**
* READ-ONLY: Whether the association cascades delete() operations from the source entity
* to the target entity/entities.
*
* @var boolean
*/
public $isCascadeRemove;
/**
* READ-ONLY: Whether the association cascades persist() operations from the source entity
* to the target entity/entities.
*
* @var boolean
*/
public $isCascadePersist;
/**
* READ-ONLY: Whether the association cascades refresh() operations from the source entity
* to the target entity/entities.
*
* @var boolean
*/
public $isCascadeRefresh;
/**
* READ-ONLY: Whether the association cascades merge() operations from the source entity
* to the target entity/entities.
*
* @var boolean
*/
public $isCascadeMerge;
/**
* READ-ONLY: Whether the association cascades detach() operations from the source entity
* to the target entity/entities.
*
* @var boolean
*/
public $isCascadeDetach;
/**
* READ-ONLY: The fetch mode used for the association.
*
* @var integer
*/
public $fetchMode;
/**
* READ-ONLY: Flag that indicates whether the class that defines this mapping is
* the owning side of the association.
*
* @var boolean
*/
public $isOwningSide = true;
/**
* READ-ONLY: The name of the source Entity (the Entity that defines this mapping).
*
* @var string
*/
public $sourceEntityName;
/**
* READ-ONLY: The name of the target Entity (the Enitity that is the target of the
* association).
*
* @var string
*/
public $targetEntityName;
/**
* READ-ONLY: Identifies the field on the source class (the class this AssociationMapping
* belongs to) that represents the association and stores the reference to the
* other entity/entities.
*
* @var string
*/
public $sourceFieldName;
/**
* READ-ONLY: Identifies the field on the owning side of a bidirectional association that
* controls the mapping for the association. This is only set on the inverse side
* of an association.
*
* @var string
*/
public $mappedBy;
/**
* READ-ONLY: Identifies the field on the inverse side of a bidirectional association.
* This is only set on the owning side of an association.
*
* @var string
*/
public $inversedBy;
/**
* READ-ONLY: The join table definition, if any.
*
* @var array
*/
public $joinTable;
/**
* READ-ONLY: The name of the entity class from which the association was
* inherited in an inheritance hierarchy.
*
* @var string
*/
public $inherited;
/**
* READ-ONLY: The name of the entity or mapped superclass that declares
* the association field in an inheritance hierarchy.
*
* @var string
*/
public $declared;
/**
* Initializes a new instance of a class derived from AssociationMapping.
*
* @param array $mapping The mapping definition.
*/
public function __construct(array $mapping)
{
$this->_validateAndCompleteMapping($mapping);
}
/**
* Validates & completes the mapping. Mapping defaults are applied here.
*
* @param array $mapping
* @throws MappingException If something is wrong with the mapping.
*/
protected function _validateAndCompleteMapping(array $mapping)
{
// Mandatory attributes for both sides
if ( ! isset($mapping['fieldName'])) {
throw MappingException::missingFieldName();
}
$this->sourceFieldName = $mapping['fieldName'];
if ( ! isset($mapping['sourceEntity'])) {
throw MappingException::missingSourceEntity($mapping['fieldName']);
}
$this->sourceEntityName = $mapping['sourceEntity'];
if ( ! isset($mapping['targetEntity'])) {
throw MappingException::missingTargetEntity($mapping['fieldName']);
}
$this->targetEntityName = $mapping['targetEntity'];
// Mandatory and optional attributes for either side
if ( ! isset($mapping['mappedBy'])) {
// Optional
if (isset($mapping['joinTable']) && $mapping['joinTable']) {
if ($mapping['joinTable']['name'][0] == '`') {
$mapping['joinTable']['name'] = trim($mapping['joinTable']['name'], '`');
$mapping['joinTable']['quoted'] = true;
}
$this->joinTable = $mapping['joinTable'];
}
if (isset($mapping['inversedBy'])) {
$this->inversedBy = $mapping['inversedBy'];
}
} else {
$this->isOwningSide = false;
$this->mappedBy = $mapping['mappedBy'];
}
// Optional attributes for both sides
$this->fetchMode = isset($mapping['fetch']) ? $mapping['fetch'] : self::FETCH_LAZY;
$cascades = isset($mapping['cascade']) ? $mapping['cascade'] : array();
if (in_array('all', $cascades)) {
$cascades = array(
'remove',
'persist',
'refresh',
'merge',
'detach'
);
}
$this->isCascadeRemove = in_array('remove', $cascades);
$this->isCascadePersist = in_array('persist', $cascades);
$this->isCascadeRefresh = in_array('refresh', $cascades);
$this->isCascadeMerge = in_array('merge', $cascades);
$this->isCascadeDetach = in_array('detach', $cascades);
}
/**
* Whether the target entity/entities of the association are eagerly fetched.
*
* @return boolean
*/
public function isEagerlyFetched()
{
return $this->fetchMode == self::FETCH_EAGER;
}
/**
* Whether the target entity/entities of the association are lazily fetched.
*
* @return boolean
*/
public function isLazilyFetched()
{
return $this->fetchMode == self::FETCH_LAZY;
}
/**
* Whether the association is a one-to-one association.
*
* @return boolean
*/
public function isOneToOne()
{
return false;
}
/**
* Whether the association is a one-to-many association.
*
* @return boolean
*/
public function isOneToMany()
{
return false;
}
/**
* Whether the association is a many-to-many association.
*
* @return boolean
*/
public function isManyToMany()
{
return false;
}
/**
* Whether the association uses a join table for the mapping.
*
* @return boolean
*/
public function usesJoinTable()
{
return (bool) $this->joinTable;
}
/**
* Checks whether the association has any cascades configured.
*
* @return boolean
*/
public function hasCascades()
{
return $this->isCascadePersist ||
$this->isCascadeRemove ||
$this->isCascadeRefresh ||
$this->isCascadeMerge ||
$this->isCascadeDetach;
}
/**
* Loads data in $target domain object using this association.
* The data comes from the association navigated from $sourceEntity
* using $em.
*
* @param object $sourceEntity
* @param object $target an entity or a collection
* @param EntityManager $em
* @param array $joinColumnValues foreign keys (significative for this
* association) of $sourceEntity, if needed
*/
abstract public function load($sourceEntity, $target, $em, array $joinColumnValues = array());
/**
* Gets the (possibly quoted) name of the join table.
*
* @param AbstractPlatform $platform
* @return string
*/
public function getQuotedJoinTableName($platform)
{
return isset($this->joinTable['quoted'])
? $platform->quoteIdentifier($this->joinTable['name'])
: $this->joinTable['name'];
}
/**
* Determines which fields get serialized.
*
* It is only serialized what is necessary for best unserialization performance.
* That means any metadata properties that are not set or empty or simply have
* their default value are NOT serialized.
*
* @return array The names of all the fields that should be serialized.
*/
public function __sleep()
{
$serialized = array(
'sourceEntityName',
'targetEntityName',
'sourceFieldName',
'fetchMode'
);
if ($this->isCascadeDetach) {
$serialized[] = 'isCascadeDetach';
}
if ($this->isCascadeMerge) {
$serialized[] = 'isCascadeMerge';
}
if ($this->isCascadePersist) {
$serialized[] = 'isCascadePersist';
}
if ($this->isCascadeRefresh) {
$serialized[] = 'isCascadeRefresh';
}
if ($this->isCascadeRemove) {
$serialized[] = 'isCascadeRemove';
}
if ( ! $this->isOwningSide) {
$serialized[] = 'isOwningSide';
}
if ($this->mappedBy) {
$serialized[] = 'mappedBy';
}
if ($this->inversedBy) {
$serialized[] = 'inversedBy';
}
if ($this->joinTable) {
$serialized[] = 'joinTable';
}
if ($this->inherited) {
$serialized[] = 'inherited';
}
if ($this->declared) {
$serialized[] = 'declared';
}
return $serialized;
}
}

View File

@ -193,12 +193,12 @@ class ClassMetadata extends ClassMetadataInfo
*
* @param AssociationMapping $assocMapping
*/
protected function _storeAssociationMapping(AssociationMapping $assocMapping)
protected function _storeAssociationMapping(array $assocMapping)
{
parent::_storeAssociationMapping($assocMapping);
// Store ReflectionProperty of mapped field
$sourceFieldName = $assocMapping->sourceFieldName;
$sourceFieldName = $assocMapping['fieldName'];
$refProp = $this->reflClass->getProperty($sourceFieldName);
$refProp->setAccessible(true);
@ -234,6 +234,19 @@ class ClassMetadata extends ClassMetadataInfo
$this->table['name'];
}
/**
* Gets the (possibly quoted) name of the join table.
*
* @param AbstractPlatform $platform
* @return string
*/
public function getQuotedJoinTableName(array $assoc, $platform)
{
return isset($assoc['joinTable']['quoted'])
? $platform->quoteIdentifier($assoc['joinTable']['name'])
: $assoc['joinTable']['name'];
}
/**
* Creates a string representation of this instance.
*
@ -337,8 +350,8 @@ class ClassMetadata extends ClassMetadataInfo
}
foreach ($this->associationMappings as $field => $mapping) {
if ($mapping->declared) {
$reflField = new ReflectionProperty($mapping->declared, $field);
if (isset($mapping['declared'])) {
$reflField = new ReflectionProperty($mapping['declared'], $field);
} else {
$reflField = $this->reflClass->getProperty($field);
}

View File

@ -255,7 +255,7 @@ class ClassMetadataFactory
// Invoke driver
try {
$this->_driver->loadMetadataForClass($className, $class);
} catch(ReflectionException $e) {
} catch (ReflectionException $e) {
throw MappingException::reflectionFailure($className, $e);
}
@ -346,14 +346,14 @@ class ClassMetadataFactory
private function _addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass)
{
foreach ($parentClass->associationMappings as $field => $mapping) {
$subclassMapping = clone $mapping;
if ( ! isset($mapping->inherited) && ! $parentClass->isMappedSuperclass) {
$subclassMapping->inherited = $parentClass->name;
//$subclassMapping = $mapping;
if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
$mapping['inherited'] = $parentClass->name;
}
if ( ! isset($mapping->declared)) {
$subclassMapping->declared = $parentClass->name;
if ( ! isset($mapping['declared'])) {
$mapping['declared'] = $parentClass->name;
}
$subClass->addInheritedAssociationMapping($subclassMapping);
$subClass->addInheritedAssociationMapping($mapping);
}
}

View File

@ -112,6 +112,25 @@ class ClassMetadataInfo
* the <tt>NotifyPropertyChanged</tt> interface.
*/
const CHANGETRACKING_NOTIFY = 3;
/**
* Specifies that an association is to be fetched when it is first accessed.
*
* @var integer
*/
const FETCH_LAZY = 2;
/**
* Specifies that an association is to be fetched when the owner of the
* association is fetched.
*
* @var integer
*/
const FETCH_EAGER = 3;
const ONE_TO_ONE = 1;
const MANY_TO_ONE = 2;
const TO_ONE = 3;
const ONE_TO_MANY = 4;
const MANY_TO_MANY = 8;
const TO_MANY = 12;
/**
* READ-ONLY: The name of the entity class.
@ -600,6 +619,215 @@ class ClassMetadataInfo
}
}
/**
* Validates & completes the mapping. Mapping defaults are applied here.
*
* @param array $mapping
* @throws MappingException If something is wrong with the mapping.
*/
protected function _validateAndCompleteAssociationMapping(array $mapping)
{
if ( ! isset($mapping['mappedBy'])) {
$mapping['mappedBy'] = null;
}
if ( ! isset($mapping['inversedBy'])) {
$mapping['inversedBy'] = null;
}
$mapping['isOwningSide'] = true;
$mapping['sourceEntity'] = $this->name;
if (isset($mapping['targetEntity']) && strpos($mapping['targetEntity'], '\\') === false && strlen($this->namespace) > 0) {
$mapping['targetEntity'] = $this->namespace . '\\' . $mapping['targetEntity'];
}
// Mandatory attributes for both sides
if ( ! isset($mapping['fieldName'])) {
throw MappingException::missingFieldName();
}
if ( ! isset($mapping['sourceEntity'])) {
throw MappingException::missingSourceEntity($mapping['fieldName']);
}
if ( ! isset($mapping['targetEntity'])) {
throw MappingException::missingTargetEntity($mapping['fieldName']);
}
// Mandatory and optional attributes for either side
if ( ! isset($mapping['mappedBy'])) {
// Optional
if (isset($mapping['joinTable']) && $mapping['joinTable']) {
if ($mapping['joinTable']['name'][0] == '`') {
$mapping['joinTable']['name'] = trim($mapping['joinTable']['name'], '`');
$mapping['joinTable']['quoted'] = true;
}
}
} else {
$mapping['isOwningSide'] = false;
}
// Optional attributes for both sides
if ( ! isset($mapping['fetch'])) {
$mapping['fetch'] = self::FETCH_LAZY;
}
$cascades = isset($mapping['cascade']) ? $mapping['cascade'] : array();
if (in_array('all', $cascades)) {
$cascades = array(
'remove',
'persist',
'refresh',
'merge',
'detach'
);
}
$mapping['cascade'] = $cascades;
$mapping['isCascadeRemove'] = in_array('remove', $cascades);
$mapping['isCascadePersist'] = in_array('persist', $cascades);
$mapping['isCascadeRefresh'] = in_array('refresh', $cascades);
$mapping['isCascadeMerge'] = in_array('merge', $cascades);
$mapping['isCascadeDetach'] = in_array('detach', $cascades);
return $mapping;
}
/**
* {@inheritdoc}
*
* @param array $mapping The mapping to validate & complete.
* @return array The validated & completed mapping.
* @override
*/
protected function _validateAndCompleteOneToOneMapping(array $mapping)
{
$mapping = $this->_validateAndCompleteAssociationMapping($mapping);
if (isset($mapping['joinColumns']) && $mapping['joinColumns']) {
$mapping['isOwningSide'] = true;
}
if ($mapping['isOwningSide']) {
if ( ! isset($mapping['joinColumns']) || ! $mapping['joinColumns']) {
// Apply default join column
$mapping['joinColumns'] = array(array(
'name' => $mapping['fieldName'] . '_id',
'referencedColumnName' => 'id'
));
}
foreach ($mapping['joinColumns'] as $joinColumn) {
$mapping['sourceToTargetKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName'];
$mapping['joinColumnFieldNames'][$joinColumn['name']] = isset($joinColumn['fieldName'])
? $joinColumn['fieldName'] : $joinColumn['name'];
}
$mapping['targetToSourceKeyColumns'] = array_flip($mapping['sourceToTargetKeyColumns']);
}
//TODO: if orphanRemoval, cascade=remove is implicit!
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ?
(bool) $mapping['orphanRemoval'] : false;
return $mapping;
}
/**
* Validates and completes the mapping.
*
* @param array $mapping The mapping to validate and complete.
* @return array The validated and completed mapping.
* @override
*/
protected function _validateAndCompleteOneToManyMapping(array $mapping)
{
$mapping = $this->_validateAndCompleteAssociationMapping($mapping);
// OneToMany-side MUST be inverse (must have mappedBy)
if ( ! isset($mapping['mappedBy'])) {
throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']);
}
//TODO: if orphanRemoval, cascade=remove is implicit!
$mapping['orphanRemoval'] = isset($mapping['orphanRemoval']) ?
(bool) $mapping['orphanRemoval'] : false;
if (isset($mapping['orderBy'])) {
if ( ! is_array($mapping['orderBy'])) {
throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
}
}
return $mapping;
}
protected function _validateAndCompleteManyToManyMapping(array $mapping)
{
$mapping = $this->_validateAndCompleteAssociationMapping($mapping);
if ($mapping['isOwningSide']) {
// owning side MUST have a join table
if ( ! isset($mapping['joinTable']) || ! $mapping['joinTable']) {
// Apply default join table
$sourceShortName = substr($mapping['sourceEntity'], strrpos($mapping['sourceEntity'], '\\') + 1);
$targetShortName = substr($mapping['targetEntity'], strrpos($mapping['targetEntity'], '\\') + 1);
$mapping['joinTable'] = array(
'name' => $sourceShortName .'_' . $targetShortName,
'joinColumns' => array(
array(
'name' => $sourceShortName . '_id',
'referencedColumnName' => 'id',
'onDelete' => 'CASCADE'
)
),
'inverseJoinColumns' => array(
array(
'name' => $targetShortName . '_id',
'referencedColumnName' => 'id',
'onDelete' => 'CASCADE'
)
)
);
}
// owning side MUST specify joinColumns
else if ( ! isset($mapping['joinTable']['joinColumns'])) {
throw MappingException::missingRequiredOption(
$mapping['fieldName'], 'joinColumns',
'Did you think of case sensitivity / plural s?'
);
}
// owning side MUST specify inverseJoinColumns
else if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) {
throw MappingException::missingRequiredOption(
$mapping['fieldName'], 'inverseJoinColumns',
'Did you think of case sensitivity / plural s?'
);
}
foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) {
if (isset($joinColumn['onDelete']) && strtolower($joinColumn['onDelete']) == 'cascade') {
$mapping['isOnDeleteCascade'] = true;
}
$mapping['relationToSourceKeyColumns'][$joinColumn['name']] = $joinColumn['referencedColumnName'];
$mapping['joinTableColumns'][] = $joinColumn['name'];
}
foreach ($mapping['joinTable']['inverseJoinColumns'] as $inverseJoinColumn) {
if (isset($inverseJoinColumn['onDelete']) && strtolower($inverseJoinColumn['onDelete']) == 'cascade') {
$mapping['isOnDeleteCascade'] = true;
}
$mapping['relationToTargetKeyColumns'][$inverseJoinColumn['name']] = $inverseJoinColumn['referencedColumnName'];
$mapping['joinTableColumns'][] = $inverseJoinColumn['name'];
}
}
if (isset($mapping['orderBy'])) {
if ( ! is_array($mapping['orderBy'])) {
throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
}
}
return $mapping;
}
/**
* Gets the identifier (primary key) field names of the class.
*
@ -897,7 +1125,7 @@ class ClassMetadataInfo
*/
public function isInheritedAssociation($fieldName)
{
return isset($this->associationMappings[$fieldName]->inherited);
return isset($this->associationMappings[$fieldName]['inherited']);
}
/**
@ -944,22 +1172,6 @@ class ClassMetadataInfo
$type == self::INHERITANCE_TYPE_TABLE_PER_CLASS;
}
/**
* Makes some automatic additions to the association mapping to make the life
* easier for the user, and store join columns in the metadata.
*
* @param array $mapping
* @todo Pass param by ref?
*/
private function _completeAssociationMapping(array $mapping)
{
$mapping['sourceEntity'] = $this->name;
if (isset($mapping['targetEntity']) && strpos($mapping['targetEntity'], '\\') === false && strlen($this->namespace) > 0) {
$mapping['targetEntity'] = $this->namespace . '\\' . $mapping['targetEntity'];
}
return $mapping;
}
/**
* Adds a mapped field to the class.
*
@ -982,12 +1194,12 @@ class ClassMetadataInfo
* @param AssociationMapping $mapping
* @param string $owningClassName The name of the class that defined this mapping.
*/
public function addInheritedAssociationMapping(AssociationMapping $mapping/*, $owningClassName = null*/)
public function addInheritedAssociationMapping(array $mapping/*, $owningClassName = null*/)
{
if (isset($this->associationMappings[$mapping->sourceFieldName])) {
throw MappingException::duplicateAssociationMapping($this->name, $mapping->sourceFieldName);
if (isset($this->associationMappings[$mapping['fieldName']])) {
throw MappingException::duplicateAssociationMapping($this->name, $mapping['fieldName']);
}
$this->associationMappings[$mapping->sourceFieldName] = $mapping;
$this->associationMappings[$mapping['fieldName']] = $mapping;
}
/**
@ -1012,9 +1224,9 @@ class ClassMetadataInfo
*/
public function mapOneToOne(array $mapping)
{
$mapping = $this->_completeAssociationMapping($mapping);
$oneToOneMapping = new OneToOneMapping($mapping);
$this->_storeAssociationMapping($oneToOneMapping);
$mapping['type'] = self::ONE_TO_ONE;
$mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
$this->_storeAssociationMapping($mapping);
}
/**
@ -1024,9 +1236,9 @@ class ClassMetadataInfo
*/
public function mapOneToMany(array $mapping)
{
$mapping = $this->_completeAssociationMapping($mapping);
$oneToManyMapping = new OneToManyMapping($mapping);
$this->_storeAssociationMapping($oneToManyMapping);
$mapping['type'] = self::ONE_TO_MANY;
$mapping = $this->_validateAndCompleteOneToManyMapping($mapping);
$this->_storeAssociationMapping($mapping);
}
/**
@ -1036,8 +1248,10 @@ class ClassMetadataInfo
*/
public function mapManyToOne(array $mapping)
{
// A many-to-one mapping is simply a one-one backreference
$this->mapOneToOne($mapping);
$mapping['type'] = self::MANY_TO_ONE;
// A many-to-one mapping is essentially a one-one backreference
$mapping = $this->_validateAndCompleteOneToOneMapping($mapping);
$this->_storeAssociationMapping($mapping);
}
/**
@ -1047,9 +1261,9 @@ class ClassMetadataInfo
*/
public function mapManyToMany(array $mapping)
{
$mapping = $this->_completeAssociationMapping($mapping);
$manyToManyMapping = new ManyToManyMapping($mapping);
$this->_storeAssociationMapping($manyToManyMapping);
$mapping['type'] = self::MANY_TO_MANY;
$mapping = $this->_validateAndCompleteManyToManyMapping($mapping);
$this->_storeAssociationMapping($mapping);
}
/**
@ -1057,9 +1271,9 @@ class ClassMetadataInfo
*
* @param AssociationMapping $assocMapping
*/
protected function _storeAssociationMapping(AssociationMapping $assocMapping)
protected function _storeAssociationMapping(array $assocMapping)
{
$sourceFieldName = $assocMapping->sourceFieldName;
$sourceFieldName = $assocMapping['fieldName'];
if (isset($this->fieldMappings[$sourceFieldName]) || isset($this->associationMappings[$sourceFieldName])) {
throw MappingException::duplicateFieldMapping($this->name, $sourceFieldName);
}
@ -1207,7 +1421,7 @@ class ClassMetadataInfo
public function isSingleValuedAssociation($fieldName)
{
return isset($this->associationMappings[$fieldName]) &&
$this->associationMappings[$fieldName]->isOneToOne();
($this->associationMappings[$fieldName]['type'] & self::TO_ONE);
}
/**
@ -1220,7 +1434,7 @@ class ClassMetadataInfo
public function isCollectionValuedAssociation($fieldName)
{
return isset($this->associationMappings[$fieldName]) &&
! $this->associationMappings[$fieldName]->isOneToOne();
! ($this->associationMappings[$fieldName]['type'] & self::TO_ONE);
}
/**

View File

@ -296,14 +296,14 @@ class AnnotationDriver implements Driver
$mapping['inversedBy'] = $oneToOneAnnot->inversedBy;
$mapping['cascade'] = $oneToOneAnnot->cascade;
$mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . $oneToOneAnnot->fetch);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToOneAnnot->fetch);
$metadata->mapOneToOne($mapping);
} else if ($oneToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToMany')) {
$mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
$mapping['targetEntity'] = $oneToManyAnnot->targetEntity;
$mapping['cascade'] = $oneToManyAnnot->cascade;
$mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . $oneToManyAnnot->fetch);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyAnnot->fetch);
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;
@ -315,7 +315,7 @@ class AnnotationDriver implements Driver
$mapping['cascade'] = $manyToOneAnnot->cascade;
$mapping['inversedBy'] = $manyToOneAnnot->inversedBy;
$mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . $manyToOneAnnot->fetch);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToOneAnnot->fetch);
$metadata->mapManyToOne($mapping);
} else if ($manyToManyAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) {
$joinTable = array();
@ -356,7 +356,7 @@ class AnnotationDriver implements Driver
$mapping['mappedBy'] = $manyToManyAnnot->mappedBy;
$mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
$mapping['cascade'] = $manyToManyAnnot->cascade;
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . $manyToManyAnnot->fetch);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyAnnot->fetch);
if ($orderByAnnot = $this->_reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
$mapping['orderBy'] = $orderByAnnot->value;

View File

@ -238,7 +238,7 @@ class XmlDriver extends AbstractFileDriver
);
if (isset($oneToOneElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . (string)$oneToOneElement['fetch']);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$oneToOneElement['fetch']);
}
if (isset($oneToOneElement['mapped-by'])) {
@ -282,7 +282,7 @@ class XmlDriver extends AbstractFileDriver
);
if (isset($oneToManyElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . (string)$oneToManyElement['fetch']);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$oneToManyElement['fetch']);
}
if (isset($oneToManyElement->cascade)) {
@ -314,7 +314,7 @@ class XmlDriver extends AbstractFileDriver
);
if (isset($manyToOneElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . (string)$manyToOneElement['fetch']);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$manyToOneElement['fetch']);
}
if (isset($manyToOneElement['inversed-by'])) {
@ -357,7 +357,7 @@ class XmlDriver extends AbstractFileDriver
);
if (isset($manyToManyElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . (string)$manyToManyElement['fetch']);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string)$manyToManyElement['fetch']);
}
if (isset($manyToManyElement['mapped-by'])) {

View File

@ -237,7 +237,7 @@ class YamlDriver extends AbstractFileDriver
);
if (isset($oneToOneElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . $oneToOneElement['fetch']);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToOneElement['fetch']);
}
if (isset($oneToOneElement['mappedBy'])) {
@ -282,7 +282,7 @@ class YamlDriver extends AbstractFileDriver
);
if (isset($oneToManyElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . $oneToManyElement['fetch']);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyElement['fetch']);
}
if (isset($oneToManyElement['cascade'])) {
@ -306,7 +306,7 @@ class YamlDriver extends AbstractFileDriver
);
if (isset($manyToOneElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . $manyToOneElement['fetch']);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToOneElement['fetch']);
}
if (isset($manyToOneElement['inversedBy'])) {
@ -346,7 +346,7 @@ class YamlDriver extends AbstractFileDriver
);
if (isset($manyToManyElement['fetch'])) {
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\AssociationMapping::FETCH_' . $manyToManyElement['fetch']);
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyElement['fetch']);
}
if (isset($manyToManyElement['mappedBy'])) {

View File

@ -1,195 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* A many-to-many mapping describes the mapping between two collections of
* entities.
*
* <b>IMPORTANT NOTE:</b>
*
* The fields of this class are only public for 2 reasons:
* 1) To allow fast READ access.
* 2) To drastically reduce the size of a serialized instance (private/protected members
* get the whole class name, namespace inclusive, prepended to every property in
* the serialized representation).
*
* Instances of this class are stored serialized in the metadata cache together with the
* owning <tt>ClassMetadata</tt> instance.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
* @todo Potentially remove if assoc mapping objects get replaced by simple arrays.
*/
class ManyToManyMapping extends AssociationMapping
{
/**
* READ-ONLY: Maps the columns in the relational table to the columns in the source table.
*/
public $relationToSourceKeyColumns = array();
/**
* READ-ONLY: Maps the columns in the relation table to the columns in the target table.
*/
public $relationToTargetKeyColumns = array();
/**
* READ-ONLY: List of aggregated column names on the join table.
*/
public $joinTableColumns = array();
/** FUTURE: The key column mapping, if any. The key column holds the keys of the Collection. */
//public $keyColumn;
/**
* READ-ONLY: Order this collection by the given DQL snippet.
*
* Only simple unqualified field names and ASC|DESC are allowed
*
* @var array
*/
public $orderBy;
/**
* READ-ONLY: Are entries on the owning AND inverse side of this join-table deleted through a database onDelete="CASCADE" operation?
*
* @var bool
*/
public $isOnDeleteCascade = false;
/**
* {@inheritdoc}
*/
protected function _validateAndCompleteMapping(array $mapping)
{
parent::_validateAndCompleteMapping($mapping);
if ($this->isOwningSide) {
// owning side MUST have a join table
if ( ! isset($mapping['joinTable']) || ! $mapping['joinTable']) {
// Apply default join table
$sourceShortName = substr($this->sourceEntityName, strrpos($this->sourceEntityName, '\\') + 1);
$targetShortName = substr($this->targetEntityName, strrpos($this->targetEntityName, '\\') + 1);
$mapping['joinTable'] = array(
'name' => $sourceShortName .'_' . $targetShortName,
'joinColumns' => array(
array(
'name' => $sourceShortName . '_id',
'referencedColumnName' => 'id',
'onDelete' => 'CASCADE'
)
),
'inverseJoinColumns' => array(
array(
'name' => $targetShortName . '_id',
'referencedColumnName' => 'id',
'onDelete' => 'CASCADE'
)
)
);
$this->joinTable = $mapping['joinTable'];
}
// owning side MUST specify joinColumns
else if ( ! isset($mapping['joinTable']['joinColumns'])) {
throw MappingException::missingRequiredOption(
$this->sourceFieldName, 'joinColumns',
'Did you think of case sensitivity / plural s?'
);
}
// owning side MUST specify inverseJoinColumns
else if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) {
throw MappingException::missingRequiredOption(
$this->sourceFieldName, 'inverseJoinColumns',
'Did you think of case sensitivity / plural s?'
);
}
foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) {
if (isset($joinColumn['onDelete']) && strtolower($joinColumn['onDelete']) == 'cascade') {
$this->isOnDeleteCascade = true;
}
$this->relationToSourceKeyColumns[$joinColumn['name']] = $joinColumn['referencedColumnName'];
$this->joinTableColumns[] = $joinColumn['name'];
}
foreach ($mapping['joinTable']['inverseJoinColumns'] as $inverseJoinColumn) {
if (isset($inverseJoinColumn['onDelete']) && strtolower($inverseJoinColumn['onDelete']) == 'cascade') {
$this->isOnDeleteCascade = true;
}
$this->relationToTargetKeyColumns[$inverseJoinColumn['name']] = $inverseJoinColumn['referencedColumnName'];
$this->joinTableColumns[] = $inverseJoinColumn['name'];
}
}
if (isset($mapping['orderBy'])) {
if ( ! is_array($mapping['orderBy'])) {
throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
}
$this->orderBy = $mapping['orderBy'];
}
}
/**
* Loads entities in $targetCollection using $em.
* The data of $sourceEntity are used to restrict the collection
* via the join table.
*
* @param object The owner of the collection.
* @param object The collection to populate.
* @param array
* @todo Remove
*/
public function load($sourceEntity, $targetCollection, $em, array $joinColumnValues = array())
{
$em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->loadManyToManyCollection($this, $sourceEntity, $targetCollection);
}
/** {@inheritdoc} */
public function isManyToMany()
{
return true;
}
/**
* Determines which fields get serialized.
*
* It is only serialized what is necessary for best unserialization performance.
* That means any metadata properties that are not set or empty or simply have
* their default value are NOT serialized.
*
* @return array The names of all the fields that should be serialized.
*/
public function __sleep()
{
$serialized = parent::__sleep();
$serialized[] = 'joinTableColumns';
$serialized[] = 'relationToSourceKeyColumns';
$serialized[] = 'relationToTargetKeyColumns';
if ($this->isOnDeleteCascade) {
$serialized[] = 'isOnDeleteCascade';
}
if ($this->orderBy) {
$serialized[] = 'orderBy';
}
return $serialized;
}
}

View File

@ -1,144 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* Represents a one-to-many mapping.
*
* NOTE: One-to-many mappings can currently not be uni-directional (one -> many).
* They must either be bidirectional (one <-> many) or unidirectional (many -> one).
* In other words, the many-side MUST be the owning side and the one-side MUST be
* the inverse side.
*
* <b>IMPORTANT NOTE:</b>
*
* The fields of this class are only public for 2 reasons:
* 1) To allow fast READ access.
* 2) To drastically reduce the size of a serialized instance (private/protected members
* get the whole class name, namespace inclusive, prepended to every property in
* the serialized representation).
*
* Instances of this class are stored serialized in the metadata cache together with the
* owning <tt>ClassMetadata</tt> instance.
*
* @author Roman Borschel <roman@code-factory.org>
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
* @since 2.0
* @todo Potentially remove if assoc mapping objects get replaced by simple arrays.
*/
class OneToManyMapping extends AssociationMapping
{
/**
* READ-ONLY: Whether to delete orphaned elements (removed from the collection)
*
* @var boolean
*/
public $orphanRemoval = false;
/** FUTURE: The key column mapping, if any. The key column holds the keys of the Collection. */
//public $keyColumn;
/**
* READ-ONLY: Order this collection by the given SQL snippet.
*/
public $orderBy;
/**
* Validates and completes the mapping.
*
* @param array $mapping The mapping to validate and complete.
* @return array The validated and completed mapping.
* @override
*/
protected function _validateAndCompleteMapping(array $mapping)
{
parent::_validateAndCompleteMapping($mapping);
// OneToMany-side MUST be inverse (must have mappedBy)
if ( ! isset($mapping['mappedBy'])) {
throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']);
}
//TODO: if orphanRemoval, cascade=remove is implicit!
$this->orphanRemoval = isset($mapping['orphanRemoval']) ?
(bool) $mapping['orphanRemoval'] : false;
if (isset($mapping['orderBy'])) {
if (!is_array($mapping['orderBy'])) {
throw new \InvalidArgumentException("'orderBy' is expected to be an array, not ".gettype($mapping['orderBy']));
}
$this->orderBy = $mapping['orderBy'];
}
}
/**
* Whether orphaned elements (removed from the collection) should be deleted.
*
* @return boolean TRUE if orphaned elements should be deleted, FALSE otherwise.
*/
public function shouldDeleteOrphans()
{
return $this->deleteOrphans;
}
/**
* {@inheritdoc}
*/
public function isOneToMany()
{
return true;
}
/**
* Loads a one-to-many collection.
*
* @param $sourceEntity The entity that owns the collection.
* @param $targetCollection The collection to load/fill.
* @param $em The EntityManager to use.
* @param $joinColumnValues
* @return void
* @todo Remove
*/
public function load($sourceEntity, $targetCollection, $em, array $joinColumnValues = array())
{
$em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->loadOneToManyCollection($this, $sourceEntity, $targetCollection);
}
/**
* Determines which fields get serialized.
*
* It is only serialized what is necessary for best unserialization performance.
* That means any metadata properties that are not set or empty or simply have
* their default value are NOT serialized.
*
* @return array The names of all the fields that should be serialized.
*/
public function __sleep()
{
$serialized = parent::__sleep();
if ($this->orderBy) {
$serialized[] = 'orderBy';
}
if ($this->orphanRemoval) {
$serialized[] = 'orphanRemoval';
}
return $serialized;
}
}

View File

@ -1,165 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
/**
* A one-to-one mapping describes a uni-directional mapping from one entity
* to another entity.
*
* <b>IMPORTANT NOTE:</b>
*
* The fields of this class are only public for 2 reasons:
* 1) To allow fast READ access.
* 2) To drastically reduce the size of a serialized instance (private/protected members
* get the whole class name, namespace inclusive, prepended to every property in
* the serialized representation).
*
* Instances of this class are stored serialized in the metadata cache together with the
* owning <tt>ClassMetadata</tt> instance.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
* @todo Potentially remove if assoc mapping objects get replaced by simple arrays.
*/
class OneToOneMapping extends AssociationMapping
{
/**
* READ-ONLY: Maps the source foreign/primary key columns to the target primary/foreign key columns.
* i.e. source.id (pk) => target.user_id (fk).
* Reverse mapping of _targetToSourceKeyColumns.
*/
public $sourceToTargetKeyColumns = array();
/**
* READ-ONLY: Maps the target primary/foreign key columns to the source foreign/primary key columns.
* i.e. target.user_id (fk) => source.id (pk).
* Reverse mapping of _sourceToTargetKeyColumns.
*/
public $targetToSourceKeyColumns = array();
/**
* READ-ONLY: Whether to delete orphaned elements (when nulled out, i.e. $foo->other = null)
*
* @var boolean
*/
public $orphanRemoval = false;
/**
* READ-ONLY: The join column definitions. Only present on the owning side.
*
* @var array
*/
public $joinColumns = array();
/**
* READ-ONLY: A map of join column names to field names that are used in cases
* when the join columns are fetched as part of the query result.
*
* @var array
*/
public $joinColumnFieldNames = array();
/**
* {@inheritdoc}
*
* @param array $mapping The mapping to validate & complete.
* @return array The validated & completed mapping.
* @override
*/
protected function _validateAndCompleteMapping(array $mapping)
{
parent::_validateAndCompleteMapping($mapping);
if (isset($mapping['joinColumns']) && $mapping['joinColumns']) {
$this->isOwningSide = true;
}
if ($this->isOwningSide) {
if ( ! isset($mapping['joinColumns']) || ! $mapping['joinColumns']) {
// Apply default join column
$mapping['joinColumns'] = array(array(
'name' => $this->sourceFieldName . '_id',
'referencedColumnName' => 'id'
));
}
foreach ($mapping['joinColumns'] as $joinColumn) {
$this->sourceToTargetKeyColumns[$joinColumn['name']] = $joinColumn['referencedColumnName'];
$this->joinColumnFieldNames[$joinColumn['name']] = isset($joinColumn['fieldName'])
? $joinColumn['fieldName'] : $joinColumn['name'];
}
$this->joinColumns = $mapping['joinColumns'];
$this->targetToSourceKeyColumns = array_flip($this->sourceToTargetKeyColumns);
}
//TODO: if orphanRemoval, cascade=remove is implicit!
$this->orphanRemoval = isset($mapping['orphanRemoval']) ?
(bool) $mapping['orphanRemoval'] : false;
return $mapping;
}
/**
* {@inheritdoc}
*
* @return boolean
* @override
*/
public function isOneToOne()
{
return true;
}
/**
* {@inheritdoc}
*
* @param object $sourceEntity the entity source of this association
* @param object $targetEntity the entity to load data in
* @param EntityManager $em
* @param array $joinColumnValues Values of the join columns of $sourceEntity.
* @todo Remove
*/
public function load($sourceEntity, $targetEntity, $em, array $joinColumnValues = array())
{
return $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->loadOneToOneEntity($this, $sourceEntity, $targetEntity, $joinColumnValues);
}
/**
* Determines which fields get serialized.
*
* It is only serialized what is necessary for best unserialization performance.
* That means any metadata properties that are not set or empty or simply have
* their default value are NOT serialized.
*
* @return array The names of all the fields that should be serialized.
*/
public function __sleep()
{
$serialized = parent::__sleep();
$serialized[] = 'joinColumns';
$serialized[] = 'joinColumnFieldNames';
$serialized[] = 'sourceToTargetKeyColumns';
$serialized[] = 'targetToSourceKeyColumns';
if ($this->orphanRemoval) {
$serialized[] = 'orphanRemoval';
}
return $serialized;
}
}

View File

@ -19,7 +19,7 @@
namespace Doctrine\ORM;
use Doctrine\ORM\Mapping\AssociationMapping,
use Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\Common\Collections\Collection,
Closure;
@ -127,11 +127,11 @@ final class PersistentCollection implements Collection
* @param object $entity
* @param AssociationMapping $assoc
*/
public function setOwner($entity, AssociationMapping $assoc)
public function setOwner($entity, array $assoc)
{
$this->owner = $entity;
$this->association = $assoc;
$this->backRefFieldName = $assoc->inversedBy ?: $assoc->mappedBy;
$this->backRefFieldName = $assoc['inversedBy'] ?: $assoc['mappedBy'];
}
/**
@ -162,7 +162,7 @@ final class PersistentCollection implements Collection
$this->coll->add($element);
// If _backRefFieldName is set and its a one-to-many association,
// we need to set the back reference.
if ($this->backRefFieldName && $this->association->isOneToMany()) {
if ($this->backRefFieldName && $this->association['type'] == ClassMetadata::ONE_TO_MANY) {
// Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]
->setValue($element, $this->owner);
@ -185,7 +185,7 @@ final class PersistentCollection implements Collection
$this->coll->set($key, $element);
// If _backRefFieldName is set, then the association is bidirectional
// and we need to set the back reference.
if ($this->backRefFieldName && $this->association->isOneToMany()) {
if ($this->backRefFieldName && $this->association['type'] == ClassMetadata::ONE_TO_MANY) {
// Set back reference to owner
$this->typeClass->reflFields[$this->backRefFieldName]
->setValue($element, $this->owner);
@ -204,7 +204,7 @@ final class PersistentCollection implements Collection
$newObjects = $this->coll->toArray();
}
$this->coll->clear();
$this->association->load($this->owner, $this, $this->em);
$this->em->getUnitOfWork()->loadCollection($this);
$this->takeSnapshot();
// Reattach NEW objects added through add(), if any.
if (isset($newObjects)) {
@ -279,7 +279,7 @@ final class PersistentCollection implements Collection
{
if ( ! $this->isDirty) {
$this->isDirty = true;
if ($this->association !== null && $this->association->isOwningSide && $this->association->isManyToMany() &&
if ($this->association !== null && $this->association['isOwningSide'] && $this->association['type'] == ClassMetadata::MANY_TO_MANY &&
$this->em->getClassMetadata(get_class($this->owner))->isChangeTrackingNotify()) {
$this->em->getUnitOfWork()->scheduleForDirtyCheck($this->owner);
}
@ -354,8 +354,8 @@ final class PersistentCollection implements Collection
$removed = $this->coll->remove($key);
if ($removed) {
$this->changed();
if ($this->association !== null && $this->association->isOneToMany() &&
$this->association->orphanRemoval) {
if ($this->association !== null && $this->association['type'] == ClassMetadata::ONE_TO_MANY &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
}
}
@ -382,8 +382,8 @@ final class PersistentCollection implements Collection
$removed = $this->coll->removeElement($element);
if ($removed) {
$this->changed();
if ($this->association !== null && $this->association->isOneToMany() &&
$this->association->orphanRemoval) {
if ($this->association !== null && $this->association['type'] == ClassMetadata::ONE_TO_MANY &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
}
}
@ -570,13 +570,13 @@ final class PersistentCollection implements Collection
if ($this->initialized && $this->isEmpty()) {
return;
}
if ($this->association->isOneToMany() && $this->association->orphanRemoval) {
if ($this->association['type'] == ClassMetadata::ONE_TO_MANY && $this->association['orphanRemoval']) {
foreach ($this->coll as $element) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($element);
}
}
$this->coll->clear();
if ($this->association->isOwningSide) {
if ($this->association['isOwningSide']) {
$this->changed();
$this->em->getUnitOfWork()->scheduleCollectionDeletion($this);
$this->takeSnapshot();

View File

@ -64,7 +64,8 @@ abstract class AbstractCollectionPersister
*/
public function delete(PersistentCollection $coll)
{
if ( ! $coll->getMapping()->isOwningSide) {
$mapping = $coll->getMapping();
if ( ! $mapping['isOwningSide']) {
return; // ignore inverse side
}
$sql = $this->_getDeleteSQL($coll);
@ -94,7 +95,8 @@ abstract class AbstractCollectionPersister
*/
public function update(PersistentCollection $coll)
{
if ( ! $coll->getMapping()->isOwningSide) {
$mapping = $coll->getMapping();
if ( ! $mapping['isOwningSide']) {
return; // ignore inverse side
}
$this->deleteRows($coll);

View File

@ -28,10 +28,7 @@ use PDO,
Doctrine\ORM\Query,
Doctrine\ORM\PersistentCollection,
Doctrine\ORM\Mapping\MappingException,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Mapping\OneToOneMapping,
Doctrine\ORM\Mapping\OneToManyMapping,
Doctrine\ORM\Mapping\ManyToManyMapping;
Doctrine\ORM\Mapping\ClassMetadata;
/**
* A BasicEntityPersiter maps an entity to a single table in a relational database.
@ -342,32 +339,31 @@ class BasicEntityPersister
*/
protected function deleteJoinTableRecords($identifier)
{
foreach ($this->_class->associationMappings AS $mapping) {
/* @var $mapping \Doctrine\ORM\Mapping\AssociationMapping */
if ($mapping->isManyToMany()) {
foreach ($this->_class->associationMappings as $mapping) {
if ($mapping['type'] == ClassMetadata::MANY_TO_MANY) {
// @Todo this only covers scenarios with no inheritance or of the same level. Is there something
// like self-referential relationship between different levels of an inheritance hierachy? I hope not!
$selfReferential = ($mapping->targetEntityName == $mapping->sourceEntityName);
$selfReferential = ($mapping['targetEntity'] == $mapping['sourceEntity']);
if (!$mapping->isOwningSide) {
$relatedClass = $this->_em->getClassMetadata($mapping->targetEntityName);
$mapping = $relatedClass->associationMappings[$mapping->mappedBy];
$keys = array_keys($mapping->relationToTargetKeyColumns);
if ( ! $mapping['isOwningSide']) {
$relatedClass = $this->_em->getClassMetadata($mapping['targetEntity']);
$mapping = $relatedClass->associationMappings[$mapping['mappedBy']];
$keys = array_keys($mapping['relationToTargetKeyColumns']);
if ($selfReferential) {
$otherKeys = array_keys($mapping->relationToSourceKeyColumns);
$otherKeys = array_keys($mapping['relationToSourceKeyColumns']);
}
} else {
$keys = array_keys($mapping->relationToSourceKeyColumns);
$keys = array_keys($mapping['relationToSourceKeyColumns']);
if ($selfReferential) {
$otherKeys = array_keys($mapping->relationToTargetKeyColumns);
$otherKeys = array_keys($mapping['relationToTargetKeyColumns']);
}
}
if(!$mapping->isOnDeleteCascade) {
$this->_conn->delete($mapping->joinTable['name'], array_combine($keys, $identifier));
if ( ! isset($mapping['isOnDeleteCascade'])) {
$this->_conn->delete($mapping['joinTable']['name'], array_combine($keys, $identifier));
if ($selfReferential) {
$this->_conn->delete($mapping->joinTable['name'], array_combine($otherKeys, $identifier));
$this->_conn->delete($mapping['joinTable']['name'], array_combine($otherKeys, $identifier));
}
}
}
@ -443,7 +439,7 @@ class BasicEntityPersister
if (isset($this->_class->associationMappings[$field])) {
$assoc = $this->_class->associationMappings[$field];
// Only owning side of x-1 associations can have a FK column.
if ( ! $assoc->isOwningSide || ! $assoc->isOneToOne()) {
if ( ! $assoc['isOwningSide'] || ! ($assoc['type'] & ClassMetadata::TO_ONE)) {
continue;
}
@ -464,10 +460,10 @@ class BasicEntityPersister
$newValId = $uow->getEntityIdentifier($newVal);
}
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
$owningTable = $this->getOwningTable($field);
foreach ($assoc->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
foreach ($assoc['sourceToTargetKeyColumns'] as $sourceColumn => $targetColumn) {
if ($newVal === null) {
$result[$owningTable][$sourceColumn] = null;
} else {
@ -540,7 +536,7 @@ class BasicEntityPersister
* Loads an entity of this persister's mapped class as part of a single-valued
* association from another entity.
*
* @param OneToOneMapping $assoc The association to load.
* @param array $assoc The association to load.
* @param object $sourceEntity The entity that owns the association (not necessarily the "owning side").
* @param object $targetEntity The existing ghost entity (proxy) to load, if any.
* @param array $identifier The identifier of the entity to load. Must be provided if
@ -548,21 +544,21 @@ class BasicEntityPersister
* the identifier is derived from the $sourceEntity.
* @return object The loaded and managed entity instance or NULL if the entity can not be found.
*/
public function loadOneToOneEntity(OneToOneMapping $assoc, $sourceEntity, $targetEntity, array $identifier = array())
public function loadOneToOneEntity(array $assoc, $sourceEntity, $targetEntity, array $identifier = array())
{
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
if ($assoc->isOwningSide) {
$isInverseSingleValued = $assoc->inversedBy && ! $targetClass->isCollectionValuedAssociation($assoc->inversedBy);
if ($assoc['isOwningSide']) {
$isInverseSingleValued = $assoc['inversedBy'] && ! $targetClass->isCollectionValuedAssociation($assoc['inversedBy']);
// Mark inverse side as fetched in the hints, otherwise the UoW would
// try to load it in a separate query (remember: to-one inverse sides can not be lazy).
$hints = array();
if ($isInverseSingleValued) {
$hints['fetched'][$targetClass->name][$assoc->inversedBy] = true;
$hints['fetched'][$targetClass->name][$assoc['inversedBy']] = true;
if ($targetClass->subClasses) {
foreach ($targetClass->subClasses as $targetSubclassName) {
$hints['fetched'][$targetSubclassName][$assoc->inversedBy] = true;
$hints['fetched'][$targetSubclassName][$assoc['inversedBy']] = true;
}
}
}
@ -576,13 +572,13 @@ class BasicEntityPersister
// Complete bidirectional association, if necessary
if ($targetEntity !== null && $isInverseSingleValued) {
$targetClass->reflFields[$assoc->inversedBy]->setValue($targetEntity, $sourceEntity);
$targetClass->reflFields[$assoc['inversedBy']]->setValue($targetEntity, $sourceEntity);
}
} else {
$sourceClass = $this->_em->getClassMetadata($assoc->sourceEntityName);
$owningAssoc = $targetClass->getAssociationMapping($assoc->mappedBy);
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
$owningAssoc = $targetClass->getAssociationMapping($assoc['mappedBy']);
// TRICKY: since the association is specular source and target are flipped
foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) {
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
$identifier[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
@ -595,7 +591,7 @@ class BasicEntityPersister
$targetEntity = $this->load($identifier, $targetEntity, $assoc);
if ($targetEntity !== null) {
$targetClass->setFieldValue($targetEntity, $assoc->mappedBy, $sourceEntity);
$targetClass->setFieldValue($targetEntity, $assoc['mappedBy'], $sourceEntity);
}
}
@ -635,14 +631,14 @@ class BasicEntityPersister
// Refresh associations
foreach ($this->_class->associationMappings as $field => $assoc) {
$value = $this->_class->reflFields[$field]->getValue($entity);
if ($assoc->isOneToOne()) {
if ($assoc['type'] & ClassMetadata::TO_ONE) {
if ($value instanceof Proxy && ! $value->__isInitialized__) {
continue; // skip uninitialized proxies
}
if ($assoc->isOwningSide) {
if ($assoc['isOwningSide']) {
$joinColumnValues = array();
foreach ($assoc->targetToSourceKeyColumns as $targetColumn => $srcColumn) {
foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
if ($metaColumns[$srcColumn] !== null) {
$joinColumnValues[$targetColumn] = $metaColumns[$srcColumn];
}
@ -653,18 +649,18 @@ class BasicEntityPersister
} else if ($value !== null) {
// Check identity map first, if the entity is not there,
// place a proxy in there instead.
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
if ($found = $this->_em->getUnitOfWork()->tryGetById($joinColumnValues, $targetClass->rootEntityName)) {
$this->_class->reflFields[$field]->setValue($entity, $found);
// Complete inverse side, if necessary.
if ($assoc->inversedBy) {
$inverseAssoc = $targetClass->associationMappings[$assoc->inversedBy];
$targetClass->reflFields[$inverseAssoc->sourceFieldName]->setValue($found, $entity);
if ($assoc['inversedBy']) {
$inverseAssoc = $targetClass->associationMappings[$assoc['inversedBy']];
$targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($found, $entity);
}
$newData[$field] = $found;
} else {
// FIXME: What is happening with subClassees here?
$proxy = $this->_em->getProxyFactory()->getProxy($assoc->targetEntityName, $joinColumnValues);
$proxy = $this->_em->getProxyFactory()->getProxy($assoc['targetEntity'], $joinColumnValues);
$this->_class->reflFields[$field]->setValue($entity, $proxy);
$newData[$field] = $proxy;
$this->_em->getUnitOfWork()->registerManaged($proxy, $joinColumnValues, array());
@ -672,7 +668,9 @@ class BasicEntityPersister
}
} else {
// Inverse side of 1-1/1-x can never be lazy.
$newData[$field] = $assoc->load($entity, null, $this->_em);
//$newData[$field] = $assoc->load($entity, null, $this->_em);
$newData[$field] = $this->_em->getUnitOfWork()->getEntityPersister($assoc['targetEntity'])
->loadOneToOneEntity($assoc, $entity, null);
}
} else if ($value instanceof PersistentCollection && $value->isInitialized()) {
$value->setInitialized(false);
@ -711,13 +709,13 @@ class BasicEntityPersister
* @param object $sourceEntity The entity that owns the collection.
* @param PersistentCollection $coll The collection to fill.
*/
public function loadManyToManyCollection(ManyToManyMapping $assoc, $sourceEntity, PersistentCollection $coll)
public function loadManyToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
{
$criteria = array();
$sourceClass = $this->_em->getClassMetadata($assoc->sourceEntityName);
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
$joinTableConditions = array();
if ($assoc->isOwningSide) {
foreach ($assoc->relationToSourceKeyColumns as $relationKeyColumn => $sourceKeyColumn) {
if ($assoc['isOwningSide']) {
foreach ($assoc['relationToSourceKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
$criteria[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
@ -727,9 +725,9 @@ class BasicEntityPersister
}
}
} else {
$owningAssoc = $this->_em->getClassMetadata($assoc->targetEntityName)->associationMappings[$assoc->mappedBy];
$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) {
foreach ($owningAssoc['relationToTargetKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
$criteria[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
} else {
@ -826,13 +824,13 @@ class BasicEntityPersister
*/
protected function _getSelectEntitiesSQL(array $criteria, $assoc = null, $lockMode = 0)
{
$joinSql = $assoc != null && $assoc->isManyToMany() ?
$joinSql = $assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY ?
$this->_getSelectManyToManyJoinSQL($assoc) : '';
$conditionSql = $this->_getSelectConditionSQL($criteria, $assoc);
$orderBySql = $assoc !== null && isset($assoc->orderBy) ?
$this->_getCollectionOrderBySQL($assoc->orderBy, $this->_getSQLTableAlias($this->_class->name))
$orderBySql = $assoc !== null && isset($assoc['orderBy']) ?
$this->_getCollectionOrderBySQL($assoc['orderBy'], $this->_getSQLTableAlias($this->_class->name))
: '';
$lockSql = '';
@ -917,17 +915,17 @@ class BasicEntityPersister
* @param ManyToManyMapping $manyToMany
* @return string
*/
protected function _getSelectManyToManyJoinSQL(ManyToManyMapping $manyToMany)
protected function _getSelectManyToManyJoinSQL(array $manyToMany)
{
if ($manyToMany->isOwningSide) {
if ($manyToMany['isOwningSide']) {
$owningAssoc = $manyToMany;
$joinClauses = $manyToMany->relationToTargetKeyColumns;
$joinClauses = $manyToMany['relationToTargetKeyColumns'];
} else {
$owningAssoc = $this->_em->getClassMetadata($manyToMany->targetEntityName)->associationMappings[$manyToMany->mappedBy];
$joinClauses = $owningAssoc->relationToSourceKeyColumns;
$owningAssoc = $this->_em->getClassMetadata($manyToMany['targetEntity'])->associationMappings[$manyToMany['mappedBy']];
$joinClauses = $owningAssoc['relationToSourceKeyColumns'];
}
$joinTableName = $owningAssoc->getQuotedJoinTableName($this->_platform);
$joinTableName = $this->_class->getQuotedJoinTableName($owningAssoc, $this->_platform);
$joinSql = '';
foreach ($joinClauses as $joinTableColumn => $sourceColumn) {
@ -985,8 +983,8 @@ class BasicEntityPersister
}
if (isset($this->_class->associationMappings[$name])) {
$assoc = $this->_class->associationMappings[$name];
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $sourceCol) {
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) {
$columns[] = $sourceCol;
}
}
@ -1030,8 +1028,8 @@ class BasicEntityPersister
{
$sql = '';
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
$sql .= ', ' . $this->_getSQLTableAlias($this->_class->name) . ".$srcColumn AS $columnAlias";
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
@ -1123,10 +1121,10 @@ class BasicEntityPersister
}
$conditionSql .= $this->_class->getQuotedColumnName($field, $this->_platform);
} else if ($assoc !== null) {
if ($assoc->isManyToMany()) {
$owningAssoc = $assoc->isOwningSide ? $assoc : $this->_em->getClassMetadata($assoc->targetEntityName)
->associationMappings[$assoc->mappedBy];
$conditionSql .= $owningAssoc->getQuotedJoinTableName($this->_platform) . '.' . $field;
if ($assoc['type'] == ClassMetadata::MANY_TO_MANY) {
$owningAssoc = $assoc['isOwningSide'] ? $assoc : $this->_em->getClassMetadata($assoc['targetEntity'])
->associationMappings[$assoc['mappedBy']];
$conditionSql .= $this->_class->getQuotedJoinTableName($owningAssoc, $this->_platform) . '.' . $field;
} else {
$conditionSql .= $field;
}
@ -1145,12 +1143,12 @@ class BasicEntityPersister
* @param array $criteria The criteria by which to select the entities.
* @param PersistentCollection The collection to load/fill.
*/
public function loadOneToManyCollection(OneToManyMapping $assoc, $sourceEntity, PersistentCollection $coll)
public function loadOneToManyCollection(array $assoc, $sourceEntity, PersistentCollection $coll)
{
$criteria = array();
$owningAssoc = $this->_class->associationMappings[$assoc->mappedBy];
$sourceClass = $this->_em->getClassMetadata($assoc->sourceEntityName);
foreach ($owningAssoc->targetToSourceKeyColumns as $sourceKeyColumn => $targetKeyColumn) {
$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);
}

View File

@ -20,7 +20,7 @@
namespace Doctrine\ORM\Persisters;
use Doctrine\ORM\ORMException,
Doctrine\ORM\Mapping\ManyToManyMapping;
Doctrine\ORM\Mapping\ClassMetadata;
/**
* The joined subclass persister maps a single entity instance to several tables in the
@ -75,9 +75,9 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
public function getOwningTable($fieldName)
{
if ( ! isset($this->_owningTableMap[$fieldName])) {
if (isset($this->_class->associationMappings[$fieldName]->inherited)) {
if (isset($this->_class->associationMappings[$fieldName]['inherited'])) {
$this->_owningTableMap[$fieldName] = $this->_em->getClassMetadata(
$this->_class->associationMappings[$fieldName]->inherited
$this->_class->associationMappings[$fieldName]['inherited']
)->table['name'];
} else if (isset($this->_class->fieldMappings[$fieldName]['inherited'])) {
$this->_owningTableMap[$fieldName] = $this->_em->getClassMetadata(
@ -247,11 +247,11 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
// Add foreign key columns
foreach ($this->_class->associationMappings as $assoc2) {
if ($assoc2->isOwningSide && $assoc2->isOneToOne()) {
$tableAlias = $assoc2->inherited ?
$this->_getSQLTableAlias($assoc2->inherited)
if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE) {
$tableAlias = isset($assoc2['inherited']) ?
$this->_getSQLTableAlias($assoc2['inherited'])
: $baseTableAlias;
foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) {
foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) {
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
$columnList .= ", $tableAlias.$srcColumn AS $columnAlias";
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
@ -304,8 +304,9 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
// Add join columns (foreign keys)
foreach ($subClass->associationMappings as $assoc2) {
if ($assoc2->isOwningSide && $assoc2->isOneToOne() && ! $assoc2->inherited) {
foreach ($assoc2->targetToSourceKeyColumns as $srcColumn) {
if ($assoc2['isOwningSide'] && $assoc2['type'] & ClassMetadata::TO_ONE
&& ! isset($assoc2['inherited'])) {
foreach ($assoc2['targetToSourceKeyColumns'] as $srcColumn) {
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
$columnList .= ', ' . $tableAlias . ".$srcColumn AS $columnAlias";
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);
@ -326,14 +327,14 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
}
}
$joinSql .= $assoc != null && $assoc->isManyToMany() ?
$joinSql .= $assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY ?
$this->_getSelectManyToManyJoinSQL($assoc) : '';
$conditionSql = $this->_getSelectConditionSQL($criteria, $assoc);
$orderBySql = '';
if ($assoc != null && isset($assoc->orderBy)) {
$orderBySql = $this->_getCollectionOrderBySQL($assoc->orderBy, $baseTableAlias);
if ($assoc != null && isset($assoc['orderBy'])) {
$orderBySql = $this->_getCollectionOrderBySQL($assoc['orderBy'], $baseTableAlias);
}
if ($this->_selectColumnListSql === null) {
@ -385,15 +386,15 @@ class JoinedSubclassPersister extends AbstractEntityInheritancePersister
foreach ($this->_class->reflFields as $name => $field) {
if (isset($this->_class->fieldMappings[$name]['inherited']) && ! isset($this->_class->fieldMappings[$name]['id'])
|| isset($this->_class->associationMappings[$name]->inherited)
|| isset($this->_class->associationMappings[$name]['inherited'])
|| ($this->_class->isVersioned && $this->_class->versionField == $name)) {
continue;
}
if (isset($this->_class->associationMappings[$name])) {
$assoc = $this->_class->associationMappings[$name];
if ($assoc->isOneToOne() && $assoc->isOwningSide) {
foreach ($assoc->targetToSourceKeyColumns as $sourceCol) {
if ($assoc['type'] & ClassMetadata::TO_ONE && $assoc['isOwningSide']) {
foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) {
$columns[] = $sourceCol;
}
}

View File

@ -39,8 +39,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
protected function _getDeleteRowSQL(PersistentCollection $coll)
{
$mapping = $coll->getMapping();
$joinTable = $mapping->joinTable;
$columns = $mapping->joinTableColumns;
$joinTable = $mapping['joinTable'];
$columns = $mapping['joinTableColumns'];
return 'DELETE FROM ' . $joinTable['name'] . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?';
}
@ -74,8 +74,8 @@ class ManyToManyPersister extends AbstractCollectionPersister
protected function _getInsertRowSQL(PersistentCollection $coll)
{
$mapping = $coll->getMapping();
$joinTable = $mapping->joinTable;
$columns = $mapping->joinTableColumns;
$joinTable = $mapping['joinTable'];
$columns = $mapping['joinTableColumns'];
return 'INSERT INTO ' . $joinTable['name'] . ' (' . implode(', ', $columns) . ')'
. ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
}
@ -104,7 +104,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
{
$params = array();
$mapping = $coll->getMapping();
$isComposite = count($mapping->joinTableColumns) > 2;
$isComposite = count($mapping['joinTableColumns']) > 2;
$identifier1 = $this->_uow->getEntityIdentifier($coll->getOwner());
$identifier2 = $this->_uow->getEntityIdentifier($element);
@ -114,16 +114,16 @@ class ManyToManyPersister extends AbstractCollectionPersister
$class2 = $coll->getTypeClass();
}
foreach ($mapping->joinTableColumns as $joinTableColumn) {
if (isset($mapping->relationToSourceKeyColumns[$joinTableColumn])) {
foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
if (isset($mapping['relationToSourceKeyColumns'][$joinTableColumn])) {
if ($isComposite) {
$params[] = $identifier1[$class1->fieldNames[$mapping->relationToSourceKeyColumns[$joinTableColumn]]];
$params[] = $identifier1[$class1->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
} else {
$params[] = array_pop($identifier1);
}
} else {
if ($isComposite) {
$params[] = $identifier2[$class2->fieldNames[$mapping->relationToTargetKeyColumns[$joinTableColumn]]];
$params[] = $identifier2[$class2->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
} else {
$params[] = array_pop($identifier2);
}
@ -141,9 +141,9 @@ class ManyToManyPersister extends AbstractCollectionPersister
protected function _getDeleteSQL(PersistentCollection $coll)
{
$mapping = $coll->getMapping();
$joinTable = $mapping->joinTable;
$joinTable = $mapping['joinTable'];
$whereClause = '';
foreach ($mapping->relationToSourceKeyColumns as $relationColumn => $srcColumn) {
foreach ($mapping['relationToSourceKeyColumns'] as $relationColumn => $srcColumn) {
if ($whereClause !== '') $whereClause .= ' AND ';
$whereClause .= "$relationColumn = ?";
}
@ -162,9 +162,9 @@ class ManyToManyPersister extends AbstractCollectionPersister
$params = array();
$mapping = $coll->getMapping();
$identifier = $this->_uow->getEntityIdentifier($coll->getOwner());
if (count($mapping->relationToSourceKeyColumns) > 1) {
if (count($mapping['relationToSourceKeyColumns']) > 1) {
$sourceClass = $this->_em->getClassMetadata(get_class($mapping->getOwner()));
foreach ($mapping->relationToSourceKeyColumns as $relColumn => $srcColumn) {
foreach ($mapping['relationToSourceKeyColumns'] as $relColumn => $srcColumn) {
$params[] = $identifier[$sourceClass->fieldNames[$srcColumn]];
}
} else {

View File

@ -50,7 +50,7 @@ class OneToManyPersister extends AbstractCollectionPersister
$targetClass = $this->_em->getClassMetadata($mapping->getTargetEntityName());
$table = $targetClass->getTableName();
$ownerMapping = $targetClass->getAssociationMapping($mapping->mappedBy);
$ownerMapping = $targetClass->getAssociationMapping($mapping['mappedBy']);
$setClause = '';
foreach ($ownerMapping->sourceToTargetKeyColumns as $sourceCol => $targetCol) {

View File

@ -61,8 +61,8 @@ class SingleTablePersister extends AbstractEntityInheritancePersister
}
// Foreign key columns
foreach ($subClass->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne() && ! $assoc->inherited) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE && ! isset($assoc['inherited'])) {
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
$columnAlias = $srcColumn . $this->_sqlAliasCounter++;
$columnList .= ', ' . $tableAlias . ".$srcColumn AS $columnAlias";
$resultColumnName = $this->_platform->getSQLResultCasing($columnAlias);

View File

@ -51,18 +51,18 @@ class SizeFunction extends FunctionNode
$assoc = $class->associationMappings[$assocField];
$sql = 'SELECT COUNT(*) FROM ';
if ($assoc->isOneToMany()) {
$targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc->targetEntityName);
if ($assoc['type'] == \Doctrine\ORM\Mapping\ClassMetadata::ONE_TO_MANY) {
$targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc['targetEntity']);
$targetTableAlias = $sqlWalker->getSqlTableAlias($targetClass->table['name']);
$sourceTableAlias = $sqlWalker->getSqlTableAlias($class->table['name'], $dqlAlias);
$sql .= $targetClass->getQuotedTableName($platform) . ' ' . $targetTableAlias . ' WHERE ';
$owningAssoc = $targetClass->associationMappings[$assoc->mappedBy];
$owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']];
$first = true;
foreach ($owningAssoc->targetToSourceKeyColumns as $targetColumn => $sourceColumn) {
foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= $targetTableAlias . '.' . $sourceColumn
@ -70,19 +70,19 @@ class SizeFunction extends FunctionNode
. $sourceTableAlias . '.' . $class->getQuotedColumnName($class->fieldNames[$targetColumn], $platform);
}
} else { // many-to-many
$targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc->targetEntityName);
$targetClass = $sqlWalker->getEntityManager()->getClassMetadata($assoc['targetEntity']);
$owningAssoc = $assoc->isOwningSide ? $assoc : $targetClass->associationMappings[$assoc->mappedBy];
$joinTable = $owningAssoc->joinTable;
$owningAssoc = $assoc['isOwningSide'] ? $assoc : $targetClass->associationMappings[$assoc['mappedBy']];
$joinTable = $owningAssoc['joinTable'];
// SQL table aliases
$joinTableAlias = $sqlWalker->getSqlTableAlias($joinTable['name']);
$sourceTableAlias = $sqlWalker->getSqlTableAlias($class->table['name'], $dqlAlias);
// join to target table
$sql .= $owningAssoc->getQuotedJoinTableName($platform) . ' ' . $joinTableAlias . ' WHERE ';
$sql .= $targetClass->getQuotedJoinTableName($owningAssoc, $platform) . ' ' . $joinTableAlias . ' WHERE ';
$joinColumns = $assoc->isOwningSide
$joinColumns = $assoc['isOwningSide']
? $joinTable['joinColumns']
: $joinTable['inverseJoinColumns'];

View File

@ -86,7 +86,7 @@ class MultiTableUpdateExecutor extends AbstractSqlExecutor
foreach ($updateItems as $updateItem) {
$field = $updateItem->pathExpression->field;
if (isset($class->fieldMappings[$field]) && ! isset($class->fieldMappings[$field]['inherited']) ||
isset($class->associationMappings[$field]) && ! $class->associationMappings[$field]->inherited) {
isset($class->associationMappings[$field]) && ! isset($class->associationMappings[$field]['inherited'])) {
$newValue = $updateItem->newValue;
if ( ! $affected) {

View File

@ -20,6 +20,7 @@
namespace Doctrine\ORM\Query;
use Doctrine\ORM\Query;
use Doctrine\ORM\Mapping\ClassMetadata;
/**
* An LL(*) recursive-descent parser for the context-free grammar of the Doctrine Query Language.
@ -581,9 +582,9 @@ class Parser
$fieldType = AST\PathExpression::TYPE_STATE_FIELD;
} else {
$assoc = $class->associationMappings[$field];
$class = $this->_em->getClassMetadata($assoc->targetEntityName);
$class = $this->_em->getClassMetadata($assoc['targetEntity']);
if ($assoc->isOneToOne()) {
if ($assoc['type'] & ClassMetadata::TO_ONE) {
$fieldType = AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION;
} else {
$fieldType = AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION;
@ -1478,7 +1479,7 @@ class Parser
);
}
$targetClassName = $parentClass->getAssociationMapping($assocField)->targetEntityName;
$targetClassName = $parentClass->associationMappings[$assocField]['targetEntity'];
// Building queryComponent
$joinQueryComponent = array(

View File

@ -91,7 +91,7 @@ class QueryException extends \Doctrine\ORM\ORMException
{
return new self(
"Invalid query operation: Not allowed to iterate over fetch join collections ".
"in class ".$assoc->sourceEntityName." assocation ".$assoc->sourceFieldName
"in class ".$assoc['sourceEntity']." assocation ".$assoc['fieldName']
);
}
@ -108,7 +108,7 @@ class QueryException extends \Doctrine\ORM\ORMException
{
return new self(
"Unsupported query operation: It is not yet possible to overwrite the join ".
"conditions in class ".$assoc->sourceEntityName." assocation ".$assoc->sourceFieldName.". ".
"conditions in class ".$assoc['sourceEntityName']." assocation ".$assoc['fieldName'].". ".
"Use WITH to append additional join conditions to the association."
);
}
@ -123,8 +123,8 @@ class QueryException extends \Doctrine\ORM\ORMException
public static function iterateWithFetchJoinNotAllowed($assoc) {
return new self(
"Iterate with fetch join in class " . $assoc->sourceEntityName .
" using association " . $assoc->sourceFieldName . " not allowed."
"Iterate with fetch join in class " . $assoc['sourceEntity'] .
" using association " . $assoc['fieldName'] . " not allowed."
);
}

View File

@ -20,6 +20,7 @@
namespace Doctrine\ORM\Query;
use Doctrine\DBAL\LockMode,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Query,
Doctrine\ORM\Query\QueryException;
@ -287,8 +288,8 @@ class SqlWalker implements TreeWalker
$sql = '';
foreach ($this->_selectedClasses AS $dqlAlias => $class) {
$qComp = $this->_queryComponents[$dqlAlias];
if (isset($qComp['relation']->orderBy)) {
foreach ($qComp['relation']->orderBy AS $fieldName => $orientation) {
if (isset($qComp['relation']['orderBy'])) {
foreach ($qComp['relation']['orderBy'] AS $fieldName => $orientation) {
if ($qComp['metadata']->isInheritanceTypeJoined()) {
$tableName = $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName);
} else {
@ -484,15 +485,15 @@ class SqlWalker implements TreeWalker
$dqlAlias = $pathExpr->identificationVariable;
$class = $this->_queryComponents[$dqlAlias]['metadata'];
if (isset($class->associationMappings[$fieldName]->inherited)) {
$class = $this->_em->getClassMetadata($class->associationMappings[$fieldName]->inherited);
if (isset($class->associationMappings[$fieldName]['inherited'])) {
$class = $this->_em->getClassMetadata($class->associationMappings[$fieldName]['inherited']);
}
$assoc = $class->associationMappings[$fieldName];
if ($assoc->isOwningSide) {
if ($assoc['isOwningSide']) {
// COMPOSITE KEYS NOT (YET?) SUPPORTED
if (count($assoc->sourceToTargetKeyColumns) > 1) {
if (count($assoc['sourceToTargetKeyColumns']) > 1) {
throw QueryException::associationPathCompositeKeyNotSupported();
}
@ -500,7 +501,7 @@ class SqlWalker implements TreeWalker
$sql .= $this->getSqlTableAlias($class->table['name'], $dqlAlias) . '.';
}
$sql .= reset($assoc->targetToSourceKeyColumns);
$sql .= reset($assoc['targetToSourceKeyColumns']);
} else {
throw QueryException::associationPathInverseSideNotSupported();
}
@ -539,7 +540,7 @@ class SqlWalker implements TreeWalker
$this->_rsm->addJoinedEntityResult(
$class->name, $dqlAlias,
$this->_queryComponents[$dqlAlias]['parent'],
$this->_queryComponents[$dqlAlias]['relation']->sourceFieldName
$this->_queryComponents[$dqlAlias]['relation']['fieldName']
);
}
@ -559,15 +560,15 @@ class SqlWalker implements TreeWalker
if ($addMetaColumns) {
//FIXME: Include foreign key columns of child classes also!!??
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
if ($assoc->inherited) {
$owningClass = $this->_em->getClassMetadata($assoc->inherited);
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
if (isset($assoc['inherited'])) {
$owningClass = $this->_em->getClassMetadata($assoc['inherited']);
$sqlTableAlias = $this->getSqlTableAlias($owningClass->table['name'], $dqlAlias);
} else {
$sqlTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
}
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
$columnAlias = $this->getSqlColumnAlias($srcColumn);
$sql .= ", $sqlTableAlias." . $srcColumn . ' AS ' . $columnAlias;
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
@ -581,8 +582,8 @@ class SqlWalker implements TreeWalker
if ($addMetaColumns) {
$sqlTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
$columnAlias = $this->getSqlColumnAlias($srcColumn);
$sql .= ', ' . $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
$columnAlias = $this->_platform->getSQLResultCasing($columnAlias);
@ -722,29 +723,29 @@ class SqlWalker implements TreeWalker
$joinAssocPathExpr = $join->joinAssociationPathExpression;
$joinedDqlAlias = $join->aliasIdentificationVariable;
$relation = $this->_queryComponents[$joinedDqlAlias]['relation'];
$targetClass = $this->_em->getClassMetadata($relation->targetEntityName);
$sourceClass = $this->_em->getClassMetadata($relation->sourceEntityName);
$targetClass = $this->_em->getClassMetadata($relation['targetEntity']);
$sourceClass = $this->_em->getClassMetadata($relation['sourceEntity']);
$targetTableName = $targetClass->getQuotedTableName($this->_platform);
$targetTableAlias = $this->getSqlTableAlias($targetClass->table['name'], $joinedDqlAlias);
$sourceTableAlias = $this->getSqlTableAlias($sourceClass->table['name'], $joinAssocPathExpr->identificationVariable);
// Ensure we got the owning side, since it has all mapping info
$assoc = ( ! $relation->isOwningSide) ? $targetClass->associationMappings[$relation->mappedBy] : $relation;
$assoc = ( ! $relation['isOwningSide']) ? $targetClass->associationMappings[$relation['mappedBy']] : $relation;
if ($this->_query->getHint(Query::HINT_INTERNAL_ITERATION) == true) {
if ($relation->isOneToMany() || $relation->isManyToMany()) {
if ($relation['type'] == ClassMetadata::ONE_TO_MANY || $relation['type'] == ClassMetadata::MANY_TO_MANY) {
throw QueryException::iterateWithFetchJoinNotAllowed($assoc);
}
}
if ($assoc->isOneToOne()) {
if ($assoc['type'] & ClassMetadata::TO_ONE) {
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
$first = true;
foreach ($assoc->sourceToTargetKeyColumns as $sourceColumn => $targetColumn) {
foreach ($assoc['sourceToTargetKeyColumns'] as $sourceColumn => $targetColumn) {
if ( ! $first) $sql .= ' AND '; else $first = false;
if ($relation->isOwningSide) {
if ($relation['isOwningSide']) {
$quotedTargetColumn = $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform);
$sql .= $sourceTableAlias . '.' . $sourceColumn
. ' = '
@ -756,15 +757,15 @@ class SqlWalker implements TreeWalker
. $targetTableAlias . '.' . $sourceColumn;
}
}
} else if ($assoc->isManyToMany()) {
} else if ($assoc['type'] == ClassMetadata::MANY_TO_MANY) {
// Join relation table
$joinTable = $assoc->joinTable;
$joinTable = $assoc['joinTable'];
$joinTableAlias = $this->getSqlTableAlias($joinTable['name'], $joinedDqlAlias);
$sql .= $assoc->getQuotedJoinTableName($this->_platform) . ' ' . $joinTableAlias . ' ON ';
$sql .= $sourceClass->getQuotedJoinTableName($assoc, $this->_platform) . ' ' . $joinTableAlias . ' ON ';
$first = true;
if ($relation->isOwningSide) {
foreach ($assoc->relationToSourceKeyColumns as $relationColumn => $sourceColumn) {
if ($relation['isOwningSide']) {
foreach ($assoc['relationToSourceKeyColumns'] as $relationColumn => $sourceColumn) {
if ( ! $first) $sql .= ' AND '; else $first = false;
$sql .= $sourceTableAlias . '.' . $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$sourceColumn], $this->_platform)
@ -772,7 +773,7 @@ class SqlWalker implements TreeWalker
. $joinTableAlias . '.' . $relationColumn;
}
} else {
foreach ($assoc->relationToTargetKeyColumns as $relationColumn => $targetColumn) {
foreach ($assoc['relationToTargetKeyColumns'] as $relationColumn => $targetColumn) {
if ( ! $first) $sql .= ' AND '; else $first = false;
$sql .= $sourceTableAlias . '.' . $sourceClass->getQuotedColumnName($sourceClass->fieldNames[$targetColumn], $this->_platform)
@ -787,8 +788,8 @@ class SqlWalker implements TreeWalker
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
$first = true;
if ($relation->isOwningSide) {
foreach ($assoc->relationToTargetKeyColumns as $relationColumn => $targetColumn) {
if ($relation['isOwningSide']) {
foreach ($assoc['relationToTargetKeyColumns'] as $relationColumn => $targetColumn) {
if ( ! $first) $sql .= ' AND '; else $first = false;
$sql .= $targetTableAlias . '.' . $targetClass->getQuotedColumnName($targetClass->fieldNames[$targetColumn], $this->_platform)
@ -796,7 +797,7 @@ class SqlWalker implements TreeWalker
. $joinTableAlias . '.' . $relationColumn;
}
} else {
foreach ($assoc->relationToSourceKeyColumns as $relationColumn => $sourceColumn) {
foreach ($assoc['relationToSourceKeyColumns'] as $relationColumn => $sourceColumn) {
if ( ! $first) $sql .= ' AND '; else $first = false;
$sql .= $targetTableAlias . '.' . $targetClass->getQuotedColumnName($targetClass->fieldNames[$sourceColumn], $this->_platform)
@ -995,8 +996,8 @@ class SqlWalker implements TreeWalker
// Add join columns (foreign keys) of the subclass
//TODO: Probably better do this in walkSelectClause to honor the INCLUDE_META_COLUMNS hint
foreach ($subClass->associationMappings as $fieldName => $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne() && ! $assoc->inherited) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE && ! isset($assoc['inherited'])) {
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
if ($beginning) $beginning = false; else $sql .= ', ';
$columnAlias = $this->getSqlColumnAlias($srcColumn);
$sql .= $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
@ -1359,19 +1360,19 @@ class SqlWalker implements TreeWalker
$assoc = $class->associationMappings[$fieldName];
if ($assoc->isOneToMany()) {
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
if ($assoc['type'] == ClassMetadata::ONE_TO_MANY) {
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
$targetTableAlias = $this->getSqlTableAlias($targetClass->table['name']);
$sourceTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
$sql .= $targetClass->getQuotedTableName($this->_platform)
. ' ' . $targetTableAlias . ' WHERE ';
$owningAssoc = $targetClass->associationMappings[$assoc->mappedBy];
$owningAssoc = $targetClass->associationMappings[$assoc['mappedBy']];
$first = true;
foreach ($owningAssoc->targetToSourceKeyColumns as $targetColumn => $sourceColumn) {
foreach ($owningAssoc['targetToSourceKeyColumns'] as $targetColumn => $sourceColumn) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= $sourceTableAlias . '.' . $class->getQuotedColumnName($class->fieldNames[$targetColumn], $this->_platform)
@ -1390,24 +1391,24 @@ class SqlWalker implements TreeWalker
. $targetClass->getQuotedColumnName($idField, $this->_platform) . ' = ?';
}
} else { // many-to-many
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
$owningAssoc = $assoc->isOwningSide ? $assoc : $targetClass->associationMappings[$assoc->mappedBy];
$joinTable = $owningAssoc->joinTable;
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
$owningAssoc = $assoc['isOwningSide'] ? $assoc : $targetClass->associationMappings[$assoc['mappedBy']];
$joinTable = $owningAssoc['joinTable'];
// SQL table aliases
$joinTableAlias = $this->getSqlTableAlias($joinTable['name']);
$targetTableAlias = $this->getSqlTableAlias($targetClass->table['name']);
$sourceTableAlias = $this->getSqlTableAlias($class->table['name'], $dqlAlias);
// join to target table
$sql .= $owningAssoc->getQuotedJoinTableName($this->_platform)
$sql .= $targetClass->getQuotedJoinTableName($owningAssoc, $this->_platform)
. ' ' . $joinTableAlias . ' INNER JOIN '
. $targetClass->getQuotedTableName($this->_platform)
. ' ' . $targetTableAlias . ' ON ';
// join conditions
$joinColumns = $assoc->isOwningSide
$joinColumns = $assoc['isOwningSide']
? $joinTable['inverseJoinColumns']
: $joinTable['joinColumns'];
@ -1423,7 +1424,7 @@ class SqlWalker implements TreeWalker
$sql .= ' WHERE ';
$joinColumns = $assoc->isOwningSide
$joinColumns = $assoc['isOwningSide']
? $joinTable['joinColumns']
: $joinTable['inverseJoinColumns'];

View File

@ -505,34 +505,34 @@ public function <methodName>()
}
foreach ($metadata->associationMappings as $associationMapping) {
if ($associationMapping instanceof \Doctrine\ORM\Mapping\OneToOneMapping) {
if ($code = $this->_generateEntityStubMethod($metadata, 'set', $associationMapping->sourceFieldName, $associationMapping->targetEntityName)) {
if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
if ($code = $this->_generateEntityStubMethod($metadata, 'set', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
$methods[] = $code;
}
if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping->sourceFieldName, $associationMapping->targetEntityName)) {
if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
$methods[] = $code;
}
} else if ($associationMapping instanceof \Doctrine\ORM\Mapping\OneToManyMapping) {
} else if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_MANY) {
if ($associationMapping->isOwningSide) {
if ($code = $this->_generateEntityStubMethod($metadata, 'set', $associationMapping->sourceFieldName, $associationMapping->targetEntityName)) {
if ($code = $this->_generateEntityStubMethod($metadata, 'set', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
$methods[] = $code;
}
if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping->sourceFieldName, $associationMapping->targetEntityName)) {
if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
$methods[] = $code;
}
} else {
if ($code = $this->_generateEntityStubMethod($metadata, 'add', $associationMapping->sourceFieldName, $associationMapping->targetEntityName)) {
if ($code = $this->_generateEntityStubMethod($metadata, 'add', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
$methods[] = $code;
}
if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping->sourceFieldName, 'Doctrine\Common\Collections\Collection')) {
if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], 'Doctrine\Common\Collections\Collection')) {
$methods[] = $code;
}
}
} else if ($associationMapping instanceof \Doctrine\ORM\Mapping\ManyToManyMapping) {
if ($code = $this->_generateEntityStubMethod($metadata, 'add', $associationMapping->sourceFieldName, $associationMapping->targetEntityName)) {
} else if ($associationMapping['type'] == ClassMetadataInfo::MANY_TO_MANY) {
if ($code = $this->_generateEntityStubMethod($metadata, 'add', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
$methods[] = $code;
}
if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping->sourceFieldName, 'Doctrine\Common\Collections\Collection')) {
if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], 'Doctrine\Common\Collections\Collection')) {
$methods[] = $code;
}
}
@ -563,13 +563,13 @@ public function <methodName>()
$lines = array();
foreach ($metadata->associationMappings as $associationMapping) {
if ($this->_hasProperty($associationMapping->sourceFieldName, $metadata)) {
if ($this->_hasProperty($associationMapping['fieldName'], $metadata)) {
continue;
}
$lines[] = $this->_generateAssociationMappingPropertyDocBlock($associationMapping, $metadata);
$lines[] = $this->_spaces . 'private $' . $associationMapping->sourceFieldName
. ($associationMapping->isManyToMany() ? ' = array()' : null) . ";\n";
$lines[] = $this->_spaces . 'private $' . $associationMapping['fieldName']
. ($associationMapping['type'] == 'manyToMany' ? ' = array()' : null) . ";\n";
}
return implode("\n", $lines);
@ -681,55 +681,68 @@ public function <methodName>()
return '@JoinColumn(' . implode(', ', $joinColumnAnnot) . ')';
}
private function _generateAssociationMappingPropertyDocBlock(AssociationMapping $associationMapping, ClassMetadataInfo $metadata)
private function _generateAssociationMappingPropertyDocBlock(array $associationMapping, ClassMetadataInfo $metadata)
{
$lines = array();
$lines[] = $this->_spaces . '/**';
$lines[] = $this->_spaces . ' * @var ' . $associationMapping->targetEntityName;
$lines[] = $this->_spaces . ' * @var ' . $associationMapping['targetEntity'];
if ($this->_generateAnnotations) {
$lines[] = $this->_spaces . ' *';
$e = explode('\\', get_class($associationMapping));
$type = str_replace('Mapping', '', end($e));
$type = null;
switch ($associationMapping['type']) {
case ClassMetadataInfo::ONE_TO_ONE:
$type = 'OneToOne';
break;
case ClassMetadataInfo::MANY_TO_ONE:
$type = 'ManyToOne';
break;
case ClassMetadataInfo::ONE_TO_MANY:
$type = 'OneToMany';
break;
case ClassMetadataInfo::MANY_TO_MANY:
$type = 'ManyToMany';
break;
}
$typeOptions = array();
if (isset($associationMapping->targetEntityName)) {
$typeOptions[] = 'targetEntity="' . $associationMapping->targetEntityName . '"';
if (isset($associationMapping['targetEntity'])) {
$typeOptions[] = 'targetEntity="' . $associationMapping['targetEntity'] . '"';
}
if (isset($associationMapping->inversedBy)) {
$typeOptions[] = 'inversedBy="' . $associationMapping->inversedBy . '"';
if (isset($associationMapping['inversedBy'])) {
$typeOptions[] = 'inversedBy="' . $associationMapping['inversedBy'] . '"';
}
if (isset($associationMapping->mappedBy)) {
$typeOptions[] = 'mappedBy="' . $associationMapping->mappedBy . '"';
if (isset($associationMapping['mappedBy'])) {
$typeOptions[] = 'mappedBy="' . $associationMapping['mappedBy'] . '"';
}
if ($associationMapping->hasCascades()) {
if ($associationMapping['cascade']) {
$cascades = array();
if ($associationMapping->isCascadePersist) $cascades[] = '"persist"';
if ($associationMapping->isCascadeRemove) $cascades[] = '"remove"';
if ($associationMapping->isCascadeDetach) $cascades[] = '"detach"';
if ($associationMapping->isCascadeMerge) $cascades[] = '"merge"';
if ($associationMapping->isCascadeRefresh) $cascades[] = '"refresh"';
if ($associationMapping['isCascadePersist']) $cascades[] = '"persist"';
if ($associationMapping['isCascadeRemove']) $cascades[] = '"remove"';
if ($associationMapping['isCascadeDetach']) $cascades[] = '"detach"';
if ($associationMapping['isCascadeMerge']) $cascades[] = '"merge"';
if ($associationMapping['isCascadeRefresh']) $cascades[] = '"refresh"';
$typeOptions[] = 'cascade={' . implode(',', $cascades) . '}';
}
if (isset($associationMapping->orphanRemoval) && $associationMapping->orphanRemoval) {
$typeOptions[] = 'orphanRemoval=' . ($associationMapping->orphanRemoval ? 'true' : 'false');
if (isset($associationMapping['orphanRemoval']) && $associationMapping['orphanRemoval']) {
$typeOptions[] = 'orphanRemoval=' . ($associationMapping['orphanRemoval'] ? 'true' : 'false');
}
$lines[] = $this->_spaces . ' * @' . $type . '(' . implode(', ', $typeOptions) . ')';
if (isset($associationMapping->joinColumns) && $associationMapping->joinColumns) {
if (isset($associationMapping['joinColumns']) && $associationMapping['joinColumns']) {
$lines[] = $this->_spaces . ' * @JoinColumns({';
$joinColumnsLines = array();
foreach ($associationMapping->joinColumns as $joinColumn) {
foreach ($associationMapping['joinColumns'] as $joinColumn) {
if ($joinColumnAnnot = $this->_generateJoinColumnAnnotation($joinColumn)) {
$joinColumnsLines[] = $this->_spaces . ' * ' . $joinColumnAnnot;
}
@ -739,25 +752,25 @@ public function <methodName>()
$lines[] = $this->_spaces . ' * })';
}
if (isset($associationMapping->joinTable) && $associationMapping->joinTable) {
if (isset($associationMapping['joinTable']) && $associationMapping['joinTable']) {
$joinTable = array();
$joinTable[] = 'name="' . $associationMapping->joinTable['name'] . '"';
$joinTable[] = 'name="' . $associationMapping['joinTable']['name'] . '"';
if (isset($associationMapping->joinTable['schema'])) {
$joinTable[] = 'schema="' . $associationMapping->joinTable['schema'] . '"';
if (isset($associationMapping['joinTable']['schema'])) {
$joinTable[] = 'schema="' . $associationMapping['joinTable']['schema'] . '"';
}
$lines[] = $this->_spaces . ' * @JoinTable(' . implode(', ', $joinTable) . ',';
$lines[] = $this->_spaces . ' * joinColumns={';
foreach ($associationMapping->joinTable['joinColumns'] as $joinColumn) {
foreach ($associationMapping['joinTable']['joinColumns'] as $joinColumn) {
$lines[] = $this->_spaces . ' * ' . $this->_generateJoinColumnAnnotation($joinColumn);
}
$lines[] = $this->_spaces . ' * },';
$lines[] = $this->_spaces . ' * inverseJoinColumns={';
foreach ($associationMapping->joinTable['inverseJoinColumns'] as $joinColumn) {
foreach ($associationMapping['joinTable']['inverseJoinColumns'] as $joinColumn) {
$lines[] = $this->_spaces . ' * ' . $this->_generateJoinColumnAnnotation($joinColumn);
}
@ -765,10 +778,10 @@ public function <methodName>()
$lines[] = $this->_spaces . ' * )';
}
if (isset($associationMapping->orderBy)) {
if (isset($associationMapping['orderBy'])) {
$lines[] = $this->_spaces . ' * @OrderBy({';
foreach ($associationMapping->orderBy as $name => $direction) {
foreach ($associationMapping['orderBy'] as $name => $direction) {
$lines[] = $this->_spaces . ' * "' . $name . '"="' . $direction . '",';
}

View File

@ -99,41 +99,41 @@ class PhpExporter extends AbstractExporter
foreach ($metadata->associationMappings as $associationMapping) {
$cascade = array('remove', 'persist', 'refresh', 'merge', 'detach');
foreach ($cascade as $key => $value) {
if ( ! $associationMapping->{'isCascade'.ucfirst($value)}) {
if ( ! $associationMapping['isCascade'.ucfirst($value)]) {
unset($cascade[$key]);
}
}
$associationMappingArray = array(
'fieldName' => $associationMapping->sourceFieldName,
'targetEntity' => $associationMapping->targetEntityName,
'fieldName' => $associationMapping['fieldName'],
'targetEntity' => $associationMapping['targetEntity'],
'cascade' => $cascade,
);
if ($associationMapping instanceof \Doctrine\ORM\Mapping\OneToOneMapping) {
if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
$method = 'mapOneToOne';
$oneToOneMappingArray = array(
'mappedBy' => $associationMapping->mappedBy,
'inversedBy' => $associationMapping->inversedBy,
'joinColumns' => $associationMapping->joinColumns,
'orphanRemoval' => $associationMapping->orphanRemoval,
'mappedBy' => $associationMapping['mappedBy'],
'inversedBy' => $associationMapping['inversedBy'],
'joinColumns' => $associationMapping['joinColumns'],
'orphanRemoval' => $associationMapping['orphanRemoval'],
);
$associationMappingArray = array_merge($associationMappingArray, $oneToOneMappingArray);
} else if ($associationMapping instanceof \Doctrine\ORM\Mapping\OneToManyMapping) {
} else if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_MANY) {
$method = 'mapOneToMany';
$oneToManyMappingArray = array(
'mappedBy' => $associationMapping->mappedBy,
'orphanRemoval' => $associationMapping->orphanRemoval,
'orderBy' => $associationMapping->orderBy
'mappedBy' => $associationMapping['mappedBy'],
'orphanRemoval' => $associationMapping['orphanRemoval'],
'orderBy' => $associationMapping['orderBy']
);
$associationMappingArray = array_merge($associationMappingArray, $oneToManyMappingArray);
} else if ($associationMapping instanceof \Doctrine\ORM\Mapping\ManyToManyMapping) {
} else if ($associationMapping['type'] == ClassMetadataInfo::MANY_TO_MANY) {
$method = 'mapManyToMany';
$manyToManyMappingArray = array(
'mappedBy' => $associationMapping->mappedBy,
'joinTable' => $associationMapping->joinTable,
'orderBy' => $associationMapping->orderBy
'mappedBy' => $associationMapping['mappedBy'],
'joinTable' => $associationMapping['joinTable'],
'orderBy' => $associationMapping['orderBy']
);
$associationMappingArray = array_merge($associationMappingArray, $manyToManyMappingArray);

View File

@ -22,10 +22,7 @@
namespace Doctrine\ORM\Tools\Export\Driver;
use Doctrine\ORM\Mapping\ClassMetadataInfo,
Doctrine\ORM\Mapping\OneToOneMapping,
Doctrine\ORM\Mapping\OneToManyMapping,
Doctrine\ORM\Mapping\ManyToManyMapping;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
/**
* ClassMetadata exporter for Doctrine XML mapping files
@ -182,31 +179,33 @@ class XmlExporter extends AbstractExporter
}
foreach ($metadata->associationMappings as $name => $associationMapping) {
if ($associationMapping instanceof OneToOneMapping) {
if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_ONE) {
$associationMappingXml = $root->addChild('one-to-one');
} else if ($associationMapping instanceof OneToManyMapping) {
} else if ($associationMapping['type'] == ClassMetadataInfo::MANY_TO_ONE) {
$associationMappingXml = $root->addChild('many-to-one');
} else if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_MANY) {
$associationMappingXml = $root->addChild('one-to-many');
} else if ($associationMapping instanceof ManyToManyMapping) {
} else if ($associationMapping['type'] == ClassMetadataInfo::MANY_TO_MANY) {
$associationMappingXml = $root->addChild('many-to-many');
}
$associationMappingXml->addAttribute('field', $associationMapping->sourceFieldName);
$associationMappingXml->addAttribute('target-entity', $associationMapping->targetEntityName);
$associationMappingXml->addAttribute('field', $associationMapping['fieldName']);
$associationMappingXml->addAttribute('target-entity', $associationMapping['targetEntity']);
if (isset($associationMapping->mappedBy)) {
$associationMappingXml->addAttribute('mapped-by', $associationMapping->mappedBy);
if (isset($associationMapping['mappedBy'])) {
$associationMappingXml->addAttribute('mapped-by', $associationMapping['mappedBy']);
}
if (isset($associationMapping->inversedBy)) {
$associationMappingXml->addAttribute('inversed-by', $associationMapping->inversedBy);
if (isset($associationMapping['inversedBy'])) {
$associationMappingXml->addAttribute('inversed-by', $associationMapping['inversedBy']);
}
if (isset($associationMapping->orphanRemoval)) {
$associationMappingXml->addAttribute('orphan-removal', $associationMapping->orphanRemoval);
if (isset($associationMapping['orphanRemoval'])) {
$associationMappingXml->addAttribute('orphan-removal', $associationMapping['orphanRemoval']);
}
if (isset($associationMapping->joinTable) && $associationMapping->joinTable) {
if (isset($associationMapping['joinTable']) && $associationMapping['joinTable']) {
$joinTableXml = $associationMappingXml->addChild('join-table');
$joinTableXml->addAttribute('name', $associationMapping->joinTable['name']);
$joinTableXml->addAttribute('name', $associationMapping['joinTable']['name']);
$joinColumnsXml = $joinTableXml->addChild('join-columns');
foreach ($associationMapping->joinTable['joinColumns'] as $joinColumn) {
foreach ($associationMapping['joinTable']['joinColumns'] as $joinColumn) {
$joinColumnXml = $joinColumnsXml->addChild('join-column');
$joinColumnXml->addAttribute('name', $joinColumn['name']);
$joinColumnXml->addAttribute('referenced-column-name', $joinColumn['referencedColumnName']);
@ -218,7 +217,7 @@ class XmlExporter extends AbstractExporter
}
}
$inverseJoinColumnsXml = $joinTableXml->addChild('inverse-join-columns');
foreach ($associationMapping->joinTable['inverseJoinColumns'] as $inverseJoinColumn) {
foreach ($associationMapping['joinTable']['inverseJoinColumns'] as $inverseJoinColumn) {
$inverseJoinColumnXml = $inverseJoinColumnsXml->addChild('join-column');
$inverseJoinColumnXml->addAttribute('name', $inverseJoinColumn['name']);
$inverseJoinColumnXml->addAttribute('referenced-column-name', $inverseJoinColumn['referencedColumnName']);
@ -239,9 +238,9 @@ class XmlExporter extends AbstractExporter
}
}
}
if (isset($associationMapping->joinColumns)) {
if (isset($associationMapping['joinColumns'])) {
$joinColumnsXml = $associationMappingXml->addChild('join-columns');
foreach ($associationMapping->joinColumns as $joinColumn) {
foreach ($associationMapping['joinColumns'] as $joinColumn) {
$joinColumnXml = $joinColumnsXml->addChild('join-column');
$joinColumnXml->addAttribute('name', $joinColumn['name']);
$joinColumnXml->addAttribute('referenced-column-name', $joinColumn['referencedColumnName']);
@ -259,28 +258,28 @@ class XmlExporter extends AbstractExporter
}
}
}
if (isset($associationMapping->orderBy)) {
if (isset($associationMapping['orderBy'])) {
$orderByXml = $associationMappingXml->addChild('order-by');
foreach ($associationMapping->orderBy as $name => $direction) {
foreach ($associationMapping['orderBy'] as $name => $direction) {
$orderByFieldXml = $orderByXml->addChild('order-by-field');
$orderByFieldXml->addAttribute('name', $name);
$orderByFieldXml->addAttribute('direction', $direction);
}
}
$cascade = array();
if ($associationMapping->isCascadeRemove) {
if ($associationMapping['isCascadeRemove']) {
$cascade[] = 'cascade-remove';
}
if ($associationMapping->isCascadePersist) {
if ($associationMapping['isCascadePersist']) {
$cascade[] = 'cascade-persist';
}
if ($associationMapping->isCascadeRefresh) {
if ($associationMapping['isCascadeRefresh']) {
$cascade[] = 'cascade-refresh';
}
if ($associationMapping->isCascadeMerge) {
if ($associationMapping['isCascadeMerge']) {
$cascade[] = 'cascade-merge';
}
if ($associationMapping->isCascadeDetach) {
if ($associationMapping['isCascadeDetach']) {
$cascade[] = 'cascade-detach';
}
if ($cascade) {

View File

@ -22,10 +22,7 @@
namespace Doctrine\ORM\Tools\Export\Driver;
use Doctrine\ORM\Mapping\ClassMetadataInfo,
Doctrine\ORM\Mapping\OneToOneMapping,
Doctrine\ORM\Mapping\OneToManyMapping,
Doctrine\ORM\Mapping\ManyToManyMapping;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
/**
* ClassMetadata exporter for Doctrine YAML mapping files
@ -134,28 +131,28 @@ class YamlExporter extends AbstractExporter
$associations = array();
foreach ($metadata->associationMappings as $name => $associationMapping) {
$cascade = array();
if ($associationMapping->isCascadeRemove) {
if ($associationMapping['isCascadeRemove']) {
$cascade[] = 'remove';
}
if ($associationMapping->isCascadePersist) {
if ($associationMapping['isCascadePersist']) {
$cascade[] = 'persist';
}
if ($associationMapping->isCascadeRefresh) {
if ($associationMapping['isCascadeRefresh']) {
$cascade[] = 'refresh';
}
if ($associationMapping->isCascadeMerge) {
if ($associationMapping['isCascadeMerge']) {
$cascade[] = 'merge';
}
if ($associationMapping->isCascadeDetach) {
if ($associationMapping['isCascadeDetach']) {
$cascade[] = 'detach';
}
$associationMappingArray = array(
'targetEntity' => $associationMapping->targetEntityName,
'targetEntity' => $associationMapping['targetEntity'],
'cascade' => $cascade,
);
if ($associationMapping instanceof OneToOneMapping) {
$joinColumns = $associationMapping->joinColumns;
if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
$joinColumns = $associationMapping['joinColumns'];
$newJoinColumns = array();
foreach ($joinColumns as $joinColumn) {
$newJoinColumns[$joinColumn['name']]['referencedColumnName'] = $joinColumn['referencedColumnName'];
@ -167,30 +164,30 @@ class YamlExporter extends AbstractExporter
}
}
$oneToOneMappingArray = array(
'mappedBy' => $associationMapping->mappedBy,
'inversedBy' => $associationMapping->inversedBy,
'mappedBy' => $associationMapping['mappedBy'],
'inversedBy' => $associationMapping['inversedBy'],
'joinColumns' => $newJoinColumns,
'orphanRemoval' => $associationMapping->orphanRemoval,
'orphanRemoval' => $associationMapping['orphanRemoval'],
);
$associationMappingArray = array_merge($associationMappingArray, $oneToOneMappingArray);
$array['oneToOne'][$name] = $associationMappingArray;
} else if ($associationMapping instanceof OneToManyMapping) {
} else if ($associationMapping['type'] == ClassMetadataInfo::ONE_TO_MANY) {
$oneToManyMappingArray = array(
'mappedBy' => $associationMapping->mappedBy,
'inversedBy' => $associationMapping->inversedBy,
'orphanRemoval' => $associationMapping->orphanRemoval,
'orderBy' => $associationMapping->orderBy
'mappedBy' => $associationMapping['mappedBy'],
'inversedBy' => $associationMapping['inversedBy'],
'orphanRemoval' => $associationMapping['orphanRemoval'],
'orderBy' => $associationMapping['orderBy']
);
$associationMappingArray = array_merge($associationMappingArray, $oneToManyMappingArray);
$array['oneToMany'][$name] = $associationMappingArray;
} else if ($associationMapping instanceof ManyToManyMapping) {
} else if ($associationMapping['type'] == ClassMetadataInfo::MANY_TO_MANY) {
$manyToManyMappingArray = array(
'mappedBy' => $associationMapping->mappedBy,
'inversedBy' => $associationMapping->inversedBy,
'joinTable' => $associationMapping->joinTable,
'orderBy' => $associationMapping->orderBy
'mappedBy' => $associationMapping['mappedBy'],
'inversedBy' => $associationMapping['inversedBy'],
'joinTable' => $associationMapping['joinTable'],
'orderBy' => isset($associationMapping['orderBy']) ? $associationMapping['orderBy'] : null
);
$associationMappingArray = array_merge($associationMappingArray, $manyToManyMappingArray);

View File

@ -24,6 +24,7 @@ namespace Doctrine\ORM\Tools;
use Doctrine\ORM\ORMException,
Doctrine\DBAL\Types\Type,
Doctrine\ORM\EntityManager,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Internal\CommitOrderCalculator,
Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs,
Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
@ -353,24 +354,24 @@ class SchemaTool
private function _gatherRelationsSql($class, $table, $schema)
{
foreach ($class->associationMappings as $fieldName => $mapping) {
if ($mapping->inherited) {
if (isset($mapping['inherited'])) {
continue;
}
$foreignClass = $this->_em->getClassMetadata($mapping->targetEntityName);
$foreignClass = $this->_em->getClassMetadata($mapping['targetEntity']);
if ($mapping->isOneToOne() && $mapping->isOwningSide) {
if ($mapping['type'] & ClassMetadata::TO_ONE && $mapping['isOwningSide']) {
$primaryKeyColumns = $uniqueConstraints = array(); // unnecessary for this relation-type
$this->_gatherRelationJoinColumns($mapping->joinColumns, $table, $foreignClass, $mapping, $primaryKeyColumns, $uniqueConstraints);
} else if ($mapping->isOneToMany() && $mapping->isOwningSide) {
$this->_gatherRelationJoinColumns($mapping['joinColumns'], $table, $foreignClass, $mapping, $primaryKeyColumns, $uniqueConstraints);
} else if ($mapping['type'] == ClassMetadata::ONE_TO_MANY && $mapping['isOwningSide']) {
//... create join table, one-many through join table supported later
throw ORMException::notSupported();
} else if ($mapping->isManyToMany() && $mapping->isOwningSide) {
} else if ($mapping['type'] == ClassMetadata::MANY_TO_MANY && $mapping['isOwningSide']) {
// create join table
$joinTable = $mapping->joinTable;
$joinTable = $mapping['joinTable'];
$theJoinTable = $schema->createTable($mapping->getQuotedJoinTableName($this->_platform));
$theJoinTable = $schema->createTable($foreignClass->getQuotedJoinTableName($mapping, $this->_platform));
$primaryKeyColumns = $uniqueConstraints = array();
@ -414,7 +415,7 @@ class SchemaTool
if ( ! $class->hasField($referencedFieldName)) {
throw new \Doctrine\ORM\ORMException(
"Column name `".$joinColumn['referencedColumnName']."` referenced for relation from ".
"$mapping->sourceEntityName towards $mapping->targetEntityName does not exist."
$mapping['sourceEntity'] . " towards ". $mapping['targetEntity'] . " does not exist."
);
}
@ -603,7 +604,7 @@ class SchemaTool
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide) {
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
if ( ! $calc->hasClass($targetClass->name)) {
$calc->addClass($targetClass);
@ -624,7 +625,7 @@ class SchemaTool
foreach ($classes as $class) {
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isManyToMany()) {
if ($assoc->isOwningSide && $assoc['type'] == ClassMetadata::MANY_TO_MANY) {
$associationTables[] = $assoc->joinTable['name'];
}
}

View File

@ -20,8 +20,7 @@
namespace Doctrine\ORM\Tools;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ManyToManyMapping;
use Doctrine\ORM\Mapping\OneToOneMapping;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
/**
* Performs strict validation of the mapping schema
@ -73,60 +72,60 @@ class SchemaValidator
$ce = array();
/* @var $class ClassMetadata */
foreach ($class->associationMappings AS $fieldName => $assoc) {
if (!$cmf->hasMetadataFor($assoc->targetEntityName)) {
$ce[] = "The target entity '" . $assoc->targetEntityName . "' specified on " . $class->name . '#' . $fieldName . ' is unknown.';
if (!$cmf->hasMetadataFor($assoc['targetEntity'])) {
$ce[] = "The target entity '" . $assoc['targetEntity'] . "' specified on " . $class->name . '#' . $fieldName . ' is unknown.';
}
if ($assoc->mappedBy && $assoc->inversedBy) {
if ($assoc['mappedBy'] && $assoc['inversedBy']) {
$ce[] = "The association " . $class . "#" . $fieldName . " cannot be defined as both inverse and owning.";
}
$targetMetadata = $cmf->getMetadataFor($assoc->targetEntityName);
$targetMetadata = $cmf->getMetadataFor($assoc['targetEntity']);
/* @var $assoc AssociationMapping */
if ($assoc->mappedBy) {
if ($targetMetadata->hasField($assoc->mappedBy)) {
if ($assoc['mappedBy']) {
if ($targetMetadata->hasField($assoc['mappedBy'])) {
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ".
"field " . $assoc->targetEntityName . "#" . $assoc->mappedBy . " which is not defined as association.";
"field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which is not defined as association.";
}
if (!$targetMetadata->hasAssociation($assoc->mappedBy)) {
if (!$targetMetadata->hasAssociation($assoc['mappedBy'])) {
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the owning side ".
"field " . $assoc->targetEntityName . "#" . $assoc->mappedBy . " which does not exist.";
} else if ($targetMetadata->associationMappings[$assoc->mappedBy]->inversedBy == null) {
"field " . $assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " which does not exist.";
} else if ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] == null) {
$ce[] = "The field " . $class->name . "#" . $fieldName . " is on the inverse side of a ".
"bi-directional relationship, but the specified mappedBy association on the target-entity ".
$assoc->targetEntityName . "#" . $assoc->mappedBy . " does not contain the required ".
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ".
"'inversedBy' attribute.";
} else if ($targetMetadata->associationMappings[$assoc->mappedBy]->inversedBy != $fieldName) {
} else if ($targetMetadata->associationMappings[$assoc['mappedBy']]['inversedBy'] != $fieldName) {
$ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " .
$assoc->targetEntityName . "#" . $assoc->mappedBy . " are ".
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " are ".
"incosistent with each other.";
}
}
if ($assoc->inversedBy) {
if ($targetMetadata->hasField($assoc->inversedBy)) {
if ($assoc['inversedBy']) {
if ($targetMetadata->hasField($assoc['inversedBy'])) {
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the inverse side ".
"field " . $assoc->targetEntityName . "#" . $assoc->inversedBy . " which is not defined as association.";
"field " . $assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " which is not defined as association.";
}
if (!$targetMetadata->hasAssociation($assoc->inversedBy)) {
if (!$targetMetadata->hasAssociation($assoc['inversedBy'])) {
$ce[] = "The association " . $class->name . "#" . $fieldName . " refers to the inverse side ".
"field " . $assoc->targetEntityName . "#" . $assoc->inversedBy . " which does not exist.";
} else if ($targetMetadata->associationMappings[$assoc->inversedBy]->mappedBy == null) {
"field " . $assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " which does not exist.";
} else if ($targetMetadata->associationMappings[$assoc['inversedBy']]['mappedBy'] == null) {
$ce[] = "The field " . $class->name . "#" . $fieldName . " is on the owning side of a ".
"bi-directional relationship, but the specified mappedBy association on the target-entity ".
$assoc->targetEntityName . "#" . $assoc->mappedBy . " does not contain the required ".
$assoc['targetEntity'] . "#" . $assoc['mappedBy'] . " does not contain the required ".
"'inversedBy' attribute.";
} else if ($targetMetadata->associationMappings[$assoc->inversedBy]->mappedBy != $fieldName) {
} else if ($targetMetadata->associationMappings[$assoc['inversedBy']]['mappedBy'] != $fieldName) {
$ce[] = "The mappings " . $class->name . "#" . $fieldName . " and " .
$assoc->targetEntityName . "#" . $assoc->inversedBy . " are ".
$assoc['targetEntity'] . "#" . $assoc['inversedBy'] . " are ".
"incosistent with each other.";
}
}
if ($assoc->isOwningSide) {
if ($assoc instanceof ManyToManyMapping) {
foreach ($assoc->joinTable['joinColumns'] AS $joinColumn) {
if ($assoc['isOwningSide']) {
if ($assoc['type'] == ClassMetadataInfo::MANY_TO_MANY) {
foreach ($assoc['joinTable']['joinColumns'] AS $joinColumn) {
if (!isset($class->fieldNames[$joinColumn['referencedColumnName']])) {
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " .
"have a corresponding field with this column name on the class '" . $class->name . "'.";
@ -139,8 +138,8 @@ class SchemaValidator
"has to be a primary key column.";
}
}
foreach ($assoc->joinTable['inverseJoinColumns'] AS $inverseJoinColumn) {
$targetClass = $cmf->getMetadataFor($assoc->targetEntityName);
foreach ($assoc['joinTable']['inverseJoinColumns'] AS $inverseJoinColumn) {
$targetClass = $cmf->getMetadataFor($assoc['targetEntity']);
if (!isset($targetClass->fieldNames[$inverseJoinColumn['referencedColumnName']])) {
$ce[] = "The inverse referenced column name '" . $inverseJoinColumn['referencedColumnName'] . "' does not " .
"have a corresponding field with this column name on the class '" . $targetClass->name . "'.";
@ -153,9 +152,9 @@ class SchemaValidator
"has to be a primary key column.";
}
}
} else if ($assoc instanceof OneToOneMapping) {
foreach ($assoc->joinColumns AS $joinColumn) {
$targetClass = $cmf->getMetadataFor($assoc->targetEntityName);
} else if ($assoc['type'] & ClassMetadataInfo::TO_ONE) {
foreach ($assoc['joinColumns'] AS $joinColumn) {
$targetClass = $cmf->getMetadataFor($assoc['targetEntity']);
if (!isset($targetClass->fieldNames[$joinColumn['referencedColumnName']])) {
$ce[] = "The referenced column name '" . $joinColumn['referencedColumnName'] . "' does not " .
"have a corresponding field with this column name on the class '" . $targetClass->name . "'.";
@ -171,9 +170,9 @@ class SchemaValidator
}
}
if (isset($assoc->orderBy) && $assoc->orderBy !== null) {
$targetClass = $cmf->getMetadataFor($assoc->targetEntityName);
foreach ($assoc->orderBy AS $orderField => $orientation) {
if (isset($assoc['orderBy']) && $assoc['orderBy'] !== null) {
$targetClass = $cmf->getMetadataFor($assoc['targetEntity']);
foreach ($assoc['orderBy'] AS $orderField => $orientation) {
if (!$targetClass->hasField($orderField)) {
$ce[] = "The association " . $class->name."#".$fieldName." is ordered by a foreign field " .
$orderField . " that is not a field on the target entity " . $targetClass->name;

View File

@ -25,6 +25,7 @@ use Exception, InvalidArgumentException, UnexpectedValueException,
Doctrine\Common\NotifyPropertyChanged,
Doctrine\Common\PropertyChangedListener,
Doctrine\ORM\Event\LifecycleEventArgs,
Doctrine\ORM\Mapping\ClassMetadata,
Doctrine\ORM\Proxy\Proxy;
/**
@ -388,7 +389,7 @@ class UnitOfWork implements PropertyChangedListener
* @param ClassMetadata $class The class descriptor of the entity.
* @param object $entity The entity for which to compute the changes.
*/
public function computeChangeSet(Mapping\ClassMetadata $class, $entity)
public function computeChangeSet(ClassMetadata $class, $entity)
{
if ( ! $class->isInheritanceTypeNone()) {
$class = $this->em->getClassMetadata(get_class($entity));
@ -410,7 +411,7 @@ class UnitOfWork implements PropertyChangedListener
// Inject PersistentCollection
$coll = new PersistentCollection(
$this->em,
$this->em->getClassMetadata($assoc->targetEntityName),
$this->em->getClassMetadata($assoc['targetEntity']),
$value
);
@ -431,7 +432,7 @@ class UnitOfWork implements PropertyChangedListener
foreach ($actualData as $propName => $actualValue) {
if (isset($class->associationMappings[$propName])) {
$assoc = $class->associationMappings[$propName];
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
$changeSet[$propName] = array(null, $actualValue);
}
} else {
@ -450,11 +451,11 @@ class UnitOfWork implements PropertyChangedListener
$orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
if (isset($class->associationMappings[$propName])) {
$assoc = $class->associationMappings[$propName];
if ($assoc->isOneToOne() && $orgValue !== $actualValue) {
if ($assoc->isOwningSide) {
if ($assoc['type'] & ClassMetadata::TO_ONE && $orgValue !== $actualValue) {
if ($assoc['isOwningSide']) {
$changeSet[$propName] = array($orgValue, $actualValue);
}
if ($orgValue !== null && $assoc->orphanRemoval) {
if ($orgValue !== null && $assoc['orphanRemoval']) {
$this->scheduleOrphanRemoval($orgValue);
}
} else if ($orgValue instanceof PersistentCollection && $orgValue !== $actualValue) {
@ -539,7 +540,7 @@ class UnitOfWork implements PropertyChangedListener
private function computeAssociationChanges($assoc, $value)
{
if ($value instanceof PersistentCollection && $value->isDirty()) {
if ($assoc->isOwningSide) {
if ($assoc['isOwningSide']) {
$this->collectionUpdates[] = $value;
}
$this->visitedCollections[] = $value;
@ -547,7 +548,7 @@ class UnitOfWork implements PropertyChangedListener
// Look through the entities, and in any of their associations, for transient (new)
// enities, recursively. ("Persistence by reachability")
if ($assoc->isOneToOne()) {
if ($assoc['type'] & ClassMetadata::TO_ONE) {
if ($value instanceof Proxy && ! $value->__isInitialized__) {
return; // Ignore uninitialized proxy objects
}
@ -557,12 +558,12 @@ class UnitOfWork implements PropertyChangedListener
$value = $value->unwrap();
}
$targetClass = $this->em->getClassMetadata($assoc->targetEntityName);
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
foreach ($value as $entry) {
$state = $this->getEntityState($entry, self::STATE_NEW);
$oid = spl_object_hash($entry);
if ($state == self::STATE_NEW) {
if ( ! $assoc->isCascadePersist) {
if ( ! $assoc['isCascadePersist']) {
throw new InvalidArgumentException("A new entity was found through a relationship that was not"
. " configured to cascade persist operations: " . self::objToStr($entry) . "."
. " Explicitly persist the new entity or configure cascading persist operations"
@ -833,8 +834,8 @@ class UnitOfWork implements PropertyChangedListener
// Calculate dependencies for new nodes
foreach ($newNodes as $class) {
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
$targetClass = $this->em->getClassMetadata($assoc->targetEntityName);
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
if ( ! $calc->hasClass($targetClass->name)) {
$calc->addClass($targetClass);
}
@ -1400,20 +1401,20 @@ class UnitOfWork implements PropertyChangedListener
}
} else {
$assoc2 = $class->associationMappings[$name];
if ($assoc2->isOneToOne()) {
if ($assoc2['type'] & ClassMetadata::TO_ONE) {
$other = $prop->getValue($entity);
if ($other === null) {
$prop->setValue($managedCopy, null);
} else if ($other instanceof Proxy && !$other->__isInitialized__) {
// do not merge fields marked lazy that have not been fetched.
continue;
} else if ( ! $assoc2->isCascadeMerge) {
} else if ( ! $assoc2['isCascadeMerge']) {
if ($this->getEntityState($other, self::STATE_DETACHED) == self::STATE_MANAGED) {
$prop->setValue($managedCopy, $other);
} else {
$targetClass = $this->em->getClassMetadata($assoc2->targetEntityName);
$targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
$id = $targetClass->getIdentifierValues($other);
$proxy = $this->em->getProxyFactory()->getProxy($assoc2->targetEntityName, $id);
$proxy = $this->em->getProxyFactory()->getProxy($assoc2['targetEntity'], $id);
$prop->setValue($managedCopy, $proxy);
$this->registerManaged($proxy, $id, array());
}
@ -1429,14 +1430,14 @@ class UnitOfWork implements PropertyChangedListener
$managedCol = $prop->getValue($managedCopy);
if (!$managedCol) {
$managedCol = new PersistentCollection($this->em,
$this->em->getClassMetadata($assoc2->targetEntityName),
$this->em->getClassMetadata($assoc2['targetEntity']),
new ArrayCollection
);
$managedCol->setOwner($managedCopy, $assoc2);
$prop->setValue($managedCopy, $managedCol);
$this->originalEntityData[$oid][$name] = $managedCol;
}
$managedCol->setInitialized($assoc2->isCascadeMerge);
$managedCol->setInitialized($assoc2['isCascadeMerge']);
}
}
if ($class->isChangeTrackingNotify()) {
@ -1450,14 +1451,14 @@ class UnitOfWork implements PropertyChangedListener
}
if ($prevManagedCopy !== null) {
$assocField = $assoc->sourceFieldName;
$assocField = $assoc['fieldName'];
$prevClass = $this->em->getClassMetadata(get_class($prevManagedCopy));
if ($assoc->isOneToOne()) {
if ($assoc['type'] & ClassMetadata::TO_ONE) {
$prevClass->reflFields[$assocField]->setValue($prevManagedCopy, $managedCopy);
} else {
$prevClass->reflFields[$assocField]->getValue($prevManagedCopy)->unwrap()->add($managedCopy);
if ($assoc->isOneToMany()) {
$class->reflFields[$assoc->mappedBy]->setValue($managedCopy, $prevManagedCopy);
if ($assoc['type'] == ClassMetadata::ONE_TO_MANY) {
$class->reflFields[$assoc['mappedBy']]->setValue($managedCopy, $prevManagedCopy);
}
}
}
@ -1564,10 +1565,10 @@ class UnitOfWork implements PropertyChangedListener
{
$class = $this->em->getClassMetadata(get_class($entity));
foreach ($class->associationMappings as $assoc) {
if ( ! $assoc->isCascadeRefresh) {
if ( ! $assoc['isCascadeRefresh']) {
continue;
}
$relatedEntities = $class->reflFields[$assoc->sourceFieldName]->getValue($entity);
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
if ($relatedEntities instanceof Collection) {
if ($relatedEntities instanceof PersistentCollection) {
// Unwrap so that foreach() does not initialize
@ -1592,10 +1593,10 @@ class UnitOfWork implements PropertyChangedListener
{
$class = $this->em->getClassMetadata(get_class($entity));
foreach ($class->associationMappings as $assoc) {
if ( ! $assoc->isCascadeDetach) {
if ( ! $assoc['isCascadeDetach']) {
continue;
}
$relatedEntities = $class->reflFields[$assoc->sourceFieldName]->getValue($entity);
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
if ($relatedEntities instanceof Collection) {
if ($relatedEntities instanceof PersistentCollection) {
// Unwrap so that foreach() does not initialize
@ -1621,10 +1622,10 @@ class UnitOfWork implements PropertyChangedListener
{
$class = $this->em->getClassMetadata(get_class($entity));
foreach ($class->associationMappings as $assoc) {
if ( ! $assoc->isCascadeMerge) {
if ( ! $assoc['isCascadeMerge']) {
continue;
}
$relatedEntities = $class->reflFields[$assoc->sourceFieldName]->getValue($entity);
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
if ($relatedEntities instanceof Collection) {
if ($relatedEntities instanceof PersistentCollection) {
// Unwrap so that foreach() does not initialize
@ -1650,10 +1651,10 @@ class UnitOfWork implements PropertyChangedListener
{
$class = $this->em->getClassMetadata(get_class($entity));
foreach ($class->associationMappings as $assoc) {
if ( ! $assoc->isCascadePersist) {
if ( ! $assoc['isCascadePersist']) {
continue;
}
$relatedEntities = $class->reflFields[$assoc->sourceFieldName]->getValue($entity);
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
if (($relatedEntities instanceof Collection || is_array($relatedEntities))) {
if ($relatedEntities instanceof PersistentCollection) {
// Unwrap so that foreach() does not initialize
@ -1678,11 +1679,11 @@ class UnitOfWork implements PropertyChangedListener
{
$class = $this->em->getClassMetadata(get_class($entity));
foreach ($class->associationMappings as $assoc) {
if ( ! $assoc->isCascadeRemove) {
if ( ! $assoc['isCascadeRemove']) {
continue;
}
//TODO: If $entity instanceof Proxy => Initialize ?
$relatedEntities = $class->reflFields[$assoc->sourceFieldName]->getValue($entity);
$relatedEntities = $class->reflFields[$assoc['fieldName']]->getValue($entity);
if ($relatedEntities instanceof Collection || is_array($relatedEntities)) {
// If its a PersistentCollection initialization is intended! No unwrap!
foreach ($relatedEntities as $relatedEntity) {
@ -1874,12 +1875,12 @@ class UnitOfWork implements PropertyChangedListener
continue;
}
$targetClass = $this->em->getClassMetadata($assoc->targetEntityName);
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
if ($assoc->isOneToOne()) {
if ($assoc->isOwningSide) {
if ($assoc['type'] & ClassMetadata::TO_ONE) {
if ($assoc['isOwningSide']) {
$associatedId = array();
foreach ($assoc->targetToSourceKeyColumns as $targetColumn => $srcColumn) {
foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
$joinColumnValue = $data[$srcColumn];
if ($joinColumnValue !== null) {
$associatedId[$targetClass->fieldNames[$targetColumn]] = $joinColumnValue;
@ -1900,14 +1901,15 @@ class UnitOfWork implements PropertyChangedListener
} else {
if ($targetClass->subClasses) {
// If it might be a subtype, it can not be lazy
$newValue = $assoc->load($entity, null, $this->em, $associatedId);
$newValue = $this->getEntityPersister($assoc['targetEntity'])
->loadOneToOneEntity($assoc, $entity, null, $associatedId);
} else {
if ($assoc->fetchMode == Mapping\AssociationMapping::FETCH_EAGER) {
if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
// TODO: Maybe it could be optimized to do an eager fetch with a JOIN inside
// the persister instead of this rather unperformant approach.
$newValue = $this->em->find($assoc->targetEntityName, $associatedId);
$newValue = $this->em->find($assoc['targetEntity'], $associatedId);
} else {
$newValue = $this->em->getProxyFactory()->getProxy($assoc->targetEntityName, $associatedId);
$newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
}
// PERF: Inlined & optimized code from UnitOfWork#registerManaged()
$newValueOid = spl_object_hash($newValue);
@ -1922,7 +1924,8 @@ class UnitOfWork implements PropertyChangedListener
}
} else {
// Inverse side of x-to-one can never be lazy
$class->reflFields[$field]->setValue($entity, $assoc->load($entity, null, $this->em));
$class->reflFields[$field]->setValue($entity, $this->getEntityPersister($assoc['targetEntity'])
->loadOneToOneEntity($assoc, $entity, null));
}
} else {
// Inject collection
@ -1934,10 +1937,10 @@ class UnitOfWork implements PropertyChangedListener
);
$pColl->setOwner($entity, $assoc);
$reflField->setValue($entity, $pColl);
if ($assoc->isLazilyFetched()) {
if ($assoc['fetch'] == ClassMetadata::FETCH_LAZY) {
$pColl->setInitialized(false);
} else {
$assoc->load($entity, $pColl, $this->em);
$this->loadCollection($pColl);
}
$this->originalEntityData[$oid][$field] = $pColl;
}
@ -1956,6 +1959,27 @@ class UnitOfWork implements PropertyChangedListener
return $entity;
}
/**
* Initializes (loads) an uninitialized persistent collection of an entity.
*
* @param PeristentCollection $collection The collection to initialize.
* @todo Maybe later move to EntityManager#initialize($proxyOrCollection). See DDC-733.
*/
public function loadCollection(PersistentCollection $collection)
{
$assoc = $collection->getMapping();
switch ($assoc['type']) {
case ClassMetadata::ONE_TO_MANY:
$this->getEntityPersister($assoc['targetEntity'])->loadOneToManyCollection(
$assoc, $collection->getOwner(), $collection);
break;
case ClassMetadata::MANY_TO_MANY:
$this->getEntityPersister($assoc['targetEntity'])->loadManyToManyCollection(
$assoc, $collection->getOwner(), $collection);
break;
}
}
/**
* Gets the identity map of the UnitOfWork.
*
@ -2103,13 +2127,13 @@ class UnitOfWork implements PropertyChangedListener
* @param AssociationMapping $association
* @return AbstractCollectionPersister
*/
public function getCollectionPersister($association)
public function getCollectionPersister(array $association)
{
$type = get_class($association);
$type = $association['type'];
if ( ! isset($this->collectionPersisters[$type])) {
if ($association instanceof Mapping\OneToManyMapping) {
if ($type == ClassMetadata::ONE_TO_MANY) {
$persister = new Persisters\OneToManyPersister($this->em);
} else if ($association instanceof Mapping\ManyToManyMapping) {
} else if ($type == ClassMetadata::MANY_TO_MANY) {
$persister = new Persisters\ManyToManyPersister($this->em);
}
$this->collectionPersisters[$type] = $persister;

View File

@ -26,7 +26,6 @@ class AllTests
$suite->addTest(Query\AllTests::suite());
$suite->addTest(Hydration\AllTests::suite());
$suite->addTest(Entity\AllTests::suite());
$suite->addTest(Associations\AllTests::suite());
$suite->addTest(Mapping\AllTests::suite());
$suite->addTest(Functional\AllTests::suite());
$suite->addTest(Id\AllTests::suite());

View File

@ -1,30 +0,0 @@
<?php
namespace Doctrine\Tests\ORM\Associations;
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'Orm_Associations_AllTests::main');
}
require_once __DIR__ . '/../../TestInit.php';
class AllTests
{
public static function main()
{
\PHPUnit_TextUI_TestRunner::run(self::suite());
}
public static function suite()
{
$suite = new \Doctrine\Tests\DoctrineTestSuite('Doctrine Orm Associations');
$suite->addTestSuite('Doctrine\Tests\ORM\Associations\OneToOneMappingTest');
return $suite;
}
}
if (PHPUnit_MAIN_METHOD == 'Orm_Associations_AllTests::main') {
AllTests::main();
}

View File

@ -1,40 +0,0 @@
<?php
namespace Doctrine\Tests\ORM\Associations;
require_once __DIR__ . '/../../TestInit.php';
class OneToOneMappingTest extends \Doctrine\Tests\OrmTestCase
{
public function testCorrectOneToOneBidirectionalMapping()
{
$owningSideMapping = array(
'fieldName' => 'address',
'targetEntity' => 'Address',
'joinColumns' => array(array('name' => 'address_id', 'referencedColumnName' => 'id')),
'sourceEntity' => 'Person', // This is normally filled by ClassMetadata
);
$oneToOneMapping = new \Doctrine\ORM\Mapping\OneToOneMapping($owningSideMapping);
$this->assertEquals(array('address_id' => 'id'), $oneToOneMapping->sourceToTargetKeyColumns);
$this->assertEquals(array('id' => 'address_id'), $oneToOneMapping->targetToSourceKeyColumns);
$this->assertEquals('Address', $oneToOneMapping->targetEntityName);
$this->assertEquals('Person', $oneToOneMapping->sourceEntityName);
$this->assertEquals('address', $oneToOneMapping->sourceFieldName);
$this->assertTrue($oneToOneMapping->isOwningSide);
$inverseSideMapping = array(
'fieldName' => 'person',
'sourceEntity' => 'Address',
'targetEntity' => 'Person',
'mappedBy' => 'address'
);
$oneToOneMapping = new \Doctrine\ORM\Mapping\OneToOneMapping($inverseSideMapping);
$this->assertEquals('address', $oneToOneMapping->mappedBy);
$this->assertEquals('Address', $oneToOneMapping->sourceEntityName);
$this->assertEquals('Person', $oneToOneMapping->targetEntityName);
$this->assertTrue( ! $oneToOneMapping->isOwningSide);
}
}

View File

@ -105,6 +105,7 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
public function testBasicOneToOne()
{
//$this->_em->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger);
$user = new CmsUser;
$user->name = 'Roman';
$user->username = 'romanb';

View File

@ -84,7 +84,7 @@ class DatabaseDriverTest extends \Doctrine\Tests\OrmFunctionalTestCase
$bazMetadata->associationMappings = \array_change_key_case($bazMetadata->associationMappings, \CASE_LOWER);
$this->assertArrayHasKey('bar', $bazMetadata->associationMappings);
$this->assertType('Doctrine\ORM\Mapping\OneToOneMapping', $bazMetadata->associationMappings['bar']);
$this->assertEquals(ClassMetadataInfo::MANY_TO_ONE, $bazMetadata->associationMappings['bar']['type']);
}
public function testDetectManyToManyTables()

View File

@ -4,6 +4,7 @@ namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\ECommerce\ECommerceProduct;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Mapping\ClassMetadata;
require_once __DIR__ . '/../../TestInit.php';
@ -74,7 +75,7 @@ class ManyToManySelfReferentialAssociationTest extends AbstractManyToManyAssocia
$this->_createLoadingFixture();
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct');
$metadata->getAssociationMapping('related')->fetchMode = AssociationMapping::FETCH_LAZY;
$metadata->associationMappings['related']['fetch'] = ClassMetadata::FETCH_LAZY;
$query = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p');
$products = $query->getResult();

View File

@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\ECommerce\ECommerceCart;
use Doctrine\Tests\Models\ECommerce\ECommerceProduct;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Mapping\ClassMetadata;
require_once __DIR__ . '/../../TestInit.php';
@ -79,7 +80,7 @@ class ManyToManyUnidirectionalAssociationTest extends AbstractManyToManyAssociat
{
$this->_createFixture();
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCart');
$metadata->getAssociationMapping('products')->fetchMode = AssociationMapping::FETCH_LAZY;
$metadata->associationMappings['products']['fetch'] = ClassMetadata::FETCH_LAZY;
$query = $this->_em->createQuery('SELECT c FROM Doctrine\Tests\Models\ECommerce\ECommerceCart c');
$result = $query->getResult();

View File

@ -4,6 +4,7 @@ namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\ECommerce\ECommerceCategory;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Mapping\ClassMetadata;
require_once __DIR__ . '/../../TestInit.php';
@ -90,7 +91,7 @@ class OneToManySelfReferentialAssociationTest extends \Doctrine\Tests\OrmFunctio
{
$this->_createFixture();
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCategory');
$metadata->getAssociationMapping('children')->fetchMode = AssociationMapping::FETCH_LAZY;
$metadata->associationMappings['children']['fetch'] = ClassMetadata::FETCH_LAZY;
$query = $this->_em->createQuery('select c from Doctrine\Tests\Models\ECommerce\ECommerceCategory c order by c.id asc');
$result = $query->getResult();

View File

@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\ECommerce\ECommerceCart;
use Doctrine\Tests\Models\ECommerce\ECommerceCustomer;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Mapping\ClassMetadata;
require_once __DIR__ . '/../../TestInit.php';
@ -68,7 +69,7 @@ class OneToOneBidirectionalAssociationTest extends \Doctrine\Tests\OrmFunctional
public function testLazyLoadsObjectsOnTheOwningSide() {
$this->_createFixture();
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCart');
$metadata->getAssociationMapping('customer')->fetchMode = AssociationMapping::FETCH_LAZY;
$metadata->associationMappings['customer']['fetchMode'] = ClassMetadata::FETCH_LAZY;
$query = $this->_em->createQuery('select c from Doctrine\Tests\Models\ECommerce\ECommerceCart c');
$result = $query->getResult();
@ -82,7 +83,7 @@ class OneToOneBidirectionalAssociationTest extends \Doctrine\Tests\OrmFunctional
{
$this->_createFixture();
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCustomer');
$metadata->getAssociationMapping('mentor')->fetchMode = AssociationMapping::FETCH_EAGER;
$metadata->associationMappings['mentor']['fetch'] = ClassMetadata::FETCH_EAGER;
$query = $this->_em->createQuery('select c from Doctrine\Tests\Models\ECommerce\ECommerceCustomer c');
$result = $query->getResult();

View File

@ -4,6 +4,7 @@ namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\ECommerce\ECommerceCustomer;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Mapping\ClassMetadata;
require_once __DIR__ . '/../../TestInit.php';
@ -67,7 +68,7 @@ class OneToOneSelfReferentialAssociationTest extends \Doctrine\Tests\OrmFunction
$this->_createFixture();
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceCustomer');
$metadata->getAssociationMapping('mentor')->fetchMode = AssociationMapping::FETCH_LAZY;
$metadata->associationMappings['mentor']['fetch'] = ClassMetadata::FETCH_LAZY;
$query = $this->_em->createQuery("select c from Doctrine\Tests\Models\ECommerce\ECommerceCustomer c where c.name='Luke Skywalker'");
$result = $query->getResult();

View File

@ -5,6 +5,7 @@ namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Tests\Models\ECommerce\ECommerceProduct;
use Doctrine\Tests\Models\ECommerce\ECommerceShipping;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query;
require_once __DIR__ . '/../../TestInit.php';
@ -62,7 +63,7 @@ class OneToOneUnidirectionalAssociationTest extends \Doctrine\Tests\OrmFunctiona
public function testLazyLoadsObjects() {
$this->_createFixture();
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct');
$metadata->getAssociationMapping('shipping')->fetchMode = AssociationMapping::FETCH_LAZY;
$metadata->associationMappings['shipping']['fetch'] = ClassMetadata::FETCH_LAZY;
$query = $this->_em->createQuery('select p from Doctrine\Tests\Models\ECommerce\ECommerceProduct p');
$result = $query->getResult();

View File

@ -66,7 +66,7 @@ class DDC599Test extends \Doctrine\Tests\OrmFunctionalTestCase
$class = $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC599Subitem');
$this->assertArrayHasKey('children', $class->associationMappings);
$this->assertTrue($class->associationMappings['children']->isCascadeRemove);
$this->assertTrue($class->associationMappings['children']['isCascadeRemove']);
}
}

View File

@ -6,6 +6,7 @@ use Doctrine\Tests\Mocks\HydratorMockStatement;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Proxy\ProxyFactory;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query;
use Doctrine\Tests\Models\CMS\CmsUser;
@ -164,7 +165,7 @@ class ObjectHydratorTest extends HydrationTestCase
// configuring lazy loading
$metadata = $this->_em->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct');
$metadata->getAssociationMapping('shipping')->fetchMode = AssociationMapping::FETCH_LAZY;
$metadata->associationMappings['shipping']['fetch'] = ClassMetadata::FETCH_LAZY;
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);

View File

@ -155,16 +155,15 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
*/
public function testOwningOneToOneAssocation($class)
{
$this->assertTrue($class->associationMappings['address'] instanceof \Doctrine\ORM\Mapping\OneToOneMapping);
$this->assertTrue(isset($class->associationMappings['address']));
$this->assertTrue($class->associationMappings['address']->isOwningSide);
$this->assertEquals('user', $class->associationMappings['address']->inversedBy);
$this->assertTrue($class->associationMappings['address']['isOwningSide']);
$this->assertEquals('user', $class->associationMappings['address']['inversedBy']);
// Check cascading
$this->assertTrue($class->associationMappings['address']->isCascadeRemove);
$this->assertFalse($class->associationMappings['address']->isCascadePersist);
$this->assertFalse($class->associationMappings['address']->isCascadeRefresh);
$this->assertFalse($class->associationMappings['address']->isCascadeDetach);
$this->assertFalse($class->associationMappings['address']->isCascadeMerge);
$this->assertTrue($class->associationMappings['address']['isCascadeRemove']);
$this->assertFalse($class->associationMappings['address']['isCascadePersist']);
$this->assertFalse($class->associationMappings['address']['isCascadeRefresh']);
$this->assertFalse($class->associationMappings['address']['isCascadeDetach']);
$this->assertFalse($class->associationMappings['address']['isCascadeMerge']);
return $class;
}
@ -175,17 +174,16 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
*/
public function testInverseOneToManyAssociation($class)
{
$this->assertTrue($class->associationMappings['phonenumbers'] instanceof \Doctrine\ORM\Mapping\OneToManyMapping);
$this->assertTrue(isset($class->associationMappings['phonenumbers']));
$this->assertFalse($class->associationMappings['phonenumbers']->isOwningSide);
$this->assertTrue($class->associationMappings['phonenumbers']->isCascadePersist);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeRemove);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeRefresh);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeDetach);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeMerge);
$this->assertFalse($class->associationMappings['phonenumbers']['isOwningSide']);
$this->assertTrue($class->associationMappings['phonenumbers']['isCascadePersist']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRemove']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRefresh']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeDetach']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeMerge']);
// Test Order By
$this->assertEquals(array('number' => 'ASC'), $class->associationMappings['phonenumbers']->orderBy);
$this->assertEquals(array('number' => 'ASC'), $class->associationMappings['phonenumbers']['orderBy']);
return $class;
}
@ -196,17 +194,16 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
*/
public function testManyToManyAssociationWithCascadeAll($class)
{
$this->assertTrue($class->associationMappings['groups'] instanceof \Doctrine\ORM\Mapping\ManyToManyMapping);
$this->assertTrue(isset($class->associationMappings['groups']));
$this->assertTrue($class->associationMappings['groups']->isOwningSide);
$this->assertTrue($class->associationMappings['groups']['isOwningSide']);
// Make sure that cascade-all works as expected
$this->assertTrue($class->associationMappings['groups']->isCascadeRemove);
$this->assertTrue($class->associationMappings['groups']->isCascadePersist);
$this->assertTrue($class->associationMappings['groups']->isCascadeRefresh);
$this->assertTrue($class->associationMappings['groups']->isCascadeDetach);
$this->assertTrue($class->associationMappings['groups']->isCascadeMerge);
$this->assertTrue($class->associationMappings['groups']['isCascadeRemove']);
$this->assertTrue($class->associationMappings['groups']['isCascadePersist']);
$this->assertTrue($class->associationMappings['groups']['isCascadeRefresh']);
$this->assertTrue($class->associationMappings['groups']['isCascadeDetach']);
$this->assertTrue($class->associationMappings['groups']['isCascadeMerge']);
$this->assertNull($class->associationMappings['groups']->orderBy);
$this->assertFalse(isset($class->associationMappings['groups']['orderBy']));
return $class;
}
@ -243,8 +240,8 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
public function testJoinColumnUniqueAndNullable($class)
{
// Non-Nullability of Join Column
$this->assertFalse($class->associationMappings['groups']->joinTable['joinColumns'][0]['nullable']);
$this->assertFalse($class->associationMappings['groups']->joinTable['joinColumns'][0]['unique']);
$this->assertFalse($class->associationMappings['groups']['joinTable']['joinColumns'][0]['nullable']);
$this->assertFalse($class->associationMappings['groups']['joinTable']['joinColumns'][0]['unique']);
return $class;
}
@ -256,7 +253,7 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
public function testColumnDefinition($class)
{
$this->assertEquals("CHAR(32) NOT NULL", $class->fieldMappings['email']['columnDefinition']);
$this->assertEquals("INT NULL", $class->associationMappings['groups']->joinTable['inverseJoinColumns'][0]['columnDefinition']);
$this->assertEquals("INT NULL", $class->associationMappings['groups']['joinTable']['inverseJoinColumns'][0]['columnDefinition']);
return $class;
}
@ -267,8 +264,8 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase
*/
public function testJoinColumnOnDeleteAndOnUpdate($class)
{
$this->assertEquals('CASCADE', $class->associationMappings['address']->joinColumns[0]['onDelete']);
$this->assertEquals('CASCADE', $class->associationMappings['address']->joinColumns[0]['onUpdate']);
$this->assertEquals('CASCADE', $class->associationMappings['address']['joinColumns'][0]['onDelete']);
$this->assertEquals('CASCADE', $class->associationMappings['address']['joinColumns'][0]['onUpdate']);
return $class;
}

View File

@ -29,7 +29,6 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$cm->setCustomRepositoryClass("UserRepository");
$cm->setDiscriminatorColumn(array('name' => 'disc', 'type' => 'integer'));
$cm->mapOneToOne(array('fieldName' => 'phonenumbers', 'targetEntity' => 'Bar', 'mappedBy' => 'foo'));
$this->assertTrue($cm->getAssociationMapping('phonenumbers') instanceof \Doctrine\ORM\Mapping\OneToOneMapping);
$this->assertEquals(1, count($cm->associationMappings));
$serialized = serialize($cm);
@ -45,12 +44,12 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals(array('UserParent'), $cm->parentClasses);
$this->assertEquals('UserRepository', $cm->customRepositoryClassName);
$this->assertEquals(array('name' => 'disc', 'type' => 'integer', 'fieldName' => 'disc'), $cm->discriminatorColumn);
$this->assertTrue($cm->getAssociationMapping('phonenumbers') instanceof \Doctrine\ORM\Mapping\OneToOneMapping);
$this->assertTrue($cm->associationMappings['phonenumbers']['type'] == ClassMetadata::ONE_TO_ONE);
$this->assertEquals(1, count($cm->associationMappings));
$oneOneMapping = $cm->getAssociationMapping('phonenumbers');
$this->assertTrue($oneOneMapping->fetchMode == \Doctrine\ORM\Mapping\AssociationMapping::FETCH_LAZY);
$this->assertEquals('phonenumbers', $oneOneMapping->sourceFieldName);
$this->assertEquals('Doctrine\Tests\Models\CMS\Bar', $oneOneMapping->targetEntityName);
$this->assertTrue($oneOneMapping['fetch'] == ClassMetadata::FETCH_LAZY);
$this->assertEquals('phonenumbers', $oneOneMapping['fieldName']);
$this->assertEquals('Doctrine\Tests\Models\CMS\Bar', $oneOneMapping['targetEntity']);
}
public function testFieldIsNullable()
@ -88,7 +87,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
),
));
$this->assertEquals("DoctrineGlobal_User", $cm->associationMappings['author']->targetEntityName);
$this->assertEquals("DoctrineGlobal_User", $cm->associationMappings['author']['targetEntity']);
}
public function testMapManyToManyJoinTableDefaults()
@ -101,13 +100,13 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
));
$assoc = $cm->associationMappings['groups'];
$this->assertTrue($assoc instanceof \Doctrine\ORM\Mapping\ManyToManyMapping);
//$this->assertTrue($assoc instanceof \Doctrine\ORM\Mapping\ManyToManyMapping);
$this->assertEquals(array(
'name' => 'CmsUser_CmsGroup',
'joinColumns' => array(array('name' => 'CmsUser_id', 'referencedColumnName' => 'id', 'onDelete' => 'CASCADE')),
'inverseJoinColumns' => array(array('name' => 'CmsGroup_id', 'referencedColumnName' => 'id', 'onDelete' => 'CASCADE'))
), $assoc->joinTable);
$this->assertTrue($assoc->isOnDeleteCascade);
), $assoc['joinTable']);
$this->assertTrue($assoc['isOnDeleteCascade']);
}
public function testSerializeManyToManyJoinTableCascade()
@ -123,7 +122,7 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$assoc = $cm->associationMappings['groups'];
$assoc = unserialize(serialize($assoc));
$this->assertTrue($assoc->isOnDeleteCascade);
$this->assertTrue($assoc['isOnDeleteCascade']);
}
/**
@ -180,8 +179,8 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
public function testDuplicateAssociationMappingException()
{
$cm = new ClassMetadata('Doctrine\Tests\Models\CMS\CmsUser');
$a1 = new \Doctrine\ORM\Mapping\OneToOneMapping(array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'mappedBy' => 'foo'));
$a2 = new \Doctrine\ORM\Mapping\OneToOneMapping(array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'mappedBy' => 'foo'));
$a1 = array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'mappedBy' => 'foo');
$a2 = array('fieldName' => 'foo', 'sourceEntity' => 'stdClass', 'targetEntity' => 'stdClass', 'mappedBy' => 'foo');
$cm->addInheritedAssociationMapping($a1);
$this->setExpectedException('Doctrine\ORM\Mapping\MappingException');

View File

@ -32,22 +32,6 @@ class PersistentCollectionTest extends \Doctrine\Tests\OrmTestCase
$class = $this->_emMock->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct');
$collection = new PersistentCollection($this->_emMock, $class, new ArrayCollection);
$collection->setInitialized(false);
}
public function testQueriesAssociationToLoadItself()
{
$class = $this->_emMock->getClassMetadata('Doctrine\Tests\Models\ECommerce\ECommerceProduct');
$collection = new PersistentCollection($this->_emMock, $class, new ArrayCollection);
$collection->setInitialized(false);
$association = $this->getMock('Doctrine\ORM\Mapping\OneToManyMapping', array('load'), array(), '', false, false, false);
$association->targetEntityName = 'Doctrine\Tests\Models\ECommerce\ECommerceFeature';
$product = new ECommerceProduct();
$association->expects($this->once())
->method('load')
->with($product, $this->isInstanceOf($collection), $this->isInstanceOf($this->_emMock));
$collection->setOwner($product, $association);
count($collection);
$this->assertFalse($collection->isInitialized());
}
}

View File

@ -91,8 +91,8 @@ class ConvertDoctrine1SchemaTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals('test_alias', $userClass->fieldMappings['theAlias']['columnName']);
$this->assertEquals('theAlias', $userClass->fieldMappings['theAlias']['fieldName']);
$this->assertEquals('Profile', $profileClass->associationMappings['User']->sourceEntityName);
$this->assertEquals('User', $profileClass->associationMappings['User']->targetEntityName);
$this->assertEquals('Profile', $profileClass->associationMappings['User']['sourceEntity']);
$this->assertEquals('User', $profileClass->associationMappings['User']['targetEntity']);
$this->assertEquals('username', $userClass->table['uniqueConstraints']['username']['columns'][0]);

View File

@ -210,18 +210,18 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
public function testOneToOneAssociationsAreExported($class)
{
$this->assertTrue(isset($class->associationMappings['address']));
$this->assertTrue($class->associationMappings['address'] instanceof \Doctrine\ORM\Mapping\OneToOneMapping);
$this->assertEquals('Doctrine\Tests\ORM\Tools\Export\Address', $class->associationMappings['address']->targetEntityName);
$this->assertEquals('address_id', $class->associationMappings['address']->joinColumns[0]['name']);
$this->assertEquals('id', $class->associationMappings['address']->joinColumns[0]['referencedColumnName']);
$this->assertEquals('CASCADE', $class->associationMappings['address']->joinColumns[0]['onDelete']);
$this->assertEquals('CASCADE', $class->associationMappings['address']->joinColumns[0]['onUpdate']);
//$this->assertTrue($class->associationMappings['address'] instanceof \Doctrine\ORM\Mapping\OneToOneMapping);
$this->assertEquals('Doctrine\Tests\ORM\Tools\Export\Address', $class->associationMappings['address']['targetEntity']);
$this->assertEquals('address_id', $class->associationMappings['address']['joinColumns'][0]['name']);
$this->assertEquals('id', $class->associationMappings['address']['joinColumns'][0]['referencedColumnName']);
$this->assertEquals('CASCADE', $class->associationMappings['address']['joinColumns'][0]['onDelete']);
$this->assertEquals('CASCADE', $class->associationMappings['address']['joinColumns'][0]['onUpdate']);
$this->assertTrue($class->associationMappings['address']->isCascadeRemove);
$this->assertFalse($class->associationMappings['address']->isCascadePersist);
$this->assertFalse($class->associationMappings['address']->isCascadeRefresh);
$this->assertFalse($class->associationMappings['address']->isCascadeMerge);
$this->assertFalse($class->associationMappings['address']->isCascadeDetach);
$this->assertTrue($class->associationMappings['address']['isCascadeRemove']);
$this->assertFalse($class->associationMappings['address']['isCascadePersist']);
$this->assertFalse($class->associationMappings['address']['isCascadeRefresh']);
$this->assertFalse($class->associationMappings['address']['isCascadeMerge']);
$this->assertFalse($class->associationMappings['address']['isCascadeDetach']);
return $class;
}
@ -233,16 +233,16 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
public function testOneToManyAssociationsAreExported($class)
{
$this->assertTrue(isset($class->associationMappings['phonenumbers']));
$this->assertTrue($class->associationMappings['phonenumbers'] instanceof \Doctrine\ORM\Mapping\OneToManyMapping);
$this->assertEquals('Doctrine\Tests\ORM\Tools\Export\Phonenumber', $class->associationMappings['phonenumbers']->targetEntityName);
$this->assertEquals('user', $class->associationMappings['phonenumbers']->mappedBy);
$this->assertEquals(array('number' => 'ASC'), $class->associationMappings['phonenumbers']->orderBy);
//$this->assertTrue($class->associationMappings['phonenumbers'] instanceof \Doctrine\ORM\Mapping\OneToManyMapping);
$this->assertEquals('Doctrine\Tests\ORM\Tools\Export\Phonenumber', $class->associationMappings['phonenumbers']['targetEntity']);
$this->assertEquals('user', $class->associationMappings['phonenumbers']['mappedBy']);
$this->assertEquals(array('number' => 'ASC'), $class->associationMappings['phonenumbers']['orderBy']);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeRemove);
$this->assertTrue($class->associationMappings['phonenumbers']->isCascadePersist);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeRefresh);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeMerge);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeDetach);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRemove']);
$this->assertTrue($class->associationMappings['phonenumbers']['isCascadePersist']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRefresh']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeMerge']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeDetach']);
return $class;
}
@ -254,22 +254,22 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
public function testManyToManyAssociationsAreExported($class)
{
$this->assertTrue(isset($class->associationMappings['groups']));
$this->assertTrue($class->associationMappings['groups'] instanceof \Doctrine\ORM\Mapping\ManyToManyMapping);
$this->assertEquals('Doctrine\Tests\ORM\Tools\Export\Group', $class->associationMappings['groups']->targetEntityName);
$this->assertEquals('cms_users_groups', $class->associationMappings['groups']->joinTable['name']);
//$this->assertTrue($class->associationMappings['groups'] instanceof \Doctrine\ORM\Mapping\ManyToManyMapping);
$this->assertEquals('Doctrine\Tests\ORM\Tools\Export\Group', $class->associationMappings['groups']['targetEntity']);
$this->assertEquals('cms_users_groups', $class->associationMappings['groups']['joinTable']['name']);
$this->assertEquals('user_id', $class->associationMappings['groups']->joinTable['joinColumns'][0]['name']);
$this->assertEquals('id', $class->associationMappings['groups']->joinTable['joinColumns'][0]['referencedColumnName']);
$this->assertEquals('user_id', $class->associationMappings['groups']['joinTable']['joinColumns'][0]['name']);
$this->assertEquals('id', $class->associationMappings['groups']['joinTable']['joinColumns'][0]['referencedColumnName']);
$this->assertEquals('group_id', $class->associationMappings['groups']->joinTable['inverseJoinColumns'][0]['name']);
$this->assertEquals('id', $class->associationMappings['groups']->joinTable['inverseJoinColumns'][0]['referencedColumnName']);
$this->assertEquals('INT NULL', $class->associationMappings['groups']->joinTable['inverseJoinColumns'][0]['columnDefinition']);
$this->assertEquals('group_id', $class->associationMappings['groups']['joinTable']['inverseJoinColumns'][0]['name']);
$this->assertEquals('id', $class->associationMappings['groups']['joinTable']['inverseJoinColumns'][0]['referencedColumnName']);
$this->assertEquals('INT NULL', $class->associationMappings['groups']['joinTable']['inverseJoinColumns'][0]['columnDefinition']);
$this->assertTrue($class->associationMappings['groups']->isCascadeRemove);
$this->assertTrue($class->associationMappings['groups']->isCascadePersist);
$this->assertTrue($class->associationMappings['groups']->isCascadeRefresh);
$this->assertTrue($class->associationMappings['groups']->isCascadeMerge);
$this->assertTrue($class->associationMappings['groups']->isCascadeDetach);
$this->assertTrue($class->associationMappings['groups']['isCascadeRemove']);
$this->assertTrue($class->associationMappings['groups']['isCascadePersist']);
$this->assertTrue($class->associationMappings['groups']['isCascadeRefresh']);
$this->assertTrue($class->associationMappings['groups']['isCascadeMerge']);
$this->assertTrue($class->associationMappings['groups']['isCascadeDetach']);
return $class;
}
@ -298,10 +298,10 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
*/
public function testCascadeIsExported($class)
{
$this->assertTrue($class->associationMappings['phonenumbers']->isCascadePersist);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeMerge);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeRemove);
$this->assertFalse($class->associationMappings['phonenumbers']->isCascadeRefresh);
$this->assertTrue($class->associationMappings['phonenumbers']['isCascadePersist']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeMerge']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRemove']);
$this->assertFalse($class->associationMappings['phonenumbers']['isCascadeRefresh']);
return $class;
}
@ -312,7 +312,7 @@ abstract class AbstractClassMetadataExporterTest extends \Doctrine\Tests\OrmTest
*/
public function testInversedByIsExported($class)
{
$this->assertEquals('user', $class->associationMappings['address']->inversedBy);
$this->assertEquals('user', $class->associationMappings['address']['inversedBy']);
}
public function __destruct()