diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index 0e8e6b8..29b0d31 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -336,11 +336,25 @@ protected function buildBaseFieldDefinitions($entity_type_id) { $entity_type = $this->getDefinition($entity_type_id); $class = $entity_type->getClass(); + // Retrieve base field definitions and assign them the entity type provider. $base_field_definitions = $class::baseFieldDefinitions($entity_type); + $provider = $entity_type->getProvider(); + foreach ($base_field_definitions as $definition) { + $definition->setProvider($provider); + } - // Invoke hook. - $result = $this->moduleHandler->invokeAll('entity_base_field_info', array($entity_type)); - $base_field_definitions = NestedArray::mergeDeep($base_field_definitions, $result); + // Retrieve base field definitions from modules. + foreach ($this->moduleHandler->getImplementations('entity_base_field_info') as $module) { + $module_definitions = $this->moduleHandler->invoke($module, 'entity_base_field_info', array($entity_type)); + if (!empty($module_definitions)) { + // Ensure the provider key actually matches the name of the provider + // defining the field. + foreach ($module_definitions as $field_name => $definition) { + $definition->setProvider($module); + $base_field_definitions[$field_name] = $definition; + } + } + } // Automatically set the field name for non-configurable fields. foreach ($base_field_definitions as $field_name => $base_field_definition) { @@ -410,11 +424,24 @@ protected function buildBundleFieldDefinitions($entity_type_id, $bundle, array $ $class = $entity_type->getClass(); // Allow the entity class to override the base fields. + $provider = $entity_type->getProvider(); $bundle_field_definitions = $class::bundleFieldDefinitions($entity_type, $bundle, $base_field_definitions); + foreach ($bundle_field_definitions as $definition) { + $definition->setProvider($provider); + } - // Invoke 'per bundle' hook. - $result = $this->moduleHandler->invokeAll('entity_bundle_field_info', array($entity_type, $bundle, $base_field_definitions)); - $bundle_field_definitions = NestedArray::mergeDeep($bundle_field_definitions, $result); + // Retrieve base field definitions from modules. + foreach ($this->moduleHandler->getImplementations('entity_bundle_field_info') as $module) { + $module_definitions = $this->moduleHandler->invoke($module, 'entity_bundle_field_info', array($entity_type, $bundle, $base_field_definitions)); + if (!empty($module_definitions)) { + // Ensure the provider key actually matches the name of the provider + // defining the field. + foreach ($module_definitions as $field_name => $definition) { + $definition->setProvider($module); + $bundle_field_definitions[$field_name] = $definition; + } + } + } // Automatically set the field name for non-configurable fields. foreach ($bundle_field_definitions as $field_name => $field_definition) { diff --git a/core/lib/Drupal/Core/Field/FieldDefinition.php b/core/lib/Drupal/Core/Field/FieldDefinition.php index 3968624..6cfec74 100644 --- a/core/lib/Drupal/Core/Field/FieldDefinition.php +++ b/core/lib/Drupal/Core/Field/FieldDefinition.php @@ -151,6 +151,26 @@ public function setSetting($setting_name, $value) { /** * {@inheritdoc} */ + public function getProvider() { + return $this->definition['provider']; + } + + /** + * Sets the name of the provider of this field. + * + * @param string $provider + * The provider name to set. + * + * @return $this + */ + public function setProvider($provider) { + $this->definition['provider'] = $provider; + return $this; + } + + /** + * {@inheritdoc} + */ public function isTranslatable() { return !empty($this->definition['translatable']); } @@ -446,4 +466,25 @@ public static function getReservedColumns() { return array('deleted'); } + /** + * {@inheritdoc} + */ + public function hasCustomStorage() { + return !empty($this->definition['custom_storage']); + } + + /** + * Sets the storage behavior for this field. + * + * @param bool $custom_storage + * Pass FALSE if the storage controller takes care of storing the field, + * TRUE otherwise. + * + * @return $this + */ + public function setCustomStorage($custom_storage) { + $this->definition['custom_storage'] = $custom_storage; + return $this; + } + } diff --git a/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php b/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php index 06de3c6..b0eab20 100644 --- a/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php +++ b/core/lib/Drupal/Core/Field/FieldDefinitionInterface.php @@ -104,6 +104,14 @@ public function getSettings(); public function getSetting($setting_name); /** + * Returns the name of the provider of this field. + * + * @return string + * The provider name; e.g., the module name. + */ + public function getProvider(); + + /** * Returns whether the field is translatable. * * @return bool @@ -328,4 +336,17 @@ public function getSchema(); */ public function getColumns(); + /** + * Returns the storage behavior for this field. + * + * Indicates whether the entity type's storage controller should take care of + * storing the field values or whether it is handled separately; e.g. by the + * module providing the field. + * + * @return bool + * FALSE if the storage controller takes care of storing the field, TRUE + * otherwise. + */ + public function hasCustomStorage(); + } diff --git a/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php b/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php index ae8d4fc..971e246 100644 --- a/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php +++ b/core/modules/field/lib/Drupal/field/Entity/FieldConfig.php @@ -478,6 +478,13 @@ public function getSchema() { /** * {@inheritdoc} */ + public function hasCustomStorage() { + return FALSE; + } + + /** + * {@inheritdoc} + */ public function getColumns() { $schema = $this->getSchema(); // A typical use case for the method is to iterate on the columns, while @@ -576,6 +583,13 @@ public function setTranslatable($translatable) { /** * {@inheritdoc} */ + public function getProvider() { + return 'field'; + } + + /** + * {@inheritdoc} + */ public function getLabel() { return $this->label(); } diff --git a/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php b/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php index 384d76f..e249355 100644 --- a/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php +++ b/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php @@ -501,6 +501,13 @@ public function getSetting($setting_name) { /** * {@inheritdoc} */ + public function getProvider() { + return $this->field->getProvider(); + } + + /** + * {@inheritdoc} + */ public function isTranslatable() { return $this->field->translatable; } @@ -758,4 +765,11 @@ public function getColumns() { return $this->field->getColumns(); } + /** + * {@inheritdoc} + */ + public function hasCustomStorage() { + return $this->field->hasCustomStorage(); + } + } diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php index 4414904..b58336f 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php @@ -553,6 +553,38 @@ public function testGetBaseFieldDefinitionsInvalidDefinition() { } /** + * Tests that getFieldDefinitions() method sets the 'provider' definition key. + * + * @covers ::getFieldDefinitions() + */ + public function testGetFieldDefinitionsProvider() { + $this->setUpEntityWithFieldDefinition(TRUE); + + $module = 'entity_manager_test_module'; + + $field_definition = $this->getMockBuilder('Drupal\Core\Field\FieldDefinitionInterface') + ->getMock(); + + // We expect two calls as the field definition will be returned from both + // base and bundle entity field info hook implementations. + $field_definition + ->expects($this->exactly(2)) + ->method('setProvider') + ->with($this->matches($module)); + + $this->moduleHandler->expects($this->any()) + ->method('getImplementations') + ->will($this->returnValue(array($module))); + + $this->moduleHandler->expects($this->any()) + ->method('invoke') + ->with($this->matches($module)) + ->will($this->returnValue(array($field_definition))); + + $this->entityManager->getFieldDefinitions('test_entity_type', 'test_bundle'); + } + + /** * Prepares an entity that defines a field definition. * * @param bool $custom_invoke_all @@ -587,11 +619,12 @@ protected function setUpEntityWithFieldDefinition($custom_invoke_all = FALSE, $f ->method('bundleFieldDefinitions') ->will($this->returnValue(array())); + $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'); $this->moduleHandler->expects($this->any()) ->method('alter'); if (!$custom_invoke_all) { $this->moduleHandler->expects($this->any()) - ->method('invokeAll') + ->method('getImplementations') ->will($this->returnValue(array())); } diff --git a/core/tests/Drupal/Tests/Core/Entity/FieldDefinitionTest.php b/core/tests/Drupal/Tests/Core/Entity/FieldDefinitionTest.php index 5ddd924..e58bb61 100644 --- a/core/tests/Drupal/Tests/Core/Entity/FieldDefinitionTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/FieldDefinitionTest.php @@ -194,4 +194,26 @@ public function testFieldRequired() { $this->assertFalse($definition->isRequired()); } + /** + * Tests provider. + */ + public function testFieldProvider() { + $definition = FieldDefinition::create($this->fieldType); + $provider = $this->randomName(); + $definition->setProvider($provider); + $this->assertEquals($provider, $definition->getProvider()); + } + + /** + * Tests custom storage. + */ + public function testCustomStorage() { + $definition = FieldDefinition::create($this->fieldType); + $this->assertFalse($definition->hasCustomStorage()); + $definition->setCustomStorage(TRUE); + $this->assertTrue($definition->hasCustomStorage()); + $definition->setCustomStorage(FALSE); + $this->assertFalse($definition->hasCustomStorage()); + } + }