diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php index 8180808..0e3c8ba 100644 --- a/core/lib/Drupal/Core/Entity/Entity.php +++ b/core/lib/Drupal/Core/Entity/Entity.php @@ -445,27 +445,37 @@ public static function loadMultiple(array $ids = NULL) { protected static function getEntityTypeFromStaticClass() { $called_class = get_called_class(); $subclasses = 0; + $same_class = 0; $entity_type_id = NULL; + $subclass_entity_type_id = NULL; foreach (\Drupal::entityManager()->getDefinitions() as $entity_type) { - // If an entity type exactly matches the called class, return it. + // Check if this is the same class, throw an exception if there is more + // than one match. if ($entity_type->getClass() == $called_class) { - return $entity_type->id(); + $entity_type_id = $entity_type->id(); + if ($same_class++) { + throw new AmbiguousEntityClassException($called_class); + } } // Check for entity types that are subclasses of the called class, but // throw an exception if we have multiple matches. - elseif ($entity_type->isSubclassOf($called_class)) { - $entity_type_id = $entity_type->id(); + elseif (is_subclass_of($entity_type->getClass(), $called_class)) { + $subclass_entity_type_id = $entity_type->id(); if ($subclasses++) { throw new AmbiguousEntityClassException($called_class); } } } - if (!$entity_type_id) { - throw new NoCorrespondingEntityClassException($called_class); + // Return the matching entity type ID or the subclass match if there is one + // as a secondary priority. + if ($entity_type_id) { + return $entity_type_id; } - - return $entity_type_id; + if ($subclass_entity_type_id) { + return $subclass_entity_type_id; + } + throw new NoCorrespondingEntityClassException($called_class); } /** diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php index 8799760..9e600c6 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php @@ -10,6 +10,7 @@ use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\Entity\Entity; use Drupal\Core\Language\Language; +use Drupal\entity_test\Entity\EntityTest; use Drupal\entity_test\Entity\EntityTestMul; use Drupal\Tests\UnitTestCase; @@ -249,7 +250,6 @@ function setupTestLoad() { // 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)]); $this->entityType = $this->getMockBuilder('\Drupal\Core\Entity\EntityType') ->disableOriginalConstructor() @@ -279,6 +279,7 @@ function setupTestLoad() { /** * @covers ::load + * @covers ::getEntityTypeFromStaticClass * * Tests Entity::load() when called statically on the Entity base class. */ @@ -300,7 +301,8 @@ public function testLoad() { } /** - * @covers ::load() + * @covers ::load + * @covers ::getEntityTypeFromStaticClass * * Tests if an assertion is thrown if Entity::load() is called on a base class * which is subclassed multiple times. @@ -312,7 +314,6 @@ public function testLoadWithAmbiguousSubclasses() { // 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') @@ -340,7 +341,48 @@ public function testLoadWithAmbiguousSubclasses() { } /** - * @covers ::load() + * @covers ::load + * @covers ::getEntityTypeFromStaticClass + * + * Tests if an assertion is thrown if Entity::load() is called on a class + * that matches multiple times. + * + * @expectedException \Drupal\Core\Entity\Exception\AmbiguousEntityClassException + */ + public function testLoadWithAmbiguousClasses() { + // 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('setClass', $methods)]); + + $first_entity_type = $this->getMockBuilder('\Drupal\Core\Entity\EntityType') + ->disableOriginalConstructor() + ->setMethods($methods) + ->getMock(); + $first_entity_type->setClass('Drupal\entity_test\Entity\EntityTest'); + + $second_entity_type = $this->getMockBuilder('\Drupal\Core\Entity\EntityType') + ->disableOriginalConstructor() + ->setMethods($methods) + ->setMockClassName($this->randomName()) + ->getMock(); + $second_entity_type->setClass('Drupal\entity_test\Entity\EntityTest'); + + $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 EntityTest::load() statically and check that it throws an exception. + EntityTest::load(1); + } + + /** + * @covers ::load + * @covers ::getEntityTypeFromStaticClass * * Tests if an assertion is thrown if Entity::load() is called and there are * no subclasses defined that can return entities. @@ -358,6 +400,7 @@ public function testLoadWithNoCorrespondingSubclasses() { /** * @covers ::load + * @covers ::getEntityTypeFromStaticClass * * Tests Entity::load() when called statically on a subclass of Entity. */ @@ -382,6 +425,7 @@ public function testLoadSubClass() { /** * @covers ::loadMultiple + * @covers ::getEntityTypeFromStaticClass * * Tests Entity::loadMultiple() when called statically on the Entity base * class. @@ -406,6 +450,7 @@ public function testLoadMultiple() { /** * @covers ::loadMultiple + * @covers ::getEntityTypeFromStaticClass * * Tests Entity::loadMultiple() when called statically on a subclass of * Entity.