diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php index 527a336f3e9..ab94c27f6e6 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php @@ -69,6 +69,9 @@ class ConfigEntityType extends EntityType implements ConfigEntityTypeInterface { // Always add a default 'uuid' key. $this->entity_keys['uuid'] = 'uuid'; $this->entity_keys['langcode'] = 'langcode'; + if (isset($this->handlers['storage'])) { + $this->checkStorageClass($this->handlers['storage']); + } $this->handlers += array( 'storage' => 'Drupal\Core\Config\Entity\ConfigEntityStorage', ); @@ -132,12 +135,23 @@ class ConfigEntityType extends EntityType implements ConfigEntityTypeInterface { /** * {@inheritdoc} * - * @see \Drupal\Core\Config\Entity\ConfigEntityStorage. - * * @throws \Drupal\Core\Config\Entity\Exception\ConfigEntityStorageClassException * Exception thrown when the provided class is not an instance of * \Drupal\Core\Config\Entity\ConfigEntityStorage. */ + public function setStorageClass($class) { + $this->checkStorageClass($class); + parent::setStorageClass($class); + } + + /** + * Checks that the provided class is an instance of ConfigEntityStorage. + * + * @param string $class + * The class to check. + * + * @see \Drupal\Core\Config\Entity\ConfigEntityStorage. + */ protected function checkStorageClass($class) { if (!is_a($class, 'Drupal\Core\Config\Entity\ConfigEntityStorage', TRUE)) { throw new ConfigEntityStorageClassException("$class is not \\Drupal\\Core\\Config\\Entity\\ConfigEntityStorage or it does not extend it"); diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php index 1e198fe014d..4f11f1e5122 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -808,13 +808,6 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C return !empty($this->translations[$langcode]['status']); } - /** - * {@inheritdoc} - */ - public function isNewTranslation() { - return $this->translations[$this->activeLangcode]['status'] == static::TRANSLATION_CREATED; - } - /** * {@inheritdoc} */ @@ -829,11 +822,37 @@ abstract class ContentEntityBase extends Entity implements \IteratorAggregate, C throw new \InvalidArgumentException("The entity cannot be translated since it is language neutral ({$this->defaultLangcode})."); } - // Initialize the translation object. - /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */ - $storage = $this->entityManager()->getStorage($this->getEntityTypeId()); + // Instantiate a new empty entity so default values will be populated in the + // specified language. + $entity_type = $this->getEntityType(); + + $default_values = array( + $entity_type->getKey('bundle') => $this->bundle(), + $this->langcodeKey => $langcode, + ); + $entity = $this->entityManager() + ->getStorage($this->getEntityTypeId()) + ->create($default_values); + + foreach ($entity as $name => $field) { + if (!isset($values[$name]) && !$field->isEmpty()) { + $values[$name] = $field->getValue(); + } + } + $values[$this->langcodeKey] = $langcode; + $values[$this->defaultLangcodeKey] = FALSE; + $this->translations[$langcode]['status'] = static::TRANSLATION_CREATED; - return $storage->createTranslation($this, $langcode, $values); + $translation = $this->getTranslation($langcode); + $definitions = $translation->getFieldDefinitions(); + + foreach ($values as $name => $value) { + if (isset($definitions[$name]) && $definitions[$name]->isTranslatable()) { + $translation->values[$name][$langcode] = $value; + } + } + + return $translation; } /** diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php index fb97c818b9d..2a5475e2f2a 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php @@ -13,10 +13,7 @@ use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -/** - * Base class for content entity storage handlers. - */ -abstract class ContentEntityStorageBase extends EntityStorageBase implements ContentEntityStorageInterface { +abstract class ContentEntityStorageBase extends EntityStorageBase implements DynamicallyFieldableEntityStorageInterface { /** * The entity bundle key. @@ -90,32 +87,13 @@ abstract class ContentEntityStorageBase extends EntityStorageBase implements Con $bundle = $values[$this->bundleKey]; } $entity = new $this->entityClass(array(), $this->entityTypeId, $bundle); - $this->initFieldValues($entity, $values); - return $entity; - } - /** - * Initializes field values. - * - * @param \Drupal\Core\Entity\ContentEntityInterface $entity - * An entity object. - * @param array $values - * (optional) An associative array of initial field values keyed by field - * name. If none is provided default values will be applied. - * @param array $field_names - * (optional) An associative array of field names to be initialized. If none - * is provided all fields will be initialized. - */ - protected function initFieldValues(ContentEntityInterface $entity, array $values = [], array $field_names = []) { - // Populate field values. foreach ($entity as $name => $field) { - if (!$field_names || isset($field_names[$name])) { - if (isset($values[$name])) { - $entity->$name = $values[$name]; - } - elseif (!array_key_exists($name, $values)) { - $entity->get($name)->applyDefaultValue(); - } + if (isset($values[$name])) { + $entity->$name = $values[$name]; + } + elseif (!array_key_exists($name, $values)) { + $entity->get($name)->applyDefaultValue(); } unset($values[$name]); } @@ -124,23 +102,7 @@ abstract class ContentEntityStorageBase extends EntityStorageBase implements Con foreach ($values as $name => $value) { $entity->$name = $value; } - - // Make sure modules can alter field initial values. - $this->invokeHook('field_values_init', $entity); - } - - /** - * {@inheritdoc} - */ - public function createTranslation(ContentEntityInterface $entity, $langcode, array $values = []) { - $translation = $entity->getTranslation($langcode); - $definitions = array_filter($translation->getFieldDefinitions(), function(FieldDefinitionInterface $definition) { return $definition->isTranslatable(); }); - $field_names = array_map(function(FieldDefinitionInterface $definition) { return $definition->getName(); }, $definitions); - $values[$this->langcodeKey] = $langcode; - $values[$this->getEntityType()->getKey('default_langcode')] = FALSE; - $this->initFieldValues($translation, $values, $field_names); - $this->invokeHook('translation_create', $entity); - return $translation; + return $entity; } /** diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php deleted file mode 100644 index f62e0ac64a2..00000000000 --- a/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php +++ /dev/null @@ -1,31 +0,0 @@ -handlers += array( 'access' => 'Drupal\Core\Entity\EntityAccessControlHandler', ); - if (isset($this->handlers['storage'])) { - $this->checkStorageClass($this->handlers['storage']); - } // Automatically add the EntityChanged constraint if the entity type tracks // the changed time. @@ -462,20 +459,9 @@ class EntityType implements EntityTypeInterface { * {@inheritdoc} */ public function setStorageClass($class) { - $this->checkStorageClass($class); $this->handlers['storage'] = $class; } - /** - * Checks that the provided class is an instance of ConfigEntityStorage. - * - * @param string $class - * The class to check. - */ - protected function checkStorageClass($class) { - // Nothing to check by default. - } - /** * {@inheritdoc} */ diff --git a/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php b/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php deleted file mode 100644 index bbff156567e..00000000000 --- a/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php +++ /dev/null @@ -1,75 +0,0 @@ -info('Entity created: @label', ['@label' => $entity->label()]); + if ($entity instanceof FieldableEntityInterface && !$entity->foo->value) { + $entity->foo->value = 'some_initial_value'; + } } /** - * Acts when creating a new entity of a specific type. + * Act on a newly created entity of a specific type. * - * This hook runs after a new entity object has just been instantiated. + * This hook runs after a new entity object has just been instantiated. It can + * be used to set initial values, e.g. to provide defaults. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object. @@ -806,7 +810,9 @@ function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) { * @see hook_entity_create() */ function hook_ENTITY_TYPE_create(\Drupal\Core\Entity\EntityInterface $entity) { - \Drupal::logger('example')->info('ENTITY_TYPE created: @label', ['@label' => $entity->label()]); + if (!$entity->foo->value) { + $entity->foo->value = 'some_initial_value'; + } } /** @@ -1005,38 +1011,6 @@ function hook_ENTITY_TYPE_update(Drupal\Core\Entity\EntityInterface $entity) { ->execute(); } -/** - * Acts when creating a new entity translation. - * - * This hook runs after a new entity translation object has just been - * instantiated. - * - * @param \Drupal\Core\Entity\EntityInterface $translation - * The entity object. - * - * @ingroup entity_crud - * @see hook_ENTITY_TYPE_translation_create() - */ -function hook_entity_translation_create(\Drupal\Core\Entity\EntityInterface $translation) { - \Drupal::logger('example')->info('Entity translation created: @label', ['@label' => $translation->label()]); -} - -/** - * Acts when creating a new entity translation of a specific type. - * - * This hook runs after a new entity translation object has just been - * instantiated. - * - * @param \Drupal\Core\Entity\EntityInterface $translation - * The entity object. - * - * @ingroup entity_crud - * @see hook_entity_translation_create() - */ -function hook_ENTITY_TYPE_translation_create(\Drupal\Core\Entity\EntityInterface $translation) { - \Drupal::logger('example')->info('ENTITY_TYPE translation created: @label', ['@label' => $translation->label()]); -} - /** * Respond to creation of a new entity translation. * @@ -1912,44 +1886,6 @@ function hook_entity_field_access_alter(array &$grants, array $context) { } } -/** - * Acts when initializing a fieldable entity object. - * - * This hook runs after a new entity object or a new entity translation object - * has just been instantiated. It can be used to set initial values, e.g. to - * provide defaults. - * - * @param \Drupal\Core\Entity\FieldableEntityInterface $entity - * The entity object. - * - * @ingroup entity_crud - * @see hook_ENTITY_TYPE_field_values_init() - */ -function hook_entity_field_values_init(\Drupal\Core\Entity\FieldableEntityInterface $entity) { - if ($entity instanceof \Drupal\Core\Entity\ContentEntityInterface && !$entity->foo->value) { - $entity->foo->value = 'some_initial_value'; - } -} - -/** - * Acts when initializing a fieldable entity object. - * - * This hook runs after a new entity object or a new entity translation object - * has just been instantiated. It can be used to set initial values, e.g. to - * provide defaults. - * - * @param \Drupal\Core\Entity\FieldableEntityInterface $entity - * The entity object. - * - * @ingroup entity_crud - * @see hook_entity_field_values_init() - */ -function hook_ENTITY_TYPE_field_values_init(\Drupal\Core\Entity\FieldableEntityInterface $entity) { - if (!$entity->foo->value) { - $entity->foo->value = 'some_initial_value'; - } -} - /** * Exposes "pseudo-field" components on content entities. * diff --git a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php index f64242c0a96..f87e7c89157 100644 --- a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php +++ b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php @@ -28,14 +28,6 @@ interface TranslatableInterface { */ public function isDefaultTranslation(); - /** - * Checks whether the translation is new. - * - * @return bool - * TRUE if the translation is new, FALSE otherwise. - */ - public function isNewTranslation(); - /** * Returns the languages the data is translated to. * diff --git a/core/modules/system/src/Tests/Entity/EntityTranslationTest.php b/core/modules/system/src/Tests/Entity/EntityTranslationTest.php index a2e9be4c15c..07d0bd7b5f6 100644 --- a/core/modules/system/src/Tests/Entity/EntityTranslationTest.php +++ b/core/modules/system/src/Tests/Entity/EntityTranslationTest.php @@ -328,7 +328,6 @@ class EntityTranslationTest extends EntityLanguageTestBase { // Verify that we obtain the entity object itself when we attempt to // retrieve a translation referring to it. $translation = $entity->getTranslation(LanguageInterface::LANGCODE_NOT_SPECIFIED); - $this->assertFalse($translation->isNewTranslation(), 'Existing translations are not marked as new.'); $this->assertIdentical($entity, $translation, 'The translation object corresponding to a non-default language is the entity object itself when the entity is language-neutral.'); $entity->{$langcode_key}->value = $default_langcode; $translation = $entity->getTranslation($default_langcode); @@ -354,7 +353,6 @@ class EntityTranslationTest extends EntityLanguageTestBase { $entity->name->value = $name; $name_translated = $langcode . '_' . $this->randomMachineName(); $translation = $entity->addTranslation($langcode); - $this->assertTrue($translation->isNewTranslation(), 'Newly added translations are marked as new.'); $this->assertNotIdentical($entity, $translation, 'The entity and the translation object differ from one another.'); $this->assertTrue($entity->hasTranslation($langcode), 'The new translation exists.'); $this->assertEqual($translation->language()->getId(), $langcode, 'The translation language matches the specified one.'); diff --git a/core/modules/system/tests/modules/keyvalue_test/keyvalue_test.module b/core/modules/system/tests/modules/keyvalue_test/keyvalue_test.module index ed059960585..d8c3666f1b7 100644 --- a/core/modules/system/tests/modules/keyvalue_test/keyvalue_test.module +++ b/core/modules/system/tests/modules/keyvalue_test/keyvalue_test.module @@ -11,7 +11,7 @@ function keyvalue_test_entity_type_alter(array &$entity_types) { /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */ if (isset($entity_types['entity_test_label'])) { - $entity_types['entity_test_label']->setStorageClass('Drupal\Core\Entity\KeyValueStore\KeyValueContentEntityStorage'); + $entity_types['entity_test_label']->setStorageClass('Drupal\Core\Entity\KeyValueStore\KeyValueEntityStorage'); $entity_keys = $entity_types['entity_test_label']->getKeys(); $entity_types['entity_test_label']->set('entity_keys', $entity_keys + array('uuid' => 'uuid')); }