Improved and extracted UnitOfWork error messages
This commit is contained in:
parent
3aea203b9c
commit
5392737de4
81
lib/Doctrine/ORM/ORMInvalidArgumentException.php
Normal file
81
lib/Doctrine/ORM/ORMInvalidArgumentException.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM;
|
||||
|
||||
class ORMInvalidArgumentException extends \InvalidArgumentException
|
||||
{
|
||||
static public function scheduleInsertForManagedEntity($entity)
|
||||
{
|
||||
return new self("A managed+dirty entity " . self::objToStr($entity) . " can not be scheduled for insertion.");
|
||||
}
|
||||
|
||||
static public function scheduleInsertForRemovedEntity($entity)
|
||||
{
|
||||
return new self("Removed entity " . self::objToStr($entity) . " can not be scheduled for insertion.");
|
||||
}
|
||||
|
||||
static public function scheduleInsertTwice($entity)
|
||||
{
|
||||
return new self("Entity " . self::objToStr($entity) . " can not be scheduled for insertion twice.");
|
||||
}
|
||||
|
||||
static public function entityWithoutIdentity($className, $entity)
|
||||
{
|
||||
throw new self(
|
||||
"The given entity of type '" . $className . "' (".self::objToStr($entity).") has no identity/no " .
|
||||
"id values set. It cannot be added to the identity map."
|
||||
);
|
||||
}
|
||||
|
||||
static public function readOnlyRequiresManagedEntity($entity)
|
||||
{
|
||||
return new self("Only managed entities can be marked or checked as read only. But " . self::objToStr($entity) . " is not");
|
||||
}
|
||||
|
||||
static public function newEntityFoundThroughRelationship(array $assoc, $entry)
|
||||
{
|
||||
return new self("A new entity was found through the relationship '"
|
||||
. $assoc['sourceEntity'] . "#" . $assoc['fieldName'] . "' that was not"
|
||||
. " configured to cascade persist operations for entity: " . self::objToStr($entry) . "."
|
||||
. " To solve this issue: Either explicitly call EntityManager#persist()"
|
||||
. " on this unknown entity or configure cascade persist "
|
||||
. " this association in the mapping for example @ManyToOne(..,cascade={\"persist\"}). "
|
||||
. " If you cannot find out which entity causes the problem"
|
||||
. " implement '" . $assoc['targetEntity'] . "#__toString()' to get a clue.");
|
||||
}
|
||||
|
||||
static public function detachedEntityFoundThroughRelationship(array $assoc, $entry)
|
||||
{
|
||||
throw new self("A detached entity of type " . $assoc['targetEntity'] . " (" . self::objToStr($entry) . ") "
|
||||
. " was found through the relationship '" . $assoc['sourceEntity'] . "#" . $assoc['fieldName'] . "' "
|
||||
. "during cascading a persist operation.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to show an object as string.
|
||||
*
|
||||
* @param object $obj
|
||||
* @return string
|
||||
*/
|
||||
private static function objToStr($obj)
|
||||
{
|
||||
return method_exists($obj, '__toString') ? (string)$obj : get_class($obj).'@'.spl_object_hash($obj);
|
||||
}
|
||||
}
|
@ -595,25 +595,16 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$oid = spl_object_hash($entry);
|
||||
if ($state == self::STATE_NEW) {
|
||||
if ( ! $assoc['isCascadePersist']) {
|
||||
throw new InvalidArgumentException("A new entity was found through the relationship '"
|
||||
. $assoc['sourceEntity'] . "#" . $assoc['fieldName'] . "' that was not"
|
||||
. " configured to cascade persist operations for entity: " . self::objToStr($entry) . "."
|
||||
. " Explicitly call EntityManager#persist() on this entity or configure to cascade persist "
|
||||
. " the association. If you cannot find out which entity causes the problem"
|
||||
. " implement '" . $assoc['targetEntity'] . "#__toString()' to get a clue.");
|
||||
throw ORMInvalidArgumentException::newEntityFoundThroughRelationship($assoc, $entry);
|
||||
}
|
||||
$this->persistNew($targetClass, $entry);
|
||||
$this->computeChangeSet($targetClass, $entry);
|
||||
} else if ($state == self::STATE_REMOVED) {
|
||||
return new InvalidArgumentException("Removed entity detected during flush: "
|
||||
. self::objToStr($entry).". Remove deleted entities from associations.");
|
||||
} else if ($state == self::STATE_DETACHED) {
|
||||
// Can actually not happen right now as we assume STATE_NEW,
|
||||
// so the exception will be raised from the DBAL layer (constraint violation).
|
||||
throw new InvalidArgumentException("A detached entity was found through a "
|
||||
. "relationship during cascading a persist operation.");
|
||||
throw ORMInvalidArgumentException::detachedEntityFoundThroughRelationship($assoc, $entry);
|
||||
}
|
||||
// MANAGED associated entities are already taken into account
|
||||
// MANAGED and REMOVED associated entities are already taken into account
|
||||
// during changeset calculation anyway, since they are in the identity map.
|
||||
}
|
||||
}
|
||||
@ -662,7 +653,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$oid = spl_object_hash($entity);
|
||||
|
||||
if ( ! isset($this->entityStates[$oid]) || $this->entityStates[$oid] != self::STATE_MANAGED) {
|
||||
throw new InvalidArgumentException('Entity must be managed.');
|
||||
throw new InvalidArgumentException("Entity of type '" . $class->name . "' must be managed.");
|
||||
}
|
||||
|
||||
/* TODO: Just return if changetracking policy is NOTIFY?
|
||||
@ -907,14 +898,14 @@ class UnitOfWork implements PropertyChangedListener
|
||||
{
|
||||
$oid = spl_object_hash($entity);
|
||||
|
||||
if (isset($this->entityUpdates[$oid])) {
|
||||
throw new InvalidArgumentException("Dirty entity can not be scheduled for insertion.");
|
||||
}
|
||||
if (isset($this->entityDeletions[$oid])) {
|
||||
throw new InvalidArgumentException("Removed entity can not be scheduled for insertion.");
|
||||
throw ORMInvalidArgumentException::scheduleInsertForRemovedEntity($entity);
|
||||
}
|
||||
if (isset($this->originalEntityData[$oid]) && ! isset($this->entityInsertions[$oid])) {
|
||||
throw ORMInvalidArgumentException::scheduleInsertForManagedEntity($entity);
|
||||
}
|
||||
if (isset($this->entityInsertions[$oid])) {
|
||||
throw new InvalidArgumentException("Entity can not be scheduled for insertion twice.");
|
||||
throw ORMInvalidArgumentException::scheduleInsertTwice($entity);
|
||||
}
|
||||
|
||||
$this->entityInsertions[$oid] = $entity;
|
||||
@ -1071,7 +1062,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$classMetadata = $this->em->getClassMetadata(get_class($entity));
|
||||
$idHash = implode(' ', $this->entityIdentifiers[spl_object_hash($entity)]);
|
||||
if ($idHash === '') {
|
||||
throw new InvalidArgumentException("The given entity has no identity.");
|
||||
throw ORMInvalidArgumentException::entityWithoutIdentity($classMetadata->name, $entity);
|
||||
}
|
||||
$className = $classMetadata->rootEntityName;
|
||||
if (isset($this->identityMap[$className][$idHash])) {
|
||||
@ -2466,7 +2457,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
public function markReadOnly($object)
|
||||
{
|
||||
if ( ! is_object($object) || ! $this->isInIdentityMap($object)) {
|
||||
throw new InvalidArgumentException("Managed entity required");
|
||||
throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
|
||||
}
|
||||
$this->readOnlyObjects[spl_object_hash($object)] = true;
|
||||
}
|
||||
@ -2481,7 +2472,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
public function isReadOnly($object)
|
||||
{
|
||||
if ( ! is_object($object) ) {
|
||||
throw new InvalidArgumentException("Managed entity required");
|
||||
throw ORMInvalidArgumentException::readOnlyRequiresManagedEntity($object);
|
||||
}
|
||||
return isset($this->readOnlyObjects[spl_object_hash($object)]);
|
||||
}
|
||||
|
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\Tests\Models\CMS\CmsUser;
|
||||
|
||||
class UnitOfWorkLifecycleTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
$this->useModelSet('cms');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testScheduleInsertManaged()
|
||||
{
|
||||
$user = new CmsUser();
|
||||
$user->username = "beberlei";
|
||||
$user->name = "Benjamin";
|
||||
$user->status = "active";
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "A managed+dirty entity Doctrine\Tests\Models\CMS\CmsUser");
|
||||
$this->_em->getUnitOfWork()->scheduleForInsert($user);
|
||||
}
|
||||
|
||||
public function testScheduleInsertDeleted()
|
||||
{
|
||||
$user = new CmsUser();
|
||||
$user->username = "beberlei";
|
||||
$user->name = "Benjamin";
|
||||
$user->status = "active";
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
|
||||
$this->_em->remove($user);
|
||||
|
||||
$this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "Removed entity Doctrine\Tests\Models\CMS\CmsUser");
|
||||
$this->_em->getUnitOfWork()->scheduleForInsert($user);
|
||||
}
|
||||
|
||||
public function testScheduleInsertTwice()
|
||||
{
|
||||
$user = new CmsUser();
|
||||
$user->username = "beberlei";
|
||||
$user->name = "Benjamin";
|
||||
$user->status = "active";
|
||||
|
||||
$this->_em->getUnitOfWork()->scheduleForInsert($user);
|
||||
|
||||
$this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "Entity Doctrine\Tests\Models\CMS\CmsUser");
|
||||
$this->_em->getUnitOfWork()->scheduleForInsert($user);
|
||||
}
|
||||
|
||||
public function testAddToIdentityMapWithoutIdentity()
|
||||
{
|
||||
$user = new CmsUser();
|
||||
|
||||
$this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "The given entity of type 'Doctrine\Tests\Models\CMS\CmsUser' (Doctrine\Tests\Models\CMS\CmsUser@");
|
||||
$this->_em->getUnitOfWork()->registerManaged($user, array(), array());
|
||||
}
|
||||
|
||||
public function testMarkReadOnlyNonManaged()
|
||||
{
|
||||
$user = new CmsUser();
|
||||
|
||||
$this->setExpectedException("Doctrine\ORM\ORMInvalidArgumentException", "Only managed entities can be marked or checked as read only. But Doctrine\Tests\Models\CMS\CmsUser@");
|
||||
$this->_em->getUnitOfWork()->markReadOnly($user);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user