commit 8429c5d53c44d0bfe6bcb851cbcaa5478a132319 Author: Pieter Frenssen Date: Thu Mar 27 16:11:45 2014 +0100 2190313-38 diff --git a/core/lib/Drupal/Core/Entity/AmbiguousEntityClassException.php b/core/lib/Drupal/Core/Entity/AmbiguousEntityClassException.php new file mode 100644 index 0000000..3b798bf --- /dev/null +++ b/core/lib/Drupal/Core/Entity/AmbiguousEntityClassException.php @@ -0,0 +1,34 @@ +getStorageController(static::getEntityTypeFromStaticClass())->load($id); + return \Drupal::entityManager()->getStorage(static::getEntityTypeFromStaticClass())->load($id); } /** * {@inheritdoc} */ public static function loadMultiple(array $ids = NULL) { - return \Drupal::entityManager()->getStorageController(static::getEntityTypeFromStaticClass())->loadMultiple($ids); + return \Drupal::entityManager()->getStorage(static::getEntityTypeFromStaticClass())->loadMultiple($ids); } /** @@ -405,7 +405,10 @@ public static function loadMultiple(array $ids = NULL) { * @return string * The entity type ID. * - * @throws \RuntimeException + * @throws \Drupal\Core\Entity\AmbiguousEntityClassException + * Thrown when multiple subclasses correspond to the called class. + * @throws \Drupal\Core\Entity\NoCorrespondingEntityClassException + * Thrown when no entity class corresponds to the called class. */ protected static function getEntityTypeFromStaticClass() { $called_class = get_called_class(); @@ -421,13 +424,13 @@ protected static function getEntityTypeFromStaticClass() { elseif ($entity_type->isSubclassOf($called_class)) { $entity_type_id = $entity_type->id(); if ($subclasses++) { - throw new \RuntimeException(sprintf('Multiple subclasses provide an entity type for %s.', $called_class)); + throw new AmbiguousEntityClassException($called_class); } } } if (!$entity_type_id) { - throw new \RuntimeException(sprintf('The %s class does not correspond to an entity type.', $called_class)); + throw new NoCorrespondingEntityClassException($called_class); } return $entity_type_id; diff --git a/core/lib/Drupal/Core/Entity/NoCorrespondingEntityClassException.php b/core/lib/Drupal/Core/Entity/NoCorrespondingEntityClassException.php new file mode 100644 index 0000000..45e4854 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/NoCorrespondingEntityClassException.php @@ -0,0 +1,30 @@ +getMockBuilder('Drupal\Core\Entity\Entity') + // Use an entity type object which has the methods enabled which are being + // called by the protected method Entity::getEntityTypeFromStaticClass(). + $methods = get_class_methods('Drupal\Core\Entity\EntityType'); + unset($methods[array_search('getClass', $methods)]); + unset($methods[array_search('isSubclassOf', $methods)]); + unset($methods[array_search('setClass', $methods)]); + $entity_type = $this->getMockBuilder('\Drupal\Core\Entity\EntityType') ->disableOriginalConstructor() ->setMethods($methods) ->getMock(); + // Base our mocked entity on a real entity class so we can test if calling + // Entity::load() on the base class will bubble up to an actual entity. + $entity_type_id = 'entity_test_mul'; + $methods = get_class_methods('Drupal\entity_test\Entity\EntityTestMul'); + unset($methods[array_search('load', $methods)]); + $test_entity = $this->getMockBuilder('Drupal\entity_test\Entity\EntityTestMul') + ->disableOriginalConstructor() + ->setMethods($methods) + ->getMock(); $test_entity->id = 1; - $test_entity->type = $this->randomName(); + $entity_type->setClass(get_class($test_entity)); - $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageControllerInterface'); + $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface'); $storage->expects($this->once()) ->method('load') ->with(1) ->will($this->returnValue($test_entity)); $this->entityManager->expects($this->once()) - ->method('getStorageController') - ->with($test_entity->type) + ->method('getStorage') + ->with($entity_type_id) ->will($this->returnValue($storage)); $this->entityManager->expects($this->once()) ->method('getDefinitions') - ->will($this->returnValue(array($test_entity->type => $this->entityType))); - $this->entityType->expects($this->once()) - ->method('getClass') - ->will($this->returnValue(get_class($test_entity))); - $this->entityType->expects($this->once()) - ->method('isSubClassOf') - ->with('Drupal\Core\Entity\Entity') - ->will($this->returnValue(TRUE)); - $this->entityType->expects($this->once()) + ->will($this->returnValue(array($entity_type_id => $entity_type))); + $entity_type->expects($this->any()) ->method('id') - ->will($this->returnValue($test_entity->type)); + ->will($this->returnValue($entity_type_id)); // Call Entity::load statically and check that it returns the mock entity. $this->assertSame($test_entity, Entity::load(1)); } /** + * @covers ::load() + * + * Tests if an assertion is thrown if Entity::load() is called on a base class + * which is subclassed multiple times. + */ + public function testLoadWithAmbiguousSubclasses() { + // Use an entity type object which has the methods enabled which are being + // called by the protected method Entity::getEntityTypeFromStaticClass(). + $methods = get_class_methods('Drupal\Core\Entity\EntityType'); + unset($methods[array_search('getClass', $methods)]); + unset($methods[array_search('isSubclassOf', $methods)]); + unset($methods[array_search('setClass', $methods)]); + + $first_entity_type = $this->getMockBuilder('\Drupal\Core\Entity\EntityType') + ->disableOriginalConstructor() + ->setMethods($methods) + ->getMock(); + $first_entity_type->setClass('Drupal\entity_test\Entity\EntityTestMul'); + + $second_entity_type = $this->getMockBuilder('\Drupal\Core\Entity\EntityType') + ->disableOriginalConstructor() + ->setMethods($methods) + ->setMockClassName($this->randomName()) + ->getMock(); + $second_entity_type->setClass('Drupal\entity_test\Entity\EntityTestMulRev'); + + $this->entityManager->expects($this->once()) + ->method('getDefinitions') + ->will($this->returnValue(array( + 'entity_test_mul' => $first_entity_type, + 'entity_test_mul_rev' => $second_entity_type, + ))); + + // Call Entity::load statically and check that it throws an exception. + try { + Entity::load(1); + $this->fail('An assertion is thrown when multiple subclasses are able to provide entities.'); + } + catch (AmbiguousEntityClassException $e) { + } + } + + /** + * @covers ::load() + * + * Tests if an assertion is thrown if Entity::load() is called and there are + * no subclasses defined that can return entities. + */ + public function testLoadWithNoCorrespondingSubclasses() { + $this->entityManager->expects($this->once()) + ->method('getDefinitions') + ->will($this->returnValue(array())); + + // Call Entity::load statically and check that it throws an exception. + try { + Entity::load(1); + $this->fail('An assertion is thrown when no classes are able to provide entities.'); + } + catch (NoCorrespondingEntityClassException $e) { + } + } + + /** * @covers ::load * * Tests Entity::load() when called statically on a subclass of Entity. */ public function testLoadSubClass() { - // Entity::load() is a wrapper for EntityStorageController::loadMultiple(). - // Test that the same mock entity object that is returned by loadMultiple() - // on the storage controller will be returned by Entity::load(). + // Entity::load() is a wrapper for EntityStorage::load(). Test that the same + // mock entity object that is returned by load() on the storage controller + // will be returned by Entity::load(). + $entity_type_id = $this->randomName(); $methods = get_class_methods('Drupal\Core\Entity\Entity'); unset($methods[array_search('load', $methods)]); $test_entity = $this->getMockBuilder('Drupal\Core\Entity\Entity') @@ -292,22 +361,21 @@ public function testLoadSubClass() { ->setMethods($methods) ->getMock(); $test_entity->id = 1; - $test_entity->type = $this->randomName(); // Mock the methods called by Entity::load() and // Entity::getEntityTypeFromStaticClass(). - $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageControllerInterface'); + $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface'); $storage->expects($this->once()) ->method('load') ->with(1) ->will($this->returnValue($test_entity)); $this->entityManager->expects($this->once()) - ->method('getStorageController') - ->with($test_entity->type) + ->method('getStorage') + ->with($entity_type_id) ->will($this->returnValue($storage)); $this->entityManager->expects($this->once()) ->method('getDefinitions') - ->will($this->returnValue(array($test_entity->type => $this->entityType))); + ->will($this->returnValue(array($entity_type_id => $this->entityType))); $this->entityType->expects($this->once()) ->method('getClass') ->will($this->returnValue(get_class($test_entity))); @@ -315,7 +383,7 @@ public function testLoadSubClass() { ->method('isSubClassOf'); $this->entityType->expects($this->once()) ->method('id') - ->will($this->returnValue($test_entity->type)); + ->will($this->returnValue($entity_type_id)); // Call Entity::load statically on the subclass and check that it returns // the mock entity. @@ -330,9 +398,10 @@ public function testLoadSubClass() { * class. */ public function testLoadMultiple() { - // Entity::load() is a wrapper for EntityStorageController::loadMultiple(). - // Test that the same mock entity object that is returned by loadMultiple() - // on the storage controller will be returned by Entity::load(). + // Entity::load() is a wrapper for EntityStorage::loadMultiple(). Test that + // the same mock entity object that is returned by loadMultiple() on the + // storage controller will be returned by Entity::load(). + $entity_type_id = $this->randomName(); $methods = get_class_methods('Drupal\Core\Entity\Entity'); unset($methods[array_search('loadMultiple', $methods)]); $test_entity = $this->getMockBuilder('Drupal\Core\Entity\Entity') @@ -340,22 +409,21 @@ public function testLoadMultiple() { ->setMethods($methods) ->getMock(); $test_entity->id = 1; - $test_entity->type = $this->randomName(); // Mock the methods called by Entity::loadMultiple() and // Entity::getEntityTypeFromStaticClass(). - $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageControllerInterface'); + $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface'); $storage->expects($this->once()) ->method('loadMultiple') ->with(array(1)) ->will($this->returnValue(array(1 => $test_entity))); $this->entityManager->expects($this->once()) - ->method('getStorageController') - ->with($test_entity->type) + ->method('getStorage') + ->with($entity_type_id) ->will($this->returnValue($storage)); $this->entityManager->expects($this->once()) ->method('getDefinitions') - ->will($this->returnValue(array($test_entity->type => $this->entityType))); + ->will($this->returnValue(array($entity_type_id => $this->entityType))); $this->entityType->expects($this->once()) ->method('getClass') ->will($this->returnValue(get_class($test_entity))); @@ -363,9 +431,9 @@ public function testLoadMultiple() { ->method('isSubClassOf') ->with('Drupal\Core\Entity\Entity') ->will($this->returnValue(TRUE)); - $this->entityType->expects($this->once()) + $this->entityType->expects($this->any()) ->method('id') - ->will($this->returnValue($test_entity->type)); + ->will($this->returnValue($entity_type_id)); // Call Entity::loadMultiple statically and check that it returns the mock // entity. @@ -380,9 +448,11 @@ public function testLoadMultiple() { * Entity. */ public function testLoadMultipleSubClass() { - // Entity::load() is a wrapper for EntityStorageController::loadMultiple(). - // Test that the same mock entity object that is returned by loadMultiple() - // on the storage controller will be returned by Entity::load(). + // Entity::load() is a wrapper for EntityStorage::loadMultiple(). Test that + // the same mock entity object that is returned by loadMultiple() on the + // storage controller will be returned by Entity::load(). + $entity_type_id = $this->randomName(); + $methods = get_class_methods('Drupal\Core\Entity\Entity'); unset($methods[array_search('loadMultiple', $methods)]); $test_entity = $this->getMockBuilder('Drupal\Core\Entity\Entity') @@ -390,22 +460,21 @@ public function testLoadMultipleSubClass() { ->setMethods($methods) ->getMock(); $test_entity->id = 1; - $test_entity->type = $this->randomName(); // Mock the methods called by Entity::loadMultiple() and // Entity::getEntityTypeFromStaticClass(). - $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageControllerInterface'); + $storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface'); $storage->expects($this->once()) ->method('loadMultiple') ->with(array(1)) ->will($this->returnValue(array(1 => $test_entity))); $this->entityManager->expects($this->once()) - ->method('getStorageController') - ->with($test_entity->type) + ->method('getStorage') + ->with($entity_type_id) ->will($this->returnValue($storage)); $this->entityManager->expects($this->once()) ->method('getDefinitions') - ->will($this->returnValue(array($test_entity->type => $this->entityType))); + ->will($this->returnValue(array($entity_type_id => $this->entityType))); $this->entityType->expects($this->once()) ->method('getClass') ->will($this->returnValue(get_class($test_entity))); @@ -413,7 +482,7 @@ public function testLoadMultipleSubClass() { ->method('isSubClassOf'); $this->entityType->expects($this->once()) ->method('id') - ->will($this->returnValue($test_entity->type)); + ->will($this->returnValue($entity_type_id)); // Call Entity::loadMultiple statically and check that it returns the mock // entity.