Merge branch 'DDC-626'
This commit is contained in:
commit
139f8b52ab
@ -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])) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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'])) {
|
||||
|
@ -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'])) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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'];
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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(
|
||||
|
@ -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."
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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'];
|
||||
|
||||
|
@ -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 . '",';
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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'];
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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';
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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');
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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]);
|
||||
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user