From 381b05e5f1fc0e2022bd85cad90645a2a30693cf Mon Sep 17 00:00:00 2001 From: Nathaniel Catchpole Date: Thu, 7 Aug 2014 11:53:05 +0100 Subject: [PATCH] Issue #2269025 by penyaskito, andypost, grom358, Berdir, mikeegoulding, larowlan: Fixed CommentManager::getAllFields() should have a static cache. --- core/lib/Drupal/Core/Entity/EntityManager.php | 30 ++++++ .../Core/Entity/EntityManagerInterface.php | 16 +++- core/modules/comment/src/CommentManager.php | 19 +--- .../comment/src/CommentManagerInterface.php | 5 - .../comment/tests/src/CommentManagerTest.php | 64 +++++++++++++ .../taxonomy/src/Entity/Vocabulary.php | 6 +- .../Tests/Core/Entity/EntityManagerTest.php | 93 +++++++++++++++++++ 7 files changed, 205 insertions(+), 28 deletions(-) create mode 100644 core/modules/comment/tests/src/CommentManagerTest.php diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index 3fc38fd8d096..f0e90e3b1fc2 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -134,6 +134,16 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa */ protected $fieldMap = array(); + /** + * An array keyed by field type. Each value is an array whose key are entity + * types including arrays in the same form that $fieldMap. + * + * It helps access the mapping between types and fields by the field type. + * + * @var array + */ + protected $fieldMapByFieldType = array(); + /** * Constructs a new Entity plugin manager. * @@ -565,6 +575,25 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa return $this->fieldMap; } + /** + * {@inheritdoc} + */ + public function getFieldMapByFieldType($field_type) { + if (!isset($this->fieldMapByFieldType[$field_type])) { + $filtered_map = array(); + $map = $this->getFieldMap(); + foreach ($map as $entity_type => $fields) { + foreach ($fields as $field_name => $field_info) { + if ($field_info['type'] == $field_type) { + $filtered_map[$entity_type][$field_name] = $field_info; + } + } + } + $this->fieldMapByFieldType[$field_type] = $filtered_map; + } + return $this->fieldMapByFieldType[$field_type]; + } + /** * Builds field storage definitions for an entity type. * @@ -610,6 +639,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa $this->fieldDefinitions = array(); $this->fieldStorageDefinitions = array(); $this->fieldMap = array(); + $this->fieldMapByFieldType = array(); $this->displayModeInfo = array(); $this->extraFields = array(); Cache::deleteTags(array('entity_field_info' => TRUE)); diff --git a/core/lib/Drupal/Core/Entity/EntityManagerInterface.php b/core/lib/Drupal/Core/Entity/EntityManagerInterface.php index 104f7741a6ac..8f4fc27e6a4a 100644 --- a/core/lib/Drupal/Core/Entity/EntityManagerInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityManagerInterface.php @@ -81,7 +81,7 @@ interface EntityManagerInterface extends PluginManagerInterface { public function getFieldStorageDefinitions($entity_type_id); /** - * Collects a lightweight map of fields across bundles. + * Returns a lightweight map of fields across bundles. * * @return array * An array keyed by entity type. Each value is an array which keys are @@ -91,6 +91,20 @@ interface EntityManagerInterface extends PluginManagerInterface { */ public function getFieldMap(); + /** + * Returns a lightweight map of fields across bundles filtered by field type. + * + * @param string $field_type + * The field type to filter by. + * + * @return array + * An array keyed by entity type. Each value is an array which keys are + * field names and value is an array with two entries: + * - type: The field type. + * - bundles: The bundles in which the field appears. + */ + public function getFieldMapByFieldType($field_type); + /** * Creates a new access controller instance. * diff --git a/core/modules/comment/src/CommentManager.php b/core/modules/comment/src/CommentManager.php index a4a11706afbf..f8dac54d874c 100644 --- a/core/modules/comment/src/CommentManager.php +++ b/core/modules/comment/src/CommentManager.php @@ -114,27 +114,10 @@ class CommentManager implements CommentManagerInterface { return array(); } - $map = $this->getAllFields(); + $map = $this->entityManager->getFieldMapByFieldType('comment'); return isset($map[$entity_type_id]) ? $map[$entity_type_id] : array(); } - /** - * {@inheritdoc} - */ - public function getAllFields() { - $map = $this->entityManager->getFieldMap(); - // Build a list of comment fields only. - $comment_fields = array(); - foreach ($map as $entity_type => $data) { - foreach ($data as $field_name => $field_info) { - if ($field_info['type'] == 'comment') { - $comment_fields[$entity_type][$field_name] = $field_info; - } - } - } - return $comment_fields; - } - /** * {@inheritdoc} */ diff --git a/core/modules/comment/src/CommentManagerInterface.php b/core/modules/comment/src/CommentManagerInterface.php index d16dc4f488e1..fc35ddbf284e 100644 --- a/core/modules/comment/src/CommentManagerInterface.php +++ b/core/modules/comment/src/CommentManagerInterface.php @@ -43,11 +43,6 @@ interface CommentManagerInterface { */ public function getFields($entity_type_id); - /** - * Utility function to return all comment fields. - */ - public function getAllFields(); - /** * Utility method to add the default comment field to an entity. * diff --git a/core/modules/comment/tests/src/CommentManagerTest.php b/core/modules/comment/tests/src/CommentManagerTest.php new file mode 100644 index 000000000000..b0011659e00a --- /dev/null +++ b/core/modules/comment/tests/src/CommentManagerTest.php @@ -0,0 +1,64 @@ +getMock('Drupal\Core\Entity\ContentEntityTypeInterface'); + $entity_type->expects($this->any()) + ->method('getClass') + ->will($this->returnValue('Node')); + $entity_type->expects($this->any()) + ->method('isSubclassOf') + ->with('\Drupal\Core\Entity\ContentEntityInterface') + ->will($this->returnValue(TRUE)); + + $entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface'); + + $entity_manager->expects($this->once()) + ->method('getFieldMapByFieldType') + ->will($this->returnValue(array( + 'node' => array( + 'field_foobar' => array( + 'type' => 'comment', + ), + ), + ))); + + $entity_manager->expects($this->any()) + ->method('getDefinition') + ->will($this->returnValue($entity_type)); + + $comment_manager = new CommentManager( + $entity_manager, + $this->getMockBuilder('Drupal\Core\Entity\Query\QueryFactory')->disableOriginalConstructor()->getMock(), + $this->getMock('Drupal\Core\Config\ConfigFactoryInterface'), + $this->getMock('Drupal\Core\StringTranslation\TranslationInterface'), + $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface'), + $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'), + $this->getMock('Drupal\Core\Session\AccountInterface') + ); + $comment_fields = $comment_manager->getFields('node'); + $this->assertArrayHasKey('field_foobar', $comment_fields); + } + +} diff --git a/core/modules/taxonomy/src/Entity/Vocabulary.php b/core/modules/taxonomy/src/Entity/Vocabulary.php index aa47b3a75d2d..3927c348b4cd 100644 --- a/core/modules/taxonomy/src/Entity/Vocabulary.php +++ b/core/modules/taxonomy/src/Entity/Vocabulary.php @@ -102,12 +102,10 @@ class Vocabulary extends ConfigEntityBundleBase implements VocabularyInterface { // Reflect machine name changes in the definitions of existing 'taxonomy' // fields. $field_ids = array(); - $field_map = \Drupal::entityManager()->getFieldMap(); + $field_map = \Drupal::entityManager()->getFieldMapByFieldType('taxonomy_term_reference'); foreach ($field_map as $entity_type => $fields) { foreach ($fields as $field => $info) { - if ($info['type'] == 'taxonomy_term_reference') { - $field_ids[] = $entity_type . '.' . $field; - } + $field_ids[] = $entity_type . '.' . $field; } } diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php index d16dab7305b2..ce1b5734bb5d 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php @@ -1161,6 +1161,99 @@ class EntityManagerTest extends UnitTestCase { $this->assertEquals($expected, $this->entityManager->getFieldMap()); } + /** + * @covers ::getFieldMapByFieldType + */ + public function testGetFieldMapByFieldType() { + // Set up a content entity type. + $entity_type = $this->getMock('Drupal\Core\Entity\ContentEntityTypeInterface'); + $entity = $this->getMockBuilder('Drupal\Tests\Core\Entity\EntityManagerTestEntity') + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $entity_class = get_class($entity); + $entity_type->expects($this->any()) + ->method('getClass') + ->will($this->returnValue($entity_class)); + $entity_type->expects($this->any()) + ->method('getKeys') + ->will($this->returnValue(array())); + $entity_type->expects($this->any()) + ->method('id') + ->will($this->returnValue('test_entity_type')); + $entity_type->expects($this->any()) + ->method('isSubclassOf') + ->with('\Drupal\Core\Entity\ContentEntityInterface') + ->will($this->returnValue(TRUE)); + + // Set up the module handler to return two bundles for the fieldable entity + // type. + $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'); + $this->moduleHandler->expects($this->any()) + ->method('alter'); + $this->moduleHandler->expects($this->any()) + ->method('getImplementations') + ->will($this->returnValue(array())); + $module_implements_value_map = array( + array( + 'entity_bundle_info', array(), + array( + 'test_entity_type' => array( + 'first_bundle' => array(), + 'second_bundle' => array(), + ), + ), + ), + ); + $this->moduleHandler->expects($this->any()) + ->method('invokeAll') + ->will($this->returnValueMap($module_implements_value_map)); + + + // Define an ID field definition as a base field. + $id_definition = $this->getMockBuilder('Drupal\Core\Field\FieldDefinition') + ->disableOriginalConstructor() + ->getMock(); + $id_definition->expects($this->exactly(2)) + ->method('getType') + ->will($this->returnValue('integer')); + $base_field_definitions = array( + 'id' => $id_definition, + ); + $entity_class::$baseFieldDefinitions = $base_field_definitions; + + // Set up a by bundle field definition that only exists on one bundle. + $bundle_definition = $this->getMockBuilder('Drupal\Core\Field\FieldDefinition') + ->disableOriginalConstructor() + ->getMock(); + $bundle_definition->expects($this->once()) + ->method('getType') + ->will($this->returnValue('string')); + $entity_class::$bundleFieldDefinitions = array( + 'test_entity_type' => array( + 'first_bundle' => array(), + 'second_bundle' => array( + 'by_bundle' => $bundle_definition, + ), + ), + ); + + $this->setUpEntityManager(array( + 'test_entity_type' => $entity_type, + )); + + $integerFields = $this->entityManager->getFieldMapByFieldType('integer'); + $this->assertCount(1, $integerFields['test_entity_type']); + $this->assertArrayNotHasKey('non_fieldable', $integerFields); + $this->assertArrayHasKey('id', $integerFields['test_entity_type']); + $this->assertArrayNotHasKey('by_bundle', $integerFields['test_entity_type']); + + $stringFields = $this->entityManager->getFieldMapByFieldType('string'); + $this->assertCount(1, $stringFields['test_entity_type']); + $this->assertArrayNotHasKey('non_fieldable', $stringFields); + $this->assertArrayHasKey('by_bundle', $stringFields['test_entity_type']); + $this->assertArrayNotHasKey('id', $stringFields['test_entity_type']); + } + /** * Gets a mock controller class name. *