Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #486 from FabioBatSilva/DDC-2084

Fix DDC-2084
  • Loading branch information...
commit d6d5c341e220ff7aec50c8ecabd5d0b8be2e0804 2 parents 262c3ee + 62f43e6
@guilhermeblanco guilhermeblanco authored
View
46 lib/Doctrine/ORM/AbstractQuery.php
@@ -26,6 +26,7 @@
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\ORM\Query\QueryException;
+use Doctrine\ORM\ORMInvalidArgumentException;
/**
* Base contract for ORM queries. Base class for Query and NativeQuery.
@@ -247,44 +248,21 @@ function ($parameter) use ($key)
*/
public function processParameterValue($value)
{
- switch (true) {
- case is_array($value):
- foreach ($value as $key => $paramValue) {
- $paramValue = $this->processParameterValue($paramValue);
- $value[$key] = is_array($paramValue) ? $paramValue[key($paramValue)] : $paramValue;
- }
-
- return $value;
-
- case is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value)):
- return $this->convertObjectParameterToScalarValue($value);
-
- default:
- return $value;
- }
- }
-
- private function convertObjectParameterToScalarValue($value)
- {
- $class = $this->_em->getClassMetadata(get_class($value));
+ if (is_array($value)) {
+ foreach ($value as $key => $paramValue) {
+ $paramValue = $this->processParameterValue($paramValue);
+ $value[$key] = is_array($paramValue) ? reset($paramValue) : $paramValue;
+ }
- if ($class->isIdentifierComposite) {
- throw new \InvalidArgumentException(
- "Binding an entity with a composite primary key to a query is not supported. " .
- "You should split the parameter into the explicit fields and bind them seperately."
- );
+ return $value;
}
- $values = ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED)
- ? $this->_em->getUnitOfWork()->getEntityIdentifier($value)
- : $class->getIdentifierValues($value);
+ if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) {
+ $value = $this->_em->getUnitOfWork()->getSingleIdentifierValue($value);
- $value = $values[$class->getSingleIdentifierFieldName()];
-
- if (null === $value) {
- throw new \InvalidArgumentException(
- "Binding entities to query parameters only allowed for entities that have an identifier."
- );
+ if ($value === null) {
+ throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
+ }
}
return $value;
View
11 lib/Doctrine/ORM/EntityManager.php
@@ -29,6 +29,7 @@
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Proxy\ProxyFactory;
use Doctrine\ORM\Query\FilterCollection;
+use Doctrine\Common\Util\ClassUtils;
/**
* The EntityManager is the central access point to ORM functionality.
@@ -354,7 +355,7 @@ public function flush($entity = null)
$this->unitOfWork->commit($entity);
}
-
+
/**
* Finds an Entity by its identifier.
*
@@ -369,6 +370,14 @@ public function find($entityName, $id, $lockMode = LockMode::NONE, $lockVersion
{
$class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
+ if (is_object($id) && $this->metadataFactory->hasMetadataFor(ClassUtils::getClass($id))) {
+ $id = $this->unitOfWork->getSingleIdentifierValue($id);
+
+ if ($id === null) {
+ throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
+ }
+ }
+
if ( ! is_array($id)) {
$id = array($class->identifier[0] => $id);
}
View
11 lib/Doctrine/ORM/ORMInvalidArgumentException.php
@@ -102,6 +102,17 @@ public static function invalidObject($context, $given, $parameterIndex = 1)
' to be an entity object, '. gettype($given) . ' given.');
}
+ public static function invalidCompositeIdentifier()
+ {
+ return new self("Binding an entity with a composite primary key to a query is not supported. " .
+ "You should split the parameter into the explicit fields and bind them seperately.");
+ }
+
+ public static function invalidIdentifierBindingEntity()
+ {
+ return new self("Binding entities to query parameters only allowed for entities that have an identifier.");
+ }
+
/**
* Helper method to show an object as string.
*
View
24 lib/Doctrine/ORM/UnitOfWork.php
@@ -2738,6 +2738,30 @@ public function getEntityIdentifier($entity)
}
/**
+ * Process an entity instance to extract their identifier values.
+ *
+ * @param object $entity The entity instance.
+ *
+ * @return scalar
+ *
+ * @throws \Doctrine\ORM\ORMInvalidArgumentException
+ */
+ public function getSingleIdentifierValue($entity)
+ {
+ $class = $this->em->getClassMetadata(get_class($entity));
+
+ if ($class->isIdentifierComposite) {
+ throw ORMInvalidArgumentException::invalidCompositeIdentifier();
+ }
+
+ $values = ($this->getEntityState($entity) === UnitOfWork::STATE_MANAGED)
+ ? $this->getEntityIdentifier($entity)
+ : $class->getIdentifierValues($entity);
+
+ return isset($values[$class->identifier[0]]) ? $values[$class->identifier[0]] : null;
+ }
+
+ /**
* Tries to find an entity with the given identifier in the identity map of
* this UnitOfWork.
*
View
128 tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2084Test.php
@@ -0,0 +1,128 @@
+<?php
+
+namespace Doctrine\Tests\ORM\Functional\Ticket;
+
+/**
+ * @group DDC-2084
+ */
+class DDC2084Test extends \Doctrine\Tests\OrmFunctionalTestCase
+{
+ public function setUp()
+ {
+ parent::setUp();
+
+ try {
+ $this->_schemaTool->createSchema(array(
+ $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2084\MyEntity1'),
+ $this->_em->getClassMetadata(__NAMESPACE__ . '\DDC2084\MyEntity2'),
+ ));
+ } catch (\Exception $exc) {
+ }
+ }
+
+ public function loadFixture()
+ {
+ $e2 = new DDC2084\MyEntity2('Foo');
+ $e1 = new DDC2084\MyEntity1($e2);
+
+ $this->_em->persist($e2);
+ $this->_em->flush();
+
+ $this->_em->persist($e1);
+ $this->_em->flush();
+
+ $this->_em->clear();
+
+ return $e1;
+ }
+
+ public function testIssue()
+ {
+ $e1 = $this->loadFixture();
+ $e2 = $e1->getMyEntity2();
+ $e = $this->_em->find(__NAMESPACE__ . '\DDC2084\MyEntity1', $e2);
+
+ $this->assertInstanceOf(__NAMESPACE__ . '\DDC2084\MyEntity1', $e);
+ $this->assertInstanceOf(__NAMESPACE__ . '\DDC2084\MyEntity2', $e->getMyEntity2());
+ $this->assertEquals('Foo', $e->getMyEntity2()->getValue());
+ }
+
+ /**
+ * @expectedException \Doctrine\ORM\ORMInvalidArgumentException
+ * @expectedExceptionMessage Binding entities to query parameters only allowed for entities that have an identifier.
+ */
+ public function testinvalidIdentifierBindingEntityException()
+ {
+ $this->_em->find(__NAMESPACE__ . '\DDC2084\MyEntity1', new DDC2084\MyEntity2('Foo'));
+ }
+}
+
+namespace Doctrine\Tests\ORM\Functional\Ticket\DDC2084;
+
+/**
+ * @Entity
+ * @Table(name="DDC2084_ENTITY1")
+ */
+class MyEntity1
+{
+ /**
+ * @Id
+ * @OneToOne(targetEntity="MyEntity2")
+ * @JoinColumn(name="entity2_id", referencedColumnName="id", nullable=false)
+ */
+ private $entity2;
+
+ public function __construct(MyEntity2 $myEntity2)
+ {
+ $this->entity2 = $myEntity2;
+ }
+
+ public function setMyEntity2(MyEntity2 $myEntity2)
+ {
+ $this->entity2 = $myEntity2;
+ }
+
+ public function getMyEntity2()
+ {
+ return $this->entity2;
+ }
+}
+
+/**
+ * @Entity
+ * @Table(name="DDC2084_ENTITY2")
+ */
+class MyEntity2
+{
+ /**
+ * @Id
+ * @Column(type="integer")
+ * @GeneratedValue(strategy="AUTO")
+ */
+ private $id;
+
+ /**
+ * @Column
+ */
+ private $value;
+
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+ public function setValue($value)
+ {
+ $this->value = $value;
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.