[DDC-992] Fix criteria usage of column names clashing with field or associations by prefixing with table names or alias.
This commit is contained in:
parent
8430aefe21
commit
7a41a205ee
@ -777,6 +777,7 @@ class BasicEntityPersister
|
|||||||
$criteria = array();
|
$criteria = array();
|
||||||
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
|
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
|
||||||
if ($assoc['isOwningSide']) {
|
if ($assoc['isOwningSide']) {
|
||||||
|
$quotedJoinTable = $sourceClass->getQuotedJoinTableName($assoc, $this->_platform);
|
||||||
foreach ($assoc['relationToSourceKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
|
foreach ($assoc['relationToSourceKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
|
||||||
if ($sourceClass->containsForeignIdentifier) {
|
if ($sourceClass->containsForeignIdentifier) {
|
||||||
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
|
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
|
||||||
@ -785,9 +786,10 @@ class BasicEntityPersister
|
|||||||
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||||
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
|
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
|
||||||
}
|
}
|
||||||
$criteria[$relationKeyColumn] = $value;
|
|
||||||
|
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $value;
|
||||||
} else if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
} else if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||||
$criteria[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||||
} else {
|
} else {
|
||||||
throw MappingException::joinColumnMustPointToMappedField(
|
throw MappingException::joinColumnMustPointToMappedField(
|
||||||
$sourceClass->name, $sourceKeyColumn
|
$sourceClass->name, $sourceKeyColumn
|
||||||
@ -796,6 +798,7 @@ class BasicEntityPersister
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$owningAssoc = $this->_em->getClassMetadata($assoc['targetEntity'])->associationMappings[$assoc['mappedBy']];
|
$owningAssoc = $this->_em->getClassMetadata($assoc['targetEntity'])->associationMappings[$assoc['mappedBy']];
|
||||||
|
$quotedJoinTable = $sourceClass->getQuotedJoinTableName($owningAssoc, $this->_platform);
|
||||||
// TRICKY: since the association is inverted source and target are flipped
|
// TRICKY: since the association is inverted source and target are flipped
|
||||||
foreach ($owningAssoc['relationToTargetKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
|
foreach ($owningAssoc['relationToTargetKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
|
||||||
if ($sourceClass->containsForeignIdentifier) {
|
if ($sourceClass->containsForeignIdentifier) {
|
||||||
@ -805,9 +808,9 @@ class BasicEntityPersister
|
|||||||
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||||
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
|
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
|
||||||
}
|
}
|
||||||
$criteria[$relationKeyColumn] = $value;
|
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $value;
|
||||||
} else if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
} else if (isset($sourceClass->fieldNames[$sourceKeyColumn])) {
|
||||||
$criteria[$relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||||
} else {
|
} else {
|
||||||
throw MappingException::joinColumnMustPointToMappedField(
|
throw MappingException::joinColumnMustPointToMappedField(
|
||||||
$sourceClass->name, $sourceKeyColumn
|
$sourceClass->name, $sourceKeyColumn
|
||||||
@ -1194,14 +1197,12 @@ class BasicEntityPersister
|
|||||||
}
|
}
|
||||||
|
|
||||||
$conditionSql .= $this->_class->associationMappings[$field]['joinColumns'][0]['name'];
|
$conditionSql .= $this->_class->associationMappings[$field]['joinColumns'][0]['name'];
|
||||||
} else if ($assoc !== null) {
|
} else if ($assoc !== null && strpos($field, " ") === false && strpos($field, "(") === false) {
|
||||||
if ($assoc['type'] == ClassMetadata::MANY_TO_MANY) {
|
// very careless developers could potentially open up this normally hidden api for userland attacks,
|
||||||
$owningAssoc = $assoc['isOwningSide'] ? $assoc : $this->_em->getClassMetadata($assoc['targetEntity'])
|
// therefore checking for spaces and function calls which are not allowed.
|
||||||
->associationMappings[$assoc['mappedBy']];
|
|
||||||
$conditionSql .= $this->_class->getQuotedJoinTableName($owningAssoc, $this->_platform) . '.' . $field;
|
// found a join column condition, not really a "field"
|
||||||
} else {
|
$conditionSql .= $field;
|
||||||
$conditionSql .= $field;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw ORMException::unrecognizedField($field);
|
throw ORMException::unrecognizedField($field);
|
||||||
}
|
}
|
||||||
@ -1254,6 +1255,11 @@ class BasicEntityPersister
|
|||||||
$criteria = array();
|
$criteria = array();
|
||||||
$owningAssoc = $this->_class->associationMappings[$assoc['mappedBy']];
|
$owningAssoc = $this->_class->associationMappings[$assoc['mappedBy']];
|
||||||
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
|
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
|
||||||
|
|
||||||
|
$tableAlias = isset($owningAssoc['inherited']) ?
|
||||||
|
$this->_getSQLTableAlias($owningAssoc['inherited'])
|
||||||
|
: $this->_getSQLTableAlias($this->_class->name);
|
||||||
|
|
||||||
foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) {
|
foreach ($owningAssoc['targetToSourceKeyColumns'] as $sourceKeyColumn => $targetKeyColumn) {
|
||||||
if ($sourceClass->containsForeignIdentifier) {
|
if ($sourceClass->containsForeignIdentifier) {
|
||||||
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
|
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
|
||||||
@ -1262,9 +1268,9 @@ class BasicEntityPersister
|
|||||||
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||||
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
|
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
|
||||||
}
|
}
|
||||||
$criteria[$targetKeyColumn] = $value;
|
$criteria[$tableAlias . "." . $targetKeyColumn] = $value;
|
||||||
} else {
|
} else {
|
||||||
$criteria[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
$criteria[$tableAlias . "." . $targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,4 +410,29 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
|||||||
$ref = $this->_em->getReference('Doctrine\Tests\Models\Company\CompanyManager', $manager->getId());
|
$ref = $this->_em->getReference('Doctrine\Tests\Models\Company\CompanyManager', $manager->getId());
|
||||||
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $ref, "A proxy can be generated only if no subclasses exists for the requested reference.");
|
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $ref, "A proxy can be generated only if no subclasses exists for the requested reference.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-992
|
||||||
|
*/
|
||||||
|
public function testGetSubClassManyToManyCollection()
|
||||||
|
{
|
||||||
|
$manager = new CompanyManager();
|
||||||
|
$manager->setName('gblanco');
|
||||||
|
$manager->setSalary(1234);
|
||||||
|
$manager->setTitle('Awesome!');
|
||||||
|
$manager->setDepartment('IT');
|
||||||
|
|
||||||
|
$person = new CompanyPerson();
|
||||||
|
$person->setName('friend');
|
||||||
|
|
||||||
|
$manager->addFriend($person);
|
||||||
|
|
||||||
|
$this->_em->persist($manager);
|
||||||
|
$this->_em->persist($person);
|
||||||
|
$this->_em->flush();
|
||||||
|
$this->_em->clear();
|
||||||
|
|
||||||
|
$manager = $this->_em->find('Doctrine\Tests\Models\Company\CompanyManager', $manager->getId());
|
||||||
|
$this->assertEquals(1, count($manager->getFriends()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
147
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC992Test.php
Normal file
147
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC992Test.php
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||||
|
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../../TestInit.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-992
|
||||||
|
*/
|
||||||
|
class DDC992Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||||
|
{
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
try {
|
||||||
|
$this->_schemaTool->createSchema(array(
|
||||||
|
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC992Role'),
|
||||||
|
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC992Parent'),
|
||||||
|
$this->_em->getClassMetadata(__NAMESPACE__ . '\DDC992Child'),
|
||||||
|
));
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIssue()
|
||||||
|
{
|
||||||
|
$role = new DDC992Role();
|
||||||
|
$role->name = "Parent";
|
||||||
|
$child = new DDC992Role();
|
||||||
|
$child->name = "child";
|
||||||
|
|
||||||
|
$role->extendedBy[] = $child;
|
||||||
|
$child->extends[] = $role;
|
||||||
|
|
||||||
|
$this->_em->persist($role);
|
||||||
|
$this->_em->persist($child);
|
||||||
|
$this->_em->flush();
|
||||||
|
$this->_em->clear();
|
||||||
|
|
||||||
|
$child = $this->_em->getRepository(get_class($role))->find($child->roleID);
|
||||||
|
$parents = count($child->extends);
|
||||||
|
$this->assertEquals(1, $parents);
|
||||||
|
foreach ($child->extends AS $parent) {
|
||||||
|
$this->assertEquals($role->getRoleID(), $parent->getRoleID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOneToManyChild()
|
||||||
|
{
|
||||||
|
$parent = new DDC992Parent();
|
||||||
|
$child = new DDC992Child();
|
||||||
|
$child->parent = $parent;
|
||||||
|
$parent->childs[] = $child;
|
||||||
|
|
||||||
|
$this->_em->persist($parent);
|
||||||
|
$this->_em->persist($child);
|
||||||
|
$this->_em->flush();
|
||||||
|
$this->_em->clear();
|
||||||
|
|
||||||
|
$parentRepository = $this->_em->getRepository(get_class($parent));
|
||||||
|
$childRepository = $this->_em->getRepository(get_class($child));
|
||||||
|
|
||||||
|
$parent = $parentRepository->find($parent->id);
|
||||||
|
$this->assertEquals(1, count($parent->childs));
|
||||||
|
$this->assertEquals(0, count($parent->childs[0]->childs()));
|
||||||
|
|
||||||
|
$child = $parentRepository->findOneBy(array("id" => $child->id));
|
||||||
|
$this->assertSame($parent->childs[0], $child);
|
||||||
|
|
||||||
|
$this->_em->clear();
|
||||||
|
|
||||||
|
$child = $parentRepository->find($child->id);
|
||||||
|
$this->assertEquals(0, count($child->childs));
|
||||||
|
|
||||||
|
$this->_em->clear();
|
||||||
|
|
||||||
|
$child = $childRepository->find($child->id);
|
||||||
|
$this->assertEquals(0, count($child->childs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Entity
|
||||||
|
* @InheritanceType("JOINED")
|
||||||
|
* @DiscriminatorMap({"child" = "DDC992Child", "parent" = "DDC992Parent"})
|
||||||
|
*/
|
||||||
|
class DDC992Parent
|
||||||
|
{
|
||||||
|
/** @Id @GeneratedValue @Column(type="integer") */
|
||||||
|
public $id;
|
||||||
|
/** @ManyToOne(targetEntity="DDC992Parent", inversedBy="childs") */
|
||||||
|
public $parent;
|
||||||
|
/** @OneToMany(targetEntity="DDC992Child", mappedBy="parent") */
|
||||||
|
public $childs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Entity
|
||||||
|
*/
|
||||||
|
class DDC992Child extends DDC992Parent
|
||||||
|
{
|
||||||
|
public function childs()
|
||||||
|
{
|
||||||
|
return $this->childs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Entity
|
||||||
|
*/
|
||||||
|
class DDC992Role
|
||||||
|
{
|
||||||
|
public function getRoleID()
|
||||||
|
{
|
||||||
|
return $this->roleID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Id @Column(name="roleID", type="integer")
|
||||||
|
* @GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
public $roleID;
|
||||||
|
/**
|
||||||
|
* @Column (name="name", type="string", length="45")
|
||||||
|
*/
|
||||||
|
public $name;
|
||||||
|
/**
|
||||||
|
* @ManyToMany (targetEntity="DDC992Role", mappedBy="extends")
|
||||||
|
*/
|
||||||
|
public $extendedBy;
|
||||||
|
/**
|
||||||
|
* @ManyToMany (targetEntity="DDC992Role", inversedBy="extendedBy")
|
||||||
|
* @JoinTable (name="RoleRelations",
|
||||||
|
* joinColumns={@JoinColumn(name="roleID", referencedColumnName="roleID")},
|
||||||
|
* inverseJoinColumns={@JoinColumn(name="extendsRoleID", referencedColumnName="roleID")}
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public $extends;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$this->extends = new ArrayCollection;
|
||||||
|
$this->extendedBy = new ArrayCollection;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user