From 4f9265c85d25697363d147df8f66389a268b3221 Mon Sep 17 00:00:00 2001 From: Alex Pott <alex.a.pott@googlemail.com> Date: Tue, 17 Nov 2015 10:44:05 +0000 Subject: [PATCH] Revert "Issue #2382675 by plach, yched: ContentEntityBase::addTranslation() should not fire hook_entity_create()" This reverts commit 58332b2637d9b2f3f72d34d1e8701d712456eb42. --- .../Core/Config/Entity/ConfigEntityType.php | 18 +++- .../Drupal/Core/Entity/ContentEntityBase.php | 41 ++++++--- .../Core/Entity/ContentEntityStorageBase.php | 52 ++--------- .../Entity/ContentEntityStorageInterface.php | 31 ------- .../Drupal/Core/Entity/ContentEntityType.php | 16 ---- core/lib/Drupal/Core/Entity/EntityType.php | 14 --- .../KeyValueContentEntityStorage.php | 75 ---------------- core/lib/Drupal/Core/Entity/entity.api.php | 88 +++---------------- .../Core/TypedData/TranslatableInterface.php | 8 -- .../Tests/Entity/EntityTranslationTest.php | 2 - .../keyvalue_test/keyvalue_test.module | 2 +- 11 files changed, 66 insertions(+), 281 deletions(-) delete mode 100644 core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php delete mode 100644 core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php index 527a336f3e91..ab94c27f6e6c 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php @@ -69,6 +69,9 @@ public function __construct($definition) { // 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 @@ public function getConfigDependencyKey() { /** * {@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 1e198fe014d4..4f11f1e51227 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -808,13 +808,6 @@ public function hasTranslation($langcode) { return !empty($this->translations[$langcode]['status']); } - /** - * {@inheritdoc} - */ - public function isNewTranslation() { - return $this->translations[$this->activeLangcode]['status'] == static::TRANSLATION_CREATED; - } - /** * {@inheritdoc} */ @@ -829,11 +822,37 @@ public function addTranslation($langcode, array $values = array()) { 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 fb97c818b9d0..2a5475e2f2ad 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\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 @@ protected function doCreate(array $values) { $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 @@ protected function initFieldValues(ContentEntityInterface $entity, array $values 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 f62e0ac64a24..000000000000 --- a/core/lib/Drupal/Core/Entity/ContentEntityStorageInterface.php +++ /dev/null @@ -1,31 +0,0 @@ -<?php - -/** - * @file - * Contains \Drupal\Core\Entity\ContentEntityStorageInterface. - */ - -namespace Drupal\Core\Entity; - -/** - * A storage that supports content entity types. - */ -interface ContentEntityStorageInterface extends DynamicallyFieldableEntityStorageInterface { - - /** - * Constructs a new entity translation object, without permanently saving it. - * - * @param \Drupal\Core\Entity\ContentEntityInterface $entity - * The entity object being translated. - * @param string $langcode - * The translation language code. - * @param array $values - * (optional) An associative array of initial field values keyed by field - * name. If none is provided default values will be applied. - * - * @return \Drupal\Core\Entity\ContentEntityInterface - * A new entity translation object. - */ - public function createTranslation(ContentEntityInterface $entity, $langcode, array $values = []); - -} diff --git a/core/lib/Drupal/Core/Entity/ContentEntityType.php b/core/lib/Drupal/Core/Entity/ContentEntityType.php index 8894f3348bac..0c375a980057 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityType.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityType.php @@ -30,20 +30,4 @@ public function getConfigDependencyKey() { return 'content'; } - /** - * {@inheritdoc} - * - * @see \Drupal\Core\Entity\ContentEntityStorageInterface. - * - * @throws \InvalidArgumentException - * If the provided class does not implement - * \Drupal\Core\Entity\ContentEntityStorageInterface. - */ - protected function checkStorageClass($class) { - $required_interface = ContentEntityStorageInterface::class; - if (!is_subclass_of($class, $required_interface)) { - throw new \InvalidArgumentException("$class does not implement $required_interface"); - } - } - } diff --git a/core/lib/Drupal/Core/Entity/EntityType.php b/core/lib/Drupal/Core/Entity/EntityType.php index d678623d99f0..7072ef5701d6 100644 --- a/core/lib/Drupal/Core/Entity/EntityType.php +++ b/core/lib/Drupal/Core/Entity/EntityType.php @@ -276,9 +276,6 @@ public function __construct($definition) { $this->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 @@ public function getStorageClass() { * {@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 bbff156567ec..000000000000 --- a/core/lib/Drupal/Core/Entity/KeyValueStore/KeyValueContentEntityStorage.php +++ /dev/null @@ -1,75 +0,0 @@ -<?php - -/** - * @file - * Contains \Drupal\Core\Entity\KeyValueStore\KeyValueContentEntityStorage. - */ - -namespace Drupal\Core\Entity\KeyValueStore; - -use Drupal\Core\Entity\ContentEntityInterface; -use Drupal\Core\Entity\ContentEntityStorageInterface; -use Drupal\Core\Field\FieldDefinitionInterface; -use Drupal\Core\Field\FieldStorageDefinitionInterface; - -/** - * Provides a key value backend for content entities. - */ -class KeyValueContentEntityStorage extends KeyValueEntityStorage implements ContentEntityStorageInterface { - - /** - * {@inheritdoc} - */ - public function countFieldData($storage_definition, $as_bool = FALSE) {} - - /** - * {@inheritdoc} - */ - public function hasData() {} - - /** - * {@inheritdoc} - */ - public function purgeFieldData(FieldDefinitionInterface $field_definition, $batch_size) {} - - /** - * {@inheritdoc} - */ - public function finalizePurge(FieldStorageDefinitionInterface $storage_definition) {} - - /** - * {@inheritdoc} - */ - public function onFieldDefinitionCreate(FieldDefinitionInterface $field_definition) {} - - /** - * {@inheritdoc} - */ - public function onFieldDefinitionUpdate(FieldDefinitionInterface $field_definition, FieldDefinitionInterface $original) {} - - /** - * {@inheritdoc} - */ - public function onFieldDefinitionDelete(FieldDefinitionInterface $field_definition) {} - - /** - * {@inheritdoc} - */ - public function onFieldStorageDefinitionCreate(FieldStorageDefinitionInterface $storage_definition) {} - - /** - * {@inheritdoc} - */ - public function onFieldStorageDefinitionUpdate(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original) {} - - /** - * {@inheritdoc} - */ - public function onFieldStorageDefinitionDelete(FieldStorageDefinitionInterface $storage_definition) {} - - /** - * {@inheritdoc} - */ - public function createTranslation(ContentEntityInterface $entity, $langcode, array $values = []) {} - -} diff --git a/core/lib/Drupal/Core/Entity/entity.api.php b/core/lib/Drupal/Core/Entity/entity.api.php index 85989bface2a..8883f78d038e 100644 --- a/core/lib/Drupal/Core/Entity/entity.api.php +++ b/core/lib/Drupal/Core/Entity/entity.api.php @@ -780,9 +780,10 @@ function hook_entity_bundle_delete($entity_type_id, $bundle) { } /** - * Acts when creating a new entity. + * Act on a newly created entity. * - * 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. @@ -791,13 +792,16 @@ function hook_entity_bundle_delete($entity_type_id, $bundle) { * @see hook_ENTITY_TYPE_create() */ function hook_entity_create(\Drupal\Core\Entity\EntityInterface $entity) { - \Drupal::logger('example')->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 f64242c0a96a..f87e7c891576 100644 --- a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php +++ b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php @@ -28,14 +28,6 @@ public function language(); */ 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 a2e9be4c15cc..07d0bd7b5f6c 100644 --- a/core/modules/system/src/Tests/Entity/EntityTranslationTest.php +++ b/core/modules/system/src/Tests/Entity/EntityTranslationTest.php @@ -328,7 +328,6 @@ protected function doTestEntityTranslationAPI($entity_type) { // 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 @@ protected function doTestEntityTranslationAPI($entity_type) { $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 ed0599605856..d8c3666f1b72 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')); } -- GitLab