[2.0][DDC-279] Fixed.
This commit is contained in:
parent
1ad982a4fe
commit
94d41dfbdc
@ -124,9 +124,9 @@ class EntityManager
|
||||
private $_hydrators = array();
|
||||
|
||||
/**
|
||||
* The proxy factory which creates association or reference proxies.
|
||||
* The proxy factory used to create dynamic proxies.
|
||||
*
|
||||
* @var ProxyFactory
|
||||
* @var Doctrine\ORM\Proxy\ProxyFactory
|
||||
*/
|
||||
private $_proxyFactory;
|
||||
|
||||
|
@ -4,7 +4,7 @@ namespace Doctrine\ORM\Event;
|
||||
|
||||
class LifecycleEventArgs extends \Doctrine\Common\EventArgs
|
||||
{
|
||||
private $_em;
|
||||
//private $_em;
|
||||
private $_entity;
|
||||
|
||||
public function __construct($entity)
|
||||
@ -17,8 +17,10 @@ class LifecycleEventArgs extends \Doctrine\Common\EventArgs
|
||||
return $this->_entity;
|
||||
}
|
||||
|
||||
/*
|
||||
public function getEntityManager()
|
||||
{
|
||||
return $this->_em;
|
||||
}
|
||||
*/
|
||||
}
|
@ -62,7 +62,6 @@ class ObjectHydrator extends AbstractHydrator
|
||||
|
||||
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
|
||||
$this->_identifierMap[$dqlAlias] = array();
|
||||
//$this->_resultPointers[$dqlAlias] = array();
|
||||
$this->_idTemplate[$dqlAlias] = '';
|
||||
$class = $this->_em->getClassMetadata($className);
|
||||
|
||||
@ -73,16 +72,26 @@ class ObjectHydrator extends AbstractHydrator
|
||||
// Remember which associations are "fetch joined", so that we know where to inject
|
||||
// collection stubs or proxies and where not.
|
||||
if (isset($this->_rsm->relationMap[$dqlAlias])) {
|
||||
$targetClassName = $this->_rsm->aliasMap[$this->_rsm->parentAliasMap[$dqlAlias]];
|
||||
$targetClass = $this->_getClassMetadata($targetClassName);
|
||||
$assoc = $targetClass->associationMappings[$this->_rsm->relationMap[$dqlAlias]];
|
||||
$this->_hints['fetched'][$assoc->sourceEntityName][$assoc->sourceFieldName] = true;
|
||||
$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;
|
||||
if ($sourceClass->subClasses) {
|
||||
foreach ($sourceClass->subClasses as $sourceSubclassName) {
|
||||
$this->_hints['fetched'][$sourceSubclassName][$assoc->sourceFieldName] = true;
|
||||
}
|
||||
}
|
||||
if ($assoc->mappedByFieldName) {
|
||||
$this->_hints['fetched'][$assoc->targetEntityName][$assoc->mappedByFieldName] = true;
|
||||
$this->_hints['fetched'][$className][$assoc->mappedByFieldName] = true;
|
||||
} else {
|
||||
if (isset($targetClass->inverseMappings[$className][$assoc->sourceFieldName])) {
|
||||
$inverseAssoc = $targetClass->inverseMappings[$className][$assoc->sourceFieldName];
|
||||
$this->_hints['fetched'][$assoc->targetEntityName][$inverseAssoc->sourceFieldName] = true;
|
||||
if (isset($sourceClass->inverseMappings[$className][$assoc->sourceFieldName])) {
|
||||
$inverseAssoc = $sourceClass->inverseMappings[$className][$assoc->sourceFieldName];
|
||||
$this->_hints['fetched'][$className][$inverseAssoc->sourceFieldName] = true;
|
||||
if ($class->subClasses) {
|
||||
foreach ($class->subClasses as $targetSubclassName) {
|
||||
$this->_hints['fetched'][$targetSubclassName][$inverseAssoc->sourceFieldName] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -383,8 +383,9 @@ class AnnotationDriver implements Driver
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the class with the specified name should have its metadata loaded.
|
||||
* This is only the case if it is annotated with either @Entity or
|
||||
* Whether the class with the specified name is transient. Only non-transient
|
||||
* classes, that is entities and mapped superclasses, should have their metadata loaded.
|
||||
* A class is non-transient if it is annotated with either @Entity or
|
||||
* @MappedSuperclass in the class doc block.
|
||||
*
|
||||
* @param string $className
|
||||
|
@ -121,4 +121,10 @@ class MappingException extends \Doctrine\ORM\ORMException
|
||||
{
|
||||
return new self('An error occurred in ' . $entity, 0, $previousException);
|
||||
}
|
||||
|
||||
public static function joinColumnMustPointToMappedField($className, $joinColumn)
|
||||
{
|
||||
return new self('The column ' . $joinColumn . ' must be mapped to a field in class '
|
||||
. $className . ' since it is referenced by a join column of another class.');
|
||||
}
|
||||
}
|
@ -76,7 +76,7 @@ class OneToManyMapping extends AssociationMapping
|
||||
{
|
||||
parent::_validateAndCompleteMapping($mapping);
|
||||
|
||||
// one-side MUST be inverse (must have mappedBy)
|
||||
// OneToMany-side MUST be inverse (must have mappedBy)
|
||||
if ( ! isset($mapping['mappedBy'])) {
|
||||
throw MappingException::oneToManyRequiresMappedBy($mapping['fieldName']);
|
||||
}
|
||||
|
@ -221,9 +221,16 @@ class OneToOneMapping extends AssociationMapping
|
||||
$targetClass->inverseMappings[$this->sourceEntityName][$this->sourceFieldName]->sourceFieldName
|
||||
: false;
|
||||
|
||||
// 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 ($inverseField) {
|
||||
$hints['fetched'][$targetClass->rootEntityName][$inverseField] = true;
|
||||
$hints['fetched'][$targetClass->name][$inverseField] = true;
|
||||
if ($targetClass->subClasses) {
|
||||
foreach ($targetClass->subClasses as $targetSubclassName) {
|
||||
$hints['fetched'][$targetSubclassName][$inverseField] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* cascade read-only status
|
||||
if ($em->getUnitOfWork()->isReadOnly($sourceEntity)) {
|
||||
@ -233,7 +240,7 @@ class OneToOneMapping extends AssociationMapping
|
||||
|
||||
$targetEntity = $em->getUnitOfWork()->getEntityPersister($this->targetEntityName)->load($joinColumnValues, $targetEntity, $this, $hints);
|
||||
|
||||
if ($targetEntity !== null && $inverseField && ! $targetClass->isCollectionValuedAssociation($inverseField)) {
|
||||
if ($targetEntity !== null && $inverseField && ! $targetClass->isCollectionValuedAssociation($inverseField)) {
|
||||
$targetClass->reflFields[$inverseField]->setValue($targetEntity, $sourceEntity);
|
||||
}
|
||||
} else {
|
||||
@ -245,8 +252,9 @@ class OneToOneMapping extends AssociationMapping
|
||||
if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||
$conditions[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||
} else {
|
||||
//TODO: Should never happen. Exception?
|
||||
$conditions[$targetKeyColumn] = $joinColumnValues[$sourceKeyColumn];
|
||||
throw MappingException::joinColumnMustPointToMappedField(
|
||||
$sourceClass->name, $sourceKeyColumn
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,7 +270,7 @@ class OneToOneMapping extends AssociationMapping
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Experimental. For MetaModel API, Doctrine 2.1.
|
||||
* @internal Experimental. For MetaModel API, Doctrine 2.1 or later.
|
||||
*/
|
||||
public static function __set_state(array $state)
|
||||
{
|
||||
|
@ -53,7 +53,7 @@ class StandardEntityPersister
|
||||
protected $_class;
|
||||
|
||||
/**
|
||||
* The Connection instance.
|
||||
* The underlying Connection of the used EntityManager.
|
||||
*
|
||||
* @var Doctrine\DBAL\Connection $conn
|
||||
*/
|
||||
@ -289,28 +289,6 @@ class StandardEntityPersister
|
||||
$this->_conn->delete($this->_class->primaryTable['name'], $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entity to delete.
|
||||
*
|
||||
* @param object $entity
|
||||
* @todo Impl.
|
||||
*/
|
||||
public function addDelete($entity)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all pending entity deletions.
|
||||
*
|
||||
* @see addDelete()
|
||||
* @todo Impl.
|
||||
*/
|
||||
public function executeDeletions()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ClassMetadata instance of the entity class this persister is used for.
|
||||
*
|
||||
@ -560,7 +538,7 @@ class StandardEntityPersister
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a collection of entities into a one-to-many association.
|
||||
* Loads a collection of entities in a one-to-many association.
|
||||
*
|
||||
* @param array $criteria The criteria by which to select the entities.
|
||||
* @param PersistentCollection The collection to fill.
|
||||
|
@ -584,16 +584,16 @@ class QueryBuilder
|
||||
* ->set('u.password', md5('password'))
|
||||
* ->where($or);
|
||||
*
|
||||
* @param mixed $where The WHERE statement
|
||||
* @return QueryBuilder $qb
|
||||
* @param mixed $predicates The predicates.
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function where($where)
|
||||
public function where($predicates)
|
||||
{
|
||||
if ( ! (func_num_args() == 1 && ($where instanceof Expr\Andx || $where instanceof Expr\Orx))) {
|
||||
$where = new Expr\Andx(func_get_args());
|
||||
if ( ! (func_num_args() == 1 && ($predicates instanceof Expr\Andx || $predicates instanceof Expr\Orx))) {
|
||||
$predicates = new Expr\Andx(func_get_args());
|
||||
}
|
||||
|
||||
return $this->add('where', $where);
|
||||
return $this->add('where', $predicates);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1217,7 +1217,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
break;
|
||||
case self::STATE_DETACHED:
|
||||
throw new \InvalidArgumentException(
|
||||
"Behavior of save() for a detached entity is not yet defined.");
|
||||
"Behavior of persist() for a detached entity is not yet defined.");
|
||||
case self::STATE_REMOVED:
|
||||
// Entity becomes managed again
|
||||
if ($this->isScheduledForDelete($entity)) {
|
||||
@ -1766,10 +1766,10 @@ class UnitOfWork implements PropertyChangedListener
|
||||
if ( ! isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
|
||||
foreach ($class->associationMappings as $field => $assoc) {
|
||||
// Check if the association is not among the fetch-joined associations already.
|
||||
if (isset($hints['fetched'][$class->rootEntityName][$field])) {
|
||||
if (isset($hints['fetched'][$className][$field])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$targetClass = $this->_em->getClassMetadata($assoc->targetEntityName);
|
||||
|
||||
if ($assoc->isOneToOne()) {
|
||||
|
@ -10,9 +10,10 @@ class DDC279Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
parent::setUp();
|
||||
$this->_schemaTool->createSchema(array(
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC279EntityXAbstract'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC279EntityX'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC279EntityY'),
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC279EntityZ')
|
||||
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC279EntityZ'),
|
||||
));
|
||||
}
|
||||
|
||||
@ -39,34 +40,31 @@ class DDC279Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$result = $this->_em->createQuery(
|
||||
$query = $this->_em->createQuery(
|
||||
'SELECT x, y, z FROM Doctrine\Tests\ORM\Functional\Ticket\DDC279EntityX x '.
|
||||
'INNER JOIN x.y y INNER JOIN y.z z WHERE x.id = 1'
|
||||
)->getArrayResult();
|
||||
'INNER JOIN x.y y INNER JOIN y.z z WHERE x.id = ?1'
|
||||
)->setParameter(1, $x->id);
|
||||
|
||||
$result = $query->getResult();
|
||||
|
||||
$expected1 = 'Y';
|
||||
$expected2 = 'Z';
|
||||
|
||||
$expected = array(
|
||||
0 => array(
|
||||
'id' => 1,
|
||||
'data' => 'X',
|
||||
'y' => array(
|
||||
'id' => 1,
|
||||
'data' => 'Y',
|
||||
'z' => array(
|
||||
'id' => 1,
|
||||
'data' => 'Z',
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $result);
|
||||
$this->assertEquals(1, count($result));
|
||||
|
||||
$this->assertEquals($expected1, $result[0]->y->data);
|
||||
$this->assertEquals($expected2, $result[0]->y->z->data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @InheritanceType("JOINED")
|
||||
* @DiscriminatorColumn(name="discr", type="string")
|
||||
* @DiscriminatorMap({"DDC279EntityX" = "DDC279EntityX"})
|
||||
*/
|
||||
class DDC279EntityX
|
||||
abstract class DDC279EntityXAbstract
|
||||
{
|
||||
/**
|
||||
* @Id
|
||||
@ -80,8 +78,15 @@ class DDC279EntityX
|
||||
*/
|
||||
public $data;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class DDC279EntityX extends DDC279EntityXAbstract
|
||||
{
|
||||
/**
|
||||
* @OneToOne(targetEntity="Doctrine\Tests\ORM\Functional\Ticket\DDC279EntityY")
|
||||
* @OneToOne(targetEntity="DDC279EntityY")
|
||||
* @JoinColumn(name="y_id", referencedColumnName="id")
|
||||
*/
|
||||
public $y;
|
||||
@ -105,7 +110,7 @@ class DDC279EntityY
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* @OneToOne(targetEntity="Doctrine\Tests\ORM\Functional\Ticket\DDC279EntityZ")
|
||||
* @OneToOne(targetEntity="DDC279EntityZ")
|
||||
* @JoinColumn(name="z_id", referencedColumnName="id")
|
||||
*/
|
||||
public $z;
|
||||
|
Loading…
x
Reference in New Issue
Block a user