diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php index 3d260ed..684840e 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -3,7 +3,6 @@ namespace Drupal\Core\Entity; use Drupal\Component\Utility\SafeMarkup; -use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\Plugin\DataType\EntityReference; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Language\Language; @@ -52,16 +51,6 @@ protected $fieldDefinitions; /** - * Local cache for field definitions filtered by setting. - * - * @see ContentEntityBase::getFieldDefinitionsFilteredBySetting() - * - * @var array - */ - protected $fieldDefinitionsFilteredBySetting; - - - /** * Local cache for the available language objects. * * @var \Drupal\Core\Language\LanguageInterface[] @@ -171,7 +160,7 @@ * * @var bool */ - protected $serializeCompleteEntityStructure = FALSE; + public $serializeCompleteEntityStructure = FALSE; /** * {@inheritdoc} @@ -452,74 +441,9 @@ protected function clearTranslationCache() { } /** - * Gets an array of field definitions of all contained fields filtered by the - * given setting and its value. - * - * @param string $setting - * The name of the setting. - * @param string $value - * The value of the setting. - * - * @return \Drupal\Core\Field\FieldDefinitionInterface[] - * An array of field definitions, keyed by field name. - * - * @see \Drupal\Core\Entity\EntityFieldManagerInterface::getFieldDefinitions() - */ - protected function getFieldDefinitionsFilteredBySetting($setting, $value) { - if (!isset($this->fieldDefinitionsFilteredBySetting[$setting][$value])) { - // Initialize the combination of setting and a value in case there is - // nothing found to not iterate over the field definitions again. - $this->fieldDefinitionsFilteredBySetting[$setting][$value] = []; - foreach ($this->getFieldDefinitions() as $name => $definition) { - if ($definition->getSetting($setting) == $value) { - $this->fieldDefinitionsFilteredBySetting[$setting][$value][$name] = $definition; - } - } - } - - return $this->fieldDefinitionsFilteredBySetting[$setting][$value]; - } - - /** * {@inheritdoc} */ public function __sleep() { - if ($this->serializeCompleteEntityStructure) { - $langcodes = $this->getTranslationLangcodes(); - foreach ($this->getFieldDefinitionsFilteredBySetting('serialize_embedded_entities', TRUE) as $name => $definition) { - // Initialize not yet initialized fields for which the computed field - // values have to be serialized. - $iterate_langcodes = $definition->isTranslatable() ? $langcodes : [LanguageInterface::LANGCODE_DEFAULT]; - foreach ($iterate_langcodes as $langcode) { - if (!isset($this->fields[$name][$langcode])) { - $this->getTranslatedField($name, $langcode); - } - } - - // Get the values of instantiated field objects. - foreach ($this->fields[$name] as $langcode => $field) { - // TODO remove this check after https://www.drupal.org/node/2828133 - // gets in. - if (!$definition->isTranslatable() && ($langcode != LanguageInterface::LANGCODE_DEFAULT)) { - continue; - } - - // Get the values together with the referenced entities and flag the - // referenced entities for deep serialization as well. - $this->values[$name][$langcode] = $field->getValue(TRUE); - foreach ($this->values[$name][$langcode] as $delta => $values) { - // We can assign protected properties of other objects only if they - // have the same class as ancestor. - $referenced_entities = array_filter($values, function ($val) {return is_object($val) && is_subclass_of($val, ContentEntityBase::class);}); - foreach ($referenced_entities as $referenced_entity) { - $referenced_entity->serializeCompleteEntityStructure = TRUE; - } - } - unset($this->fields[$name]); - } - } - } - // Get the values of instantiated field objects, only serialize the values. foreach ($this->fields as $name => $fields) { foreach ($fields as $langcode => $field) { @@ -539,6 +463,10 @@ public function __sleep() { */ public function __wakeup() { parent::__wakeup(); + // If the entity has been serialized with the flag + // "serializeCompleteEntityStructure" set to TRUE then the entity has been + // deeply serialized and in order to allow normal serialization on the + // unserialized entity we have to unset the flag. $this->serializeCompleteEntityStructure = FALSE; } @@ -546,8 +474,14 @@ public function __wakeup() { * {@inheritdoc} */ public function serializeWithCompleteStructure() { + // When running a deep serialization the flag + // "serializeCompleteEntityStructure" has to be set in order to serialize + // referenced entities as well, which are referenced by field having the + // setting "serialize_embedded_entities" set to TRUE. $this->serializeCompleteEntityStructure = TRUE; $serialized = serialize($this); + // After the deep serialization is ready we have to unset the flag in order + // to allow for normal serialization afterwards. $this->serializeCompleteEntityStructure = FALSE; return $serialized; } @@ -1013,22 +947,16 @@ public function getTranslationStatus($langcode) { /** * {@inheritdoc} */ - public function getTranslationLangcodes($include_default = TRUE) { + public function getTranslationLanguages($include_default = TRUE) { $translations = array_filter($this->translations, function($translation) { return $translation['status']; }); unset($translations[LanguageInterface::LANGCODE_DEFAULT]); if ($include_default) { $translations[$this->defaultLangcode] = TRUE; } - return array_keys($translations); - } - /** - * {@inheritdoc} - */ - public function getTranslationLanguages($include_default = TRUE) { // Now load language objects based upon translation langcodes. - return array_intersect_key($this->getLanguages(), array_flip($this->getTranslationLangcodes($include_default))); + return array_intersect_key($this->getLanguages(), $translations); } /** diff --git a/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php b/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php index d21ac96..7b4435c 100644 --- a/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php +++ b/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php @@ -13,6 +13,36 @@ class EntityReferenceFieldItemList extends FieldItemList implements EntityRefere /** * {@inheritdoc} */ + public function getValue($include_computed = FALSE) { + $values = array(); + $serialize_embedded_entities = $this->isDeepSerializationActive(); + if (!$include_computed) { + $include_computed = $serialize_embedded_entities; + } + foreach ($this->list as $delta => $item) { + $values[$delta] = $item->getValue($include_computed); + // If deep serialization is active then flag the referenced entities for + // deep serialization as well. + if (isset($values[$delta]['entity']) && $serialize_embedded_entities) { + $values[$delta]['entity']->serializeCompleteEntityStructure = TRUE; + } + } + return $values; + } + + /** + * Checks if deep serialization is active. + * + * @return bool + * TRUE if deep serialization is active, FALSE otherwise. + */ + protected function isDeepSerializationActive() { + return $this->getFieldDefinition()->getSetting('serialize_embedded_entities') && $this->getEntity()->serializeCompleteEntityStructure; + } + + /** + * {@inheritdoc} + */ public function getConstraints() { $constraints = parent::getConstraints(); $constraint_manager = $this->getTypedDataManager()->getValidationConstraintManager(); diff --git a/core/tests/Drupal/KernelTests/Core/Entity/ContentEntitySerializationTest.php b/core/tests/Drupal/KernelTests/Core/Entity/ContentEntitySerializationTest.php index efdc981..00c325e 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/ContentEntitySerializationTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/ContentEntitySerializationTest.php @@ -109,7 +109,8 @@ protected function doTestSerialization($deep_serialization, $field_name) { $this->entityTestMulStorage->resetCache(); - $entity_level_zero = unserialize($entity_level_zero->serializeWithCompleteStructure()); + $serialized_entity = $entity_level_zero->serializeWithCompleteStructure(); + $entity_level_zero = unserialize($serialized_entity); $this->assertEquals('entity level zero', $entity_level_zero->label()); $this->assertEquals($deep_serialization ? 'entity level one' : $initial_entity_name, $entity_level_zero->$field_name->entity->label()); $this->assertEquals($deep_serialization ? 'entity level two' : $initial_entity_name, $entity_level_zero->$field_name->entity->$field_name->entity->label());