diff --git a/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php index 87b86c0..e91dfb9 100644 --- a/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php +++ b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php @@ -89,8 +89,23 @@ protected function loadFieldItems(array $entities, $age) { $instances = field_info_instances($this->entityType, $entity->bundle()); foreach ($entity->getTranslationLanguages() as $langcode => $language) { $translation = $entity->getTranslation($langcode); - foreach ($instances as $instance) { - $data[$langcode][$instance['field_name']] = $translation->{$instance['field_name']}->getValue(); + foreach ($instances as $field_name => $instance) { + $items = $translation->get($field_name); + if (!$items->isEmpty()) { + // First collect all non-computed properties. + $field_data = $items->getValue(); + // Then individually collect cacheable computed properties. All + // items have the same properties, so we optimize by iterating on + // the properties of the first item. + foreach ($items->offsetGet(0)->getPropertyDefinitions() as $property => $definition) { + if (!empty($definition['computed']) && !empty($definition['cache'])) { + foreach ($items as $delta => $item) { + $field_data[$delta][$property] = $item->get($property)->getValue(); + } + } + } + $data[$langcode][$field_name] = $field_data; + } } } $cid = "field:{$this->entityType}:$id"; diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php index bbc0d7f..7dda25d 100644 --- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php +++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php @@ -103,7 +103,11 @@ public function createInstance($plugin_id, array $configuration, $name = NULL, $ * - list: Whether the data is multi-valued, i.e. a list of data items. * Defaults to FALSE. * - computed: A boolean specifying whether the data value is computed by - * the object, e.g. depending on some other values. + * the object, e.g. depending on some other values. Defaults to FALSE. + * - cache: (only supported for FieldItem objects) A boolean specifying + * whether the value should be cached as part of the field values cache. + * This only applies to computed properties since the field cache always + * includes non-computed properties. Defaults to FALSE. * - read-only: A boolean specifying whether the data is read-only. Defaults * to TRUE for computed properties, to FALSE otherwise. * - class: If set and 'list' is FALSE, the class to use for creating the diff --git a/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItemBase.php b/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItemBase.php index 54630fd..06e7153 100644 --- a/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItemBase.php +++ b/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItemBase.php @@ -40,6 +40,7 @@ public function getPropertyDefinitions() { 'label' => t('Processed text'), 'description' => t('The text value with the text format applied.'), 'computed' => TRUE, + 'cache' => TRUE, 'class' => '\Drupal\text\TextProcessed', 'settings' => array( 'text source' => 'value', diff --git a/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextWithSummaryItem.php b/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextWithSummaryItem.php index 8d5c9fb..f06dea0 100644 --- a/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextWithSummaryItem.php +++ b/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextWithSummaryItem.php @@ -51,6 +51,7 @@ public function getPropertyDefinitions() { 'label' => t('Processed summary text'), 'description' => t('The summary text value with the text format applied.'), 'computed' => TRUE, + 'cache' => TRUE, 'class' => '\Drupal\text\TextProcessed', 'settings' => array( 'text source' => 'summary', diff --git a/core/modules/text/lib/Drupal/text/Tests/TextWithSummaryItemTest.php b/core/modules/text/lib/Drupal/text/Tests/TextWithSummaryItemTest.php index ef9a7df..f3808c9 100644 --- a/core/modules/text/lib/Drupal/text/Tests/TextWithSummaryItemTest.php +++ b/core/modules/text/lib/Drupal/text/Tests/TextWithSummaryItemTest.php @@ -119,8 +119,30 @@ function testProcessedCache() { $entity->name->value = $this->randomName(); $entity->save(); - // Inject values into the cache to make sure that these are used as-is and - // not re-calculated. + // Check that the processed values are correctly computed. + $this->assertEqual($entity->summary_field->processed, $value); + $this->assertEqual($entity->summary_field->summary_processed, $summary); + + // Load the entity and check that the field cache contains the expected + // data. + $entity = entity_load($entity_type, $entity->id()); + $cache = cache('field')->get("field:$entity_type:" . $entity->id()); + $this->assertEqual($cache->data, array( + Language::LANGCODE_DEFAULT => array( + 'summary_field' => array( + 0 => array( + 'value' => $value, + 'summary' => $summary, + 'format' => 'plain_text', + 'processed' => $value, + 'summary_processed' => $summary, + ), + ), + ), + )); + + // Inject fake processed values into the cache to make sure that these are + // used as-is and not re-calculated when the entity is loaded. $data = array( Language::LANGCODE_DEFAULT => array( 'summary_field' => array( @@ -135,8 +157,7 @@ function testProcessedCache() { ), ); cache('field')->set("field:$entity_type:" . $entity->id(), $data); - - $entity = entity_load($entity_type, $entity->id()); + $entity = entity_load($entity_type, $entity->id(), TRUE); $this->assertEqual($entity->summary_field->processed, 'Cached processed value'); $this->assertEqual($entity->summary_field->summary_processed, 'Cached summary processed value'); diff --git a/core/modules/text/lib/Drupal/text/TextProcessed.php b/core/modules/text/lib/Drupal/text/TextProcessed.php index f3c65e2..bbf0fd0 100644 --- a/core/modules/text/lib/Drupal/text/TextProcessed.php +++ b/core/modules/text/lib/Drupal/text/TextProcessed.php @@ -47,7 +47,12 @@ public function getValue($langcode = NULL) { $item = $this->getParent(); $text = $item->{($this->definition['settings']['text source'])}; - if ($item->getFieldDefinition()->getFieldSetting('text_processing')) { + + // Avoid running check_markup() or check_plain() on empty strings. + if (!isset($text) || $text === '') { + $this->processed = ''; + } + elseif ($item->getFieldDefinition()->getFieldSetting('text_processing')) { $this->processed = check_markup($text, $item->format, $item->getLangcode()); } else {