1
0
mirror of synced 2025-01-30 03:51:43 +03:00

Improved and extracted UnitOfWork error messages

This commit is contained in:
Benjamin Eberlei 2011-10-22 12:40:12 +02:00
parent 3aea203b9c
commit 5392737de4
3 changed files with 164 additions and 21 deletions

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

View File

@ -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)]);
}

View File

@ -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);
}
}