Skip to content

Instantly share code, notes, and snippets.

@doctrinebot
Created December 13, 2015 18:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save doctrinebot/d9023c7662c514f9fa1f to your computer and use it in GitHub Desktop.
Save doctrinebot/d9023c7662c514f9fa1f to your computer and use it in GitHub Desktop.
Attachments to Doctrine Jira Issue DDC-203 - https://github.com/doctrine/doctrine2/issues/2707
Index: tests/Doctrine/Tests/ORM/Functional/DetachedEntityTest.php
===================================================================
--- tests/Doctrine/Tests/ORM/Functional/DetachedEntityTest.php (revision 6913)
+++ tests/Doctrine/Tests/ORM/Functional/DetachedEntityTest.php (working copy)
@@ -35,7 +35,7 @@
$user->name = 'Roman B.';
- //$this->assertEquals(UnitOfWork::STATE_DETACHED, $this->_em->getUnitOfWork()->getEntityState($user));
+ $this->assertEquals(UnitOfWork::STATE_DETACHED, $this->_em->getUnitOfWork()->getEntityState($user));
$user2 = $this->_em->merge($user);
@@ -84,6 +84,27 @@
$this->assertTrue($this->_em->contains($phonenumbers[0]));
$this->assertTrue($this->_em->contains($phonenumbers[1]));
}
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testBlocksPersistingOfADetachedAndNotMergedEntity()
+ {
+ $user = new CmsUser;
+ $user->name = 'Roman';
+ $user->username = 'romanb';
+ $user->status = 'dev';
+ $this->_em->persist($user);
+ $this->_em->flush();
+ $this->_em->detach($user);
+ $this->_em->persist($user);
+ }
+ public function testRecognizesDetachedEntitiesWithoutRelyingOnValorizedKeys()
+ {
+ $ph1 = new CmsPhonenumber;
+ $ph1->phonenumber = 1234;
+ $this->assertEquals(UnitOfWork::STATE_NEW, $this->_em->getUnitOfWork()->getEntityState($ph1));
+ }
}
Index: lib/Doctrine/ORM/UnitOfWork.php
===================================================================
--- lib/Doctrine/ORM/UnitOfWork.php (revision 6913)
+++ lib/Doctrine/ORM/UnitOfWork.php (working copy)
@@ -1045,10 +1045,11 @@
// manually assigned identifiers but in that case we would need to hit the database
// and we would like to avoid that.
if ($assume === null) {
- if ($this->_em->getClassMetadata(get_class($entity))->getIdentifierValues($entity)) {
+ $identifierValues = $this->_em->getClassMetadata(get_class($entity))->getIdentifierValues($entity);
+ if (current($identifierValues) === null) {
+ $this->_entityStates[$oid] = self::STATE_NEW;
+ } else {
$this->_entityStates[$oid] = self::STATE_DETACHED;
- } else {
- $this->_entityStates[$oid] = self::STATE_NEW;
}
} else {
$this->_entityStates[$oid] = $assume;
@@ -1180,7 +1181,7 @@
$visited[$oid] = $entity; // Mark visited
$class = $this->_em->getClassMetadata(get_class($entity));
- $entityState = $this->getEntityState($entity, self::STATE_NEW);
+ $entityState = $this->getEntityState($entity);
switch ($entityState) {
case self::STATE_MANAGED:
Index: lib/Doctrine/ORM/UnitOfWork.php
===================================================================
--- lib/Doctrine/ORM/UnitOfWork.php (revision 7099)
+++ lib/Doctrine/ORM/UnitOfWork.php (working copy)
@@ -1049,7 +1049,8 @@
// manually assigned identifiers but in that case we would need to hit the database
// and we would like to avoid that.
if ($assume === null) {
- if ($this->_em->getClassMetadata(get_class($entity))->getIdentifierValues($entity)) {
+ $cm = $this->_em->getClassMetadata(get_class($entity));
+ if (array_reduce($cm->getIdentifierValues($entity), function ($last, $next) { return $last && $next === null; }) && $cm->generatorType !== Mapping\ClassMetadata::GENERATOR_TYPE_NONE) {
$this->_entityStates[$oid] = self::STATE_DETACHED;
} else {
$this->_entityStates[$oid] = self::STATE_NEW;
@@ -1184,7 +1185,7 @@
$visited[$oid] = $entity; // Mark visited
$class = $this->_em->getClassMetadata(get_class($entity));
- $entityState = $this->getEntityState($entity, self::STATE_NEW);
+ $entityState = $this->getEntityState($entity);
switch ($entityState) {
case self::STATE_MANAGED:
Index: lib/Doctrine/ORM/EntityExistsException.php
===================================================================
--- lib/Doctrine/ORM/EntityExistsException.php (revision 0)
+++ lib/Doctrine/ORM/EntityExistsException.php (revision 0)
@@ -0,0 +1,24 @@
+<?php
+
+namespace Doctrine\ORM;
+
+/**
+ * EntityExistsException is thrown by EntityManager when a detached Entity is being persisted.
+ *
+ * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+ * @link www.doctrine-project.com
+ * @since 1.0
+ * @version $Revision$
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ */
+class EntityExistsException extends ORMException
+{
+ /**
+ * @param string $class
+ */
+ public function __construct($class)
+ {
+ parent::__construct("Entity of Type '".$class."' is already associated with the ".
+ "persistence context, you can't call persist() on it more than once.");
+ }
+}
\ No newline at end of file
Property changes on: lib/Doctrine/ORM/EntityExistsException.php
___________________________________________________________________
Added: svn:keywords
+ Id,Revision
Added: svn:eol-style
+ LF
Index: lib/Doctrine/ORM/UnitOfWork.php
===================================================================
--- lib/Doctrine/ORM/UnitOfWork.php (revision 7099)
+++ lib/Doctrine/ORM/UnitOfWork.php (working copy)
@@ -1049,7 +1049,8 @@
// manually assigned identifiers but in that case we would need to hit the database
// and we would like to avoid that.
if ($assume === null) {
- if ($this->_em->getClassMetadata(get_class($entity))->getIdentifierValues($entity)) {
+ $cm = $this->_em->getClassMetadata(get_class($entity));
+ if (array_reduce($cm->getIdentifierValues($entity), function ($last, $next) { return $last && $next === null; }) && $cm->generatorType !== Mapping\ClassMetadata::GENERATOR_TYPE_NONE) {
$this->_entityStates[$oid] = self::STATE_DETACHED;
} else {
$this->_entityStates[$oid] = self::STATE_NEW;
@@ -1184,7 +1185,7 @@
$visited[$oid] = $entity; // Mark visited
$class = $this->_em->getClassMetadata(get_class($entity));
- $entityState = $this->getEntityState($entity, self::STATE_NEW);
+ $entityState = $this->getEntityState($entity);
switch ($entityState) {
case self::STATE_MANAGED:
@@ -1216,8 +1217,7 @@
$this->scheduleForInsert($entity);
break;
case self::STATE_DETACHED:
- throw new \InvalidArgumentException(
- "Behavior of persist() for a detached entity is not yet defined.");
+ throw new EntityExistsException($class->name);
case self::STATE_REMOVED:
// Entity becomes managed again
if ($this->isScheduledForDelete($entity)) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment