From ef0cb6e091ec5f8066b2dab9d93560434120d8d3 Mon Sep 17 00:00:00 2001 From: Alex Pott Date: Fri, 27 Feb 2015 11:47:51 +0000 Subject: [PATCH] Issue #2405469 by yched, googletorp, amateescu, larowlan, Berdir: FileFormatterBase should extend EntityReferenceFormatterBase --- .../EntityReferenceFormatterBase.php | 63 +++++++++++++++---- ...AccessFormatterControlHandlerInterface.php | 30 +++++++++ .../FieldFormatter/FileFormatterBase.php | 43 +++++-------- .../FieldFormatter/GenericFileFormatter.php | 29 +++++---- .../FieldFormatter/RSSEnclosureFormatter.php | 23 +++---- .../Field/FieldFormatter/TableFormatter.php | 23 +++---- .../FieldFormatter/UrlPlainFormatter.php | 6 +- .../Tests/FileFieldFormatterAccessTest.php | 38 +++++++++++ .../file/tests/file_test/file_test.module | 11 ++++ .../src/FileTestAccessControlHandler.php | 27 ++++++++ .../Field/FieldFormatter/ImageFormatter.php | 51 ++++++++------- .../FieldFormatter/ImageFormatterBase.php | 52 ++++++++------- .../src/Tests/ImageFieldDefaultImagesTest.php | 16 ++--- .../ResponsiveImageFormatter.php | 13 +++- 14 files changed, 282 insertions(+), 143 deletions(-) create mode 100644 core/modules/file/src/FileAccessFormatterControlHandlerInterface.php create mode 100644 core/modules/file/src/Tests/FileFieldFormatterAccessTest.php create mode 100644 core/modules/file/tests/file_test/src/FileTestAccessControlHandler.php diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceFormatterBase.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceFormatterBase.php index f8dbf13f2a5..25c802c8fe6 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceFormatterBase.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceFormatterBase.php @@ -7,7 +7,8 @@ namespace Drupal\Core\Field\Plugin\Field\FieldFormatter; -use Drupal\Core\Field\FieldItemListInterface; +use Drupal\Core\Field\EntityReferenceFieldItemListInterface; +use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem; use Drupal\Core\Field\FormatterBase; use Drupal\Core\TypedData\TranslatableInterface; @@ -17,15 +18,26 @@ use Drupal\Core\TypedData\TranslatableInterface; abstract class EntityReferenceFormatterBase extends FormatterBase { /** - * Returns the accessible and translated entities for view. + * Returns the referenced entities for display. * - * @param \Drupal\Core\Field\FieldItemListInterface $items + * The method takes care of: + * - checking entity access, + * - placing the entities in the language expected for display. + * It is thus strongly recommended that formatters use it in their + * implementation of viewElements($items) rather than dealing with $items + * directly. + * + * For each entity, the EntityReferenceItem by which the entity is referenced + * is available in $entity->_referringItem. This is useful for field types + * that store additional values next to the reference itself. + * + * @param \Drupal\Core\Field\EntityReferenceFieldItemListInterface $items * The item list. * * @return \Drupal\Core\Entity\EntityInterface[] - * The entities to view. + * The array of referenced entities to display, keyed by delta. */ - protected function getEntitiesToView(FieldItemListInterface $items) { + protected function getEntitiesToView(EntityReferenceFieldItemListInterface $items) { $entities = array(); $parent_entity_langcode = $items->getEntity()->language()->getId(); @@ -39,8 +51,10 @@ abstract class EntityReferenceFormatterBase extends FormatterBase { $entity = $entity->getTranslation($parent_entity_langcode); } - // Check entity access. - if ($entity->access('view')) { + // Check entity access if needed. + if (!$this->needsAccessCheck($item) || $entity->access('view')) { + // Add the referring item, in case the formatter needs it. + $entity->_referringItem = $items[$delta]; $entities[$delta] = $entity; } } @@ -56,10 +70,9 @@ abstract class EntityReferenceFormatterBase extends FormatterBase { * viewed. */ public function prepareView(array $entities_items) { - // Load the existing (non-autocreate) entities. For performance, we want to - // use a single "multiple entity load" to load all the entities for the - // multiple "entity reference item lists" that are being displayed. We thus - // cannot use + // Collect entity IDs to load. For performance, we want to use a single + // "multiple entity load" to load all the entities for the multiple + // "entity reference item lists" being displayed. We thus cannot use // \Drupal\Core\Field\EntityReferenceFieldItemList::referencedEntities(). $ids = array(); foreach ($entities_items as $items) { @@ -69,7 +82,7 @@ abstract class EntityReferenceFormatterBase extends FormatterBase { // contains a valid entity ready for display. All items are initialized // at FALSE. $item->_loaded = FALSE; - if ($item->target_id !== NULL) { + if ($this->needsEntityLoad($item)) { $ids[] = $item->target_id; } } @@ -94,4 +107,30 @@ abstract class EntityReferenceFormatterBase extends FormatterBase { } } + /** + * Returns whether the entity referenced by an item needs to be loaded. + * + * @param \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $item + * The item to check. + * + * @return bool + * TRUE if the entity needs to be loaded. + */ + protected function needsEntityLoad(EntityReferenceItem $item) { + return !$item->hasNewEntity(); + } + + /** + * Returns whether entity access should be checked. + * + * @param \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $item + * The item to check. + * + * @return bool + * TRUE if entity access should be checked. + */ + protected function needsAccessCheck(EntityReferenceItem $item) { + return TRUE; + } + } diff --git a/core/modules/file/src/FileAccessFormatterControlHandlerInterface.php b/core/modules/file/src/FileAccessFormatterControlHandlerInterface.php new file mode 100644 index 00000000000..98d3a08e382 --- /dev/null +++ b/core/modules/file/src/FileAccessFormatterControlHandlerInterface.php @@ -0,0 +1,30 @@ +isDisplayed() && !empty($item->target_id)) { - // Load the files from the files table. - $fids[] = $item->target_id; - } - } - } - - if ($fids) { - $files = file_load_multiple($fids); - - foreach ($entities_items as $items) { - /** @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $item */ - foreach ($items as $item) { - // If the file does not exist, mark the entire item as empty. - if (!empty($item->target_id) && !$item->hasNewEntity()) { - $item->entity = isset($files[$item->target_id]) ? $files[$item->target_id] : NULL; - } - } - } - } + protected function needsEntityLoad(EntityReferenceItem $item) { + return parent::needsEntityLoad($item) && $item->isDisplayed(); } + + /** + * {@inheritdoc} + */ + protected function needsAccessCheck(EntityReferenceItem $item) { + // Only check access if the current file access control handler explicitly + // opts in by implementing FileAccessFormatterControlHandlerInterface. + $access_handler_class = $item->entity->getEntityType()->getHandlerClass('access'); + return is_subclass_of($access_handler_class, '\Drupal\file\FileAccessFormatterControlHandlerInterface'); + } + } diff --git a/core/modules/file/src/Plugin/Field/FieldFormatter/GenericFileFormatter.php b/core/modules/file/src/Plugin/Field/FieldFormatter/GenericFileFormatter.php index cdbf1c28006..cb917eb13f8 100644 --- a/core/modules/file/src/Plugin/Field/FieldFormatter/GenericFileFormatter.php +++ b/core/modules/file/src/Plugin/Field/FieldFormatter/GenericFileFormatter.php @@ -28,21 +28,20 @@ class GenericFileFormatter extends FileFormatterBase { public function viewElements(FieldItemListInterface $items) { $elements = array(); - foreach ($items as $delta => $item) { - if ($item->isDisplayed() && $item->entity) { - $elements[$delta] = array( - '#theme' => 'file_link', - '#file' => $item->entity, - '#description' => $item->description, - ); - // Pass field item attributes to the theme function. - if (isset($item->_attributes)) { - $elements[$delta] += array('#attributes' => array()); - $elements[$delta]['#attributes'] += $item->_attributes; - // Unset field item attributes since they have been included in the - // formatter output and should not be rendered in the field template. - unset($item->_attributes); - } + foreach ($this->getEntitiesToView($items) as $delta => $file) { + $item = $file->_referringItem; + $elements[$delta] = array( + '#theme' => 'file_link', + '#file' => $file, + '#description' => $item->description, + ); + // Pass field item attributes to the theme function. + if (isset($item->_attributes)) { + $elements[$delta] += array('#attributes' => array()); + $elements[$delta]['#attributes'] += $item->_attributes; + // Unset field item attributes since they have been included in the + // formatter output and should not be rendered in the field template. + unset($item->_attributes); } } if (!empty($elements)) { diff --git a/core/modules/file/src/Plugin/Field/FieldFormatter/RSSEnclosureFormatter.php b/core/modules/file/src/Plugin/Field/FieldFormatter/RSSEnclosureFormatter.php index 73e049440ca..c3247022cc8 100644 --- a/core/modules/file/src/Plugin/Field/FieldFormatter/RSSEnclosureFormatter.php +++ b/core/modules/file/src/Plugin/Field/FieldFormatter/RSSEnclosureFormatter.php @@ -29,21 +29,16 @@ class RSSEnclosureFormatter extends FileFormatterBase { $entity = $items->getEntity(); // Add the first file as an enclosure to the RSS item. RSS allows only one // enclosure per item. See: http://en.wikipedia.org/wiki/RSS_enclosure - foreach ($items as $item) { - if ($item->isDisplayed() && $item->entity) { - $file = $item->entity; - $entity->rss_elements[] = array( - 'key' => 'enclosure', - 'attributes' => array( - 'url' => file_create_url($file->getFileUri()), - 'length' => $file->getSize(), - 'type' => $file->getMimeType(), - ), - ); - break; - } + foreach ($this->getEntitiesToView($items) as $delta => $file) { + $entity->rss_elements[] = array( + 'key' => 'enclosure', + 'attributes' => array( + 'url' => file_create_url($file->getFileUri()), + 'length' => $file->getSize(), + 'type' => $file->getMimeType(), + ), + ); } - } } diff --git a/core/modules/file/src/Plugin/Field/FieldFormatter/TableFormatter.php b/core/modules/file/src/Plugin/Field/FieldFormatter/TableFormatter.php index f05f89ff9fe..460450dec8c 100644 --- a/core/modules/file/src/Plugin/Field/FieldFormatter/TableFormatter.php +++ b/core/modules/file/src/Plugin/Field/FieldFormatter/TableFormatter.php @@ -28,22 +28,19 @@ class TableFormatter extends FileFormatterBase { public function viewElements(FieldItemListInterface $items) { $elements = array(); - if (!$items->isEmpty()) { - + if ($files = $this->getEntitiesToView($items)) { $header = array(t('Attachment'), t('Size')); $rows = array(); - foreach ($items as $delta => $item) { - if ($item->isDisplayed() && $item->entity) { - $rows[] = array( - array( - 'data' => array( - '#theme' => 'file_link', - '#file' => $item->entity, - ), + foreach ($files as $delta => $file) { + $rows[] = array( + array( + 'data' => array( + '#theme' => 'file_link', + '#file' => $file, ), - array('data' => format_size($item->entity->getSize())), - ); - } + ), + array('data' => format_size($file->getSize())), + ); } $elements[0] = array(); diff --git a/core/modules/file/src/Plugin/Field/FieldFormatter/UrlPlainFormatter.php b/core/modules/file/src/Plugin/Field/FieldFormatter/UrlPlainFormatter.php index 978f95b1825..26b78f7222f 100644 --- a/core/modules/file/src/Plugin/Field/FieldFormatter/UrlPlainFormatter.php +++ b/core/modules/file/src/Plugin/Field/FieldFormatter/UrlPlainFormatter.php @@ -28,10 +28,8 @@ class UrlPlainFormatter extends FileFormatterBase { public function viewElements(FieldItemListInterface $items) { $elements = array(); - foreach ($items as $delta => $item) { - if ($item->isDisplayed() && $item->entity) { - $elements[$delta] = array('#markup' => empty($item->entity) ? '' : file_create_url($item->entity->getFileUri())); - } + foreach ($this->getEntitiesToView($items) as $delta => $file) { + $elements[$delta] = array('#markup' => file_create_url($file->getFileUri())); } return $elements; diff --git a/core/modules/file/src/Tests/FileFieldFormatterAccessTest.php b/core/modules/file/src/Tests/FileFieldFormatterAccessTest.php new file mode 100644 index 00000000000..749525a897f --- /dev/null +++ b/core/modules/file/src/Tests/FileFieldFormatterAccessTest.php @@ -0,0 +1,38 @@ +randomMachineName()); + $this->createFileField($field_name, 'node', $type_name); + \Drupal::state()->set('file_test_alternate_access_handler', TRUE); + \Drupal::entityManager()->clearCachedDefinitions(); + $test_file = $this->getTestFile('text'); + $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); + $this->drupalGet('node/' . $nid); + $this->assertTrue(\Drupal::state()->get('file_access_formatter_check', FALSE)); + } + +} diff --git a/core/modules/file/tests/file_test/file_test.module b/core/modules/file/tests/file_test/file_test.module index 6ee2ecc3217..2c0b21ed389 100644 --- a/core/modules/file/tests/file_test/file_test.module +++ b/core/modules/file/tests/file_test/file_test.module @@ -333,3 +333,14 @@ function file_test_file_scan_callback($filepath = NULL) { function file_test_file_scan_callback_reset() { drupal_static_reset('file_test_file_scan_callback'); } + +/** + * Implements hook_entity_info_alter(). + */ +function file_test_entity_type_alter(&$entity_types) { + if (\Drupal::state()->get('file_test_alternate_access_handler', FALSE)) { + /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */ + $entity_types['file'] + ->setAccessClass('Drupal\file_test\FileTestAccessControlHandler'); + } +} diff --git a/core/modules/file/tests/file_test/src/FileTestAccessControlHandler.php b/core/modules/file/tests/file_test/src/FileTestAccessControlHandler.php new file mode 100644 index 00000000000..0b1edbd7d38 --- /dev/null +++ b/core/modules/file/tests/file_test/src/FileTestAccessControlHandler.php @@ -0,0 +1,27 @@ +set('file_access_formatter_check', TRUE); + return parent::checkAccess($entity, $operation, $langcode, $account); + } + +} diff --git a/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php b/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php index dd34fc4811d..38a163c0ebe 100644 --- a/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php +++ b/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php @@ -167,8 +167,14 @@ class ImageFormatter extends ImageFormatterBase implements ContainerFactoryPlugi */ public function viewElements(FieldItemListInterface $items) { $elements = array(); - $url = NULL; + $files = $this->getEntitiesToView($items); + // Early opt-out if the field is empty. + if (empty($files)) { + return $elements; + } + + $url = NULL; $image_link_setting = $this->getSetting('image_link'); // Check if the formatter involves a link. if ($image_link_setting == 'content') { @@ -190,29 +196,28 @@ class ImageFormatter extends ImageFormatterBase implements ContainerFactoryPlugi $cache_tags = $image_style->getCacheTags(); } - foreach ($items as $delta => $item) { - if ($item->entity) { - if (isset($link_file)) { - $image_uri = $item->entity->getFileUri(); - $url = Url::fromUri(file_create_url($image_uri)); - } - - // Extract field item attributes for the theme function, and unset them - // from the $item so that the field template does not re-render them. - $item_attributes = $item->_attributes; - unset($item->_attributes); - - $elements[$delta] = array( - '#theme' => 'image_formatter', - '#item' => $item, - '#item_attributes' => $item_attributes, - '#image_style' => $image_style_setting, - '#url' => $url, - '#cache' => array( - 'tags' => $cache_tags, - ), - ); + foreach ($files as $delta => $file) { + if (isset($link_file)) { + $image_uri = $file->getFileUri(); + $url = Url::fromUri(file_create_url($image_uri)); } + + // Extract field item attributes for the theme function, and unset them + // from the $item so that the field template does not re-render them. + $item = $file->_referringItem; + $item_attributes = $item->_attributes; + unset($item->_attributes); + + $elements[$delta] = array( + '#theme' => 'image_formatter', + '#item' => $item, + '#item_attributes' => $item_attributes, + '#image_style' => $image_style_setting, + '#url' => $url, + '#cache' => array( + 'tags' => $cache_tags, + ), + ); } return $elements; diff --git a/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatterBase.php b/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatterBase.php index a78d2dba06f..dd8348ef652 100644 --- a/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatterBase.php +++ b/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatterBase.php @@ -7,6 +7,7 @@ namespace Drupal\image\Plugin\Field\FieldFormatter; +use Drupal\Core\Field\EntityReferenceFieldItemListInterface; use Drupal\field\FieldConfigInterface; use Drupal\file\Plugin\Field\FieldFormatter\FileFormatterBase; @@ -18,33 +19,36 @@ abstract class ImageFormatterBase extends FileFormatterBase { /** * {@inheritdoc} */ - public function prepareView(array $entities_items) { - parent::prepareView($entities_items); + protected function getEntitiesToView(EntityReferenceFieldItemListInterface $items) { + // Add the default image if needed. + if ($items->isEmpty()) { + $default_image = $this->getFieldSetting('default_image'); + // If we are dealing with a configurable field, look in both + // instance-level and field-level settings. + if (empty($default_image['uuid']) && $this->fieldDefinition instanceof FieldConfigInterface) { + $default_image = $this->fieldDefinition->getFieldStorageDefinition()->getSetting('default_image'); + } - // If there are no files specified at all, use the default. - foreach ($entities_items as $items) { - if ($items->isEmpty()) { - // Add the default image if one is found. - $default_image = $this->getFieldSetting('default_image'); - // If we are dealing with a configurable field, look in both - // instance-level and field-level settings. - if (empty($default_image['uuid']) && $this->fieldDefinition instanceof FieldConfigInterface) { - $default_image = $this->fieldDefinition->getFieldStorageDefinition()->getSetting('default_image'); - } - - if (!empty($default_image['uuid']) && ($file = \Drupal::entityManager()->loadEntityByUuid('file', $default_image['uuid']))) { - $items->setValue(array(array( - 'is_default' => TRUE, - 'alt' => $default_image['alt'], - 'title' => $default_image['title'], - 'width' => $default_image['width'], - 'height' => $default_image['height'], - 'entity' => $file, - 'target_id' => $file->id(), - ))); - } + if (!empty($default_image['uuid']) && $file = \Drupal::entityManager()->loadEntityByUuid('file', $default_image['uuid'])) { + // Clone the FieldItemList into a runtime-only object for the formatter, + // so that the fallback image can be rendered without affecting the + // field values in the entity being rendered. + $items = clone $items; + $items->setValue(array( + 'target_id' => $file->id(), + 'alt' => $default_image['alt'], + 'title' => $default_image['title'], + 'width' => $default_image['width'], + 'height' => $default_image['height'], + 'entity' => $file, + '_loaded' => TRUE, + '_is_default' => TRUE, + )); + $file->_referringItem = $items[0]; } } + + return parent::getEntitiesToView($items); } } diff --git a/core/modules/image/src/Tests/ImageFieldDefaultImagesTest.php b/core/modules/image/src/Tests/ImageFieldDefaultImagesTest.php index ce1e15f4987..6efc84d1746 100644 --- a/core/modules/image/src/Tests/ImageFieldDefaultImagesTest.php +++ b/core/modules/image/src/Tests/ImageFieldDefaultImagesTest.php @@ -154,7 +154,7 @@ class ImageFieldDefaultImagesTest extends ImageFieldTestBase { $article = $this->drupalCreateNode(array('type' => 'article')); $article_built = $this->drupalBuildEntityView($article); $this->assertEqual( - $article_built[$field_name]['#items'][0]->target_id, + $article_built[$field_name][0]['#item']->target_id, $default_images['field']->id(), format_string( 'A new article node without an image has the expected default image file ID of @fid.', @@ -166,7 +166,7 @@ class ImageFieldDefaultImagesTest extends ImageFieldTestBase { $page = $this->drupalCreateNode(array('type' => 'page')); $page_built = $this->drupalBuildEntityView($page); $this->assertEqual( - $page_built[$field_name]['#items'][0]->target_id, + $page_built[$field_name][0]['#item']->target_id, $default_images['field2']->id(), format_string( 'A new page node without an image has the expected default image file ID of @fid.', @@ -196,7 +196,7 @@ class ImageFieldDefaultImagesTest extends ImageFieldTestBase { $article_built = $this->drupalBuildEntityView($article = $node_storage->load($article->id())); $page_built = $this->drupalBuildEntityView($page = $node_storage->load($page->id())); $this->assertEqual( - $article_built[$field_name]['#items'][0]->target_id, + $article_built[$field_name][0]['#item']->target_id, $default_images['field']->id(), format_string( 'An existing article node without an image has the expected default image file ID of @fid.', @@ -204,7 +204,7 @@ class ImageFieldDefaultImagesTest extends ImageFieldTestBase { ) ); $this->assertEqual( - $page_built[$field_name]['#items'][0]->target_id, + $page_built[$field_name][0]['#item']->target_id, $default_images['field2']->id(), format_string( 'An existing page node without an image has the expected default image file ID of @fid.', @@ -235,7 +235,7 @@ class ImageFieldDefaultImagesTest extends ImageFieldTestBase { // Confirm the article uses the new default. $this->assertEqual( - $article_built[$field_name]['#items'][0]->target_id, + $article_built[$field_name][0]['#item']->target_id, $default_images['field_new']->id(), format_string( 'An existing article node without an image has the expected default image file ID of @fid.', @@ -244,7 +244,7 @@ class ImageFieldDefaultImagesTest extends ImageFieldTestBase { ); // Confirm the page remains unchanged. $this->assertEqual( - $page_built[$field_name]['#items'][0]->target_id, + $page_built[$field_name][0]['#item']->target_id, $default_images['field2']->id(), format_string( 'An existing page node without an image has the expected default image file ID of @fid.', @@ -275,7 +275,7 @@ class ImageFieldDefaultImagesTest extends ImageFieldTestBase { $page_built = $this->drupalBuildEntityView($page = $node_storage->load($page->id())); // Confirm the article uses the new field (not field) default. $this->assertEqual( - $article_built[$field_name]['#items'][0]->target_id, + $article_built[$field_name][0]['#item']->target_id, $default_images['field_new']->id(), format_string( 'An existing article node without an image has the expected default image file ID of @fid.', @@ -284,7 +284,7 @@ class ImageFieldDefaultImagesTest extends ImageFieldTestBase { ); // Confirm the page remains unchanged. $this->assertEqual( - $page_built[$field_name]['#items'][0]->target_id, + $page_built[$field_name][0]['#item']->target_id, $default_images['field2']->id(), format_string( 'An existing page node without an image has the expected default image file ID of @fid.', diff --git a/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php b/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php index e0fbb91d62e..bc8cb9388cc 100644 --- a/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php +++ b/core/modules/responsive_image/src/Plugin/Field/FieldFormatter/ResponsiveImageFormatter.php @@ -175,6 +175,13 @@ class ResponsiveImageFormatter extends ImageFormatterBase implements ContainerFa */ public function viewElements(FieldItemListInterface $items) { $elements = array(); + $files = $this->getEntitiesToView($items); + + // Early opt-out if the field is empty. + if (empty($files)) { + return $elements; + } + $url = NULL; // Check if the formatter involves a link. if ($this->getSetting('image_link') == 'content') { @@ -220,10 +227,10 @@ class ResponsiveImageFormatter extends ImageFormatterBase implements ContainerFa $cache_tags = Cache::mergeTags($cache_tags, $image_style->getCacheTags()); } - foreach ($items as $delta => $item) { + foreach ($files as $delta => $file) { // Link the element to the original file. if (isset($link_file)) { - $url = Url::fromUri(file_create_url($item->entity->getFileUri())); + $url = Url::fromUri(file_create_url($file->getFileUri())); } $elements[$delta] = array( '#theme' => 'responsive_image_formatter', @@ -232,7 +239,7 @@ class ResponsiveImageFormatter extends ImageFormatterBase implements ContainerFa 'core/picturefill', ), ), - '#item' => $item, + '#item' => $file->_referringItem, '#image_style' => $fallback_image_style, '#responsive_image_style_id' => $responsive_image_style ? $responsive_image_style->id() : '', '#url' => $url,