1
0
mirror of synced 2025-01-17 22:11:41 +03:00

[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:
Benjamin Eberlei 2011-03-20 17:07:19 +01:00
parent 8430aefe21
commit 7a41a205ee
3 changed files with 192 additions and 14 deletions

View File

@ -777,6 +777,7 @@ class BasicEntityPersister
$criteria = array();
$sourceClass = $this->_em->getClassMetadata($assoc['sourceEntity']);
if ($assoc['isOwningSide']) {
$quotedJoinTable = $sourceClass->getQuotedJoinTableName($assoc, $this->_platform);
foreach ($assoc['relationToSourceKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
if ($sourceClass->containsForeignIdentifier) {
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
@ -785,9 +786,10 @@ class BasicEntityPersister
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
}
$criteria[$relationKeyColumn] = $value;
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $value;
} 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 {
throw MappingException::joinColumnMustPointToMappedField(
$sourceClass->name, $sourceKeyColumn
@ -796,6 +798,7 @@ class BasicEntityPersister
}
} else {
$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
foreach ($owningAssoc['relationToTargetKeyColumns'] as $relationKeyColumn => $sourceKeyColumn) {
if ($sourceClass->containsForeignIdentifier) {
@ -805,9 +808,9 @@ class BasicEntityPersister
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
}
$criteria[$relationKeyColumn] = $value;
$criteria[$quotedJoinTable . "." . $relationKeyColumn] = $value;
} 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 {
throw MappingException::joinColumnMustPointToMappedField(
$sourceClass->name, $sourceKeyColumn
@ -1194,14 +1197,12 @@ class BasicEntityPersister
}
$conditionSql .= $this->_class->associationMappings[$field]['joinColumns'][0]['name'];
} else if ($assoc !== null) {
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;
}
} else if ($assoc !== null && strpos($field, " ") === false && strpos($field, "(") === false) {
// very careless developers could potentially open up this normally hidden api for userland attacks,
// therefore checking for spaces and function calls which are not allowed.
// found a join column condition, not really a "field"
$conditionSql .= $field;
} else {
throw ORMException::unrecognizedField($field);
}
@ -1254,6 +1255,11 @@ class BasicEntityPersister
$criteria = array();
$owningAssoc = $this->_class->associationMappings[$assoc['mappedBy']];
$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) {
if ($sourceClass->containsForeignIdentifier) {
$field = $sourceClass->getFieldForColumn($sourceKeyColumn);
@ -1262,9 +1268,9 @@ class BasicEntityPersister
$value = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
$value = $value[$this->_em->getClassMetadata($assoc['targetEntity'])->identifier[0]];
}
$criteria[$targetKeyColumn] = $value;
$criteria[$tableAlias . "." . $targetKeyColumn] = $value;
} else {
$criteria[$targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
$criteria[$tableAlias . "." . $targetKeyColumn] = $sourceClass->reflFields[$sourceClass->fieldNames[$sourceKeyColumn]]->getValue($sourceEntity);
}
}

View File

@ -410,4 +410,29 @@ class ClassTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
$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.");
}
/**
* @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()));
}
}

View 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;
}
}