diff --git a/core/modules/image/src/Entity/ImageStyle.php b/core/modules/image/src/Entity/ImageStyle.php index bacc230..85a640b 100644 --- a/core/modules/image/src/Entity/ImageStyle.php +++ b/core/modules/image/src/Entity/ImageStyle.php @@ -126,6 +126,9 @@ public static function postDelete(EntityStorageInterface $storage, array $entiti foreach ($entities as $style) { // Flush cached media for the deleted style. $style->flush(); + // Clear the replacement ID, if one has been previously stored. + /** @var \Drupal\image\ImageStyleStorageInterface $storage */ + $storage->clearReplacementId($style->id()); } } @@ -367,7 +370,9 @@ public function addImageEffect(array $configuration) { * {@inheritdoc} */ public function getReplacementID() { - return NULL; + /** @var \Drupal\image\ImageStyleStorageInterface $storage */ + $storage = $this->entityManager()->getStorage($this->getEntityTypeId()); + return $storage->getReplacementId($this->id()); } /** diff --git a/core/modules/image/src/Form/ImageStyleDeleteForm.php b/core/modules/image/src/Form/ImageStyleDeleteForm.php index 019560b..41cc3d9 100644 --- a/core/modules/image/src/Form/ImageStyleDeleteForm.php +++ b/core/modules/image/src/Form/ImageStyleDeleteForm.php @@ -37,7 +37,7 @@ public function form(array $form, FormStateInterface $form_state) { // optionally pickup a replacement. if (count($replacement_styles) > 1) { $form['warning'] = [ - '#markup' => $this->t("There are components relying on %style image style. You may select another style to replace it in all components settings. If you don't provide a replacement, those components will be disabled. In this case you'll need to revisit the form and view displays an reconfigure the widgets and formatters.", ['%style' => $this->entity->label()]), + '#markup' => $this->t("There are components relying on %style image style. You may select another style to replace it in all components settings. If you don't provide a replacement, those components will be disabled. In this case you'll need to revisit the form and view displays and reconfigure the widgets and formatters.", ['%style' => $this->entity->label()]), ]; $form['replacement'] = [ '#title' => $this->t('Replacement style'), @@ -48,7 +48,7 @@ public function form(array $form, FormStateInterface $form_state) { } else { $form['warning'] = [ - '#markup' => $this->t("There are components relying on %style image style and will be disabled. You'll need to revisit the form and view displays an reconfigure the widgets and formatters.", ['%style' => $this->entity->label()]), + '#markup' => $this->t("There are components relying on %style image style and will be disabled. You'll need to revisit the form and view displays and reconfigure the widgets and formatters.", ['%style' => $this->entity->label()]), ]; } } diff --git a/core/modules/image/src/ImageStyleInterface.php b/core/modules/image/src/ImageStyleInterface.php index fcdd5bd..6868254 100644 --- a/core/modules/image/src/ImageStyleInterface.php +++ b/core/modules/image/src/ImageStyleInterface.php @@ -19,7 +19,10 @@ * * @return null * - * @deprecated in 8.0.x, will be removed in 8.1.x. + * @deprecated in 8.0.x, will be removed in 9.0.x. Use + * \Drupal\image\ImageStyleStorageInterface::getReplacementId() instead. + * + * @see \Drupal\image\ImageStyleStorageInterface::getReplacementId() */ public function getReplacementID(); diff --git a/core/modules/image/src/ImageStyleStorage.php b/core/modules/image/src/ImageStyleStorage.php index 70ca277..0176fad 100644 --- a/core/modules/image/src/ImageStyleStorage.php +++ b/core/modules/image/src/ImageStyleStorage.php @@ -29,7 +29,14 @@ public function setReplacementId($name, $replacement) { * {@inheritdoc} */ public function getReplacementId($name) { - return array_key_exists($name, $this->replacement) ? $this->replacement[$name] : NULL; + return isset($this->replacement[$name]) ? $this->replacement[$name] : NULL; + } + + /** + * {@inheritdoc} + */ + public function clearReplacementId($name) { + unset($this->replacement[$name]); } } diff --git a/core/modules/image/src/ImageStyleStorageInterface.php b/core/modules/image/src/ImageStyleStorageInterface.php index 518d95c..e9b3744 100644 --- a/core/modules/image/src/ImageStyleStorageInterface.php +++ b/core/modules/image/src/ImageStyleStorageInterface.php @@ -39,4 +39,16 @@ public function setReplacementId($name, $replacement); */ public function getReplacementId($name); + /** + * Clears a replacement ID from the storage. + * + * The method clears the value previously stored with ::setReplacementId(). + * + * @param string $name + * The ID of the image style to be replaced. + * + * @see \Drupal\image\ImageStyleStorageInterface::setReplacementId(). + */ + public function clearReplacementId($name); + } diff --git a/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php b/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php index 0d3100f..2df32cf 100644 --- a/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php +++ b/core/modules/image/src/Plugin/Field/FieldFormatter/ImageFormatter.php @@ -42,7 +42,7 @@ class ImageFormatter extends ImageFormatterBase implements ContainerFactoryPlugi /** * The image style entity storage. * - * @var \Drupal\Core\Entity\EntityStorageInterface + * @var \Drupal\image\ImageStyleStorageInterface */ protected $imageStyleStorage; @@ -232,9 +232,11 @@ public function viewElements(FieldItemListInterface $items, $langcode) { */ public function calculateDependencies() { $dependencies = parent::calculateDependencies(); - /** @var \Drupal\image\ImageStyleInterface $style */ $style_id = $this->getSetting('image_style'); + /** @var \Drupal\image\ImageStyleInterface $style */ if ($style_id && $style = ImageStyle::load($style_id)) { + // If this formatter uses a valid image style to display the image, add + // the image style configuration entity as dependency of this formatter. $dependencies[$style->getConfigDependencyKey()][] = $style->getConfigDependencyName(); } return $dependencies; @@ -245,17 +247,17 @@ public function calculateDependencies() { */ public function onDependencyRemoval(array $dependencies) { $changed = parent::onDependencyRemoval($dependencies); - $name = $this->getSetting('image_style'); + $style_id = $this->getSetting('image_style'); /** @var \Drupal\image\ImageStyleInterface $style */ - if ($name && $style = ImageStyle::load($name)) { + if ($style_id && $style = ImageStyle::load($style_id)) { if (!empty($dependencies[$style->getConfigDependencyKey()][$style->getConfigDependencyName()])) { - /** @var \Drupal\image\ImageStyleStorageInterface $storage */ - $storage = \Drupal::entityManager()->getStorage($style->getEntityTypeId()); - if ($replacement_id = $storage->getReplacementId($name)) { - if (ImageStyle::load($replacement_id)) { - $this->setSetting('image_style', $replacement_id); - $changed = TRUE; - } + $replacement_id = $this->imageStyleStorage->getReplacementId($style_id); + // If a valid replacement has been provided in the storage, replace the + // image style with the replacement and signal that the formatter plugin + // settings were updated. + if ($replacement_id && ImageStyle::load($replacement_id)) { + $this->setSetting('image_style', $replacement_id); + $changed = TRUE; } } } diff --git a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php index 60b5611..c7c2aab 100644 --- a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php +++ b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php @@ -279,9 +279,12 @@ public static function validateRequiredFields($element, FormStateInterface $form */ public function calculateDependencies() { $dependencies = parent::calculateDependencies(); - /** @var \Drupal\image\ImageStyleInterface $style */ $style_id = $this->getSetting('preview_image_style'); + /** @var \Drupal\image\ImageStyleInterface $style */ if ($style_id && $style = ImageStyle::load($style_id)) { + // If this widget uses a valid image style to display the preview of the + // uploaded image, add that image style configuration entity as dependency + // of this widget. $dependencies[$style->getConfigDependencyKey()][] = $style->getConfigDependencyName(); } return $dependencies; @@ -292,18 +295,25 @@ public function calculateDependencies() { */ public function onDependencyRemoval(array $dependencies) { $changed = parent::onDependencyRemoval($dependencies); - $name = $this->getSetting('preview_image_style'); + $style_id = $this->getSetting('preview_image_style'); /** @var \Drupal\image\ImageStyleInterface $style */ - if ($name && $style = ImageStyle::load($name)) { + if ($style_id && $style = ImageStyle::load($style_id)) { if (!empty($dependencies[$style->getConfigDependencyKey()][$style->getConfigDependencyName()])) { /** @var \Drupal\image\ImageStyleStorageInterface $storage */ $storage = \Drupal::entityManager()->getStorage($style->getEntityTypeId()); - if ($replacement_id = $storage->getReplacementId($name)) { - if (ImageStyle::load($replacement_id)) { - $this->setSetting('preview_image_style', $replacement_id); - $changed = TRUE; - } + $replacement_id = $storage->getReplacementId($style_id); + // If a valid replacement has been provided in the storage, replace the + // preview image style with the replacement. + if ($replacement_id && ImageStyle::load($replacement_id)) { + $this->setSetting('preview_image_style', $replacement_id); + } + // If there's no replacement or the replacement is invalid, disable the + // image preview. + else { + $this->setSetting('preview_image_style', ''); } + // Signal that the formatter plugin settings were updated. + $changed = TRUE; } } return $changed; diff --git a/core/modules/image/src/Tests/ImageAdminStylesTest.php b/core/modules/image/src/Tests/ImageAdminStylesTest.php index 60093e7..da3080b 100644 --- a/core/modules/image/src/Tests/ImageAdminStylesTest.php +++ b/core/modules/image/src/Tests/ImageAdminStylesTest.php @@ -447,8 +447,8 @@ function testConfigImport() { // Copy config to sync, and delete the image style. $sync = $this->container->get('config.storage.sync'); $active = $this->container->get('config.storage'); - // Break first the entity view display dependency to image style, to avoid - // import dependency validation error. + // Remove the image field from the display, to avoid a dependency error + // during import. EntityViewDisplay::load('node.article.default') ->removeComponent($field_name) ->save(); diff --git a/core/modules/image/src/Tests/ImageFieldTestBase.php b/core/modules/image/src/Tests/ImageFieldTestBase.php index 6e894f5..9984a76 100644 --- a/core/modules/image/src/Tests/ImageFieldTestBase.php +++ b/core/modules/image/src/Tests/ImageFieldTestBase.php @@ -66,9 +66,9 @@ protected function setUp() { * @param array $field_settings * A list of instance settings that will be added to the instance defaults. * @param array $widget_settings - * A list of widget settings that will be added to the widget defaults. + * Widget settings to be added to the widget defaults. * @param array $formatter_settings - * A list of formatter settings that will be added to the formatter defaults. + * Formatter settings to be added to the formatter defaults. */ function createImageField($name, $type_name, $storage_settings = array(), $field_settings = array(), $widget_settings = array(), $formatter_settings = array()) { entity_create('field_storage_config', array( diff --git a/core/modules/image/src/Tests/ImageStyleDeleteTest.php b/core/modules/image/src/Tests/ImageStyleDeleteTest.php index e8d835c..1a02f6a 100644 --- a/core/modules/image/src/Tests/ImageStyleDeleteTest.php +++ b/core/modules/image/src/Tests/ImageStyleDeleteTest.php @@ -49,7 +49,7 @@ public function testDeletionMessages() { // Replacement select found. $this->assertFieldByName('replacement'); // Message telling about components relying on this image style found. - $this->assertRaw((string) t("There are components relying on %style image style. You may select another style to replace it in all components settings. If you don't provide a replacement, those components will be disabled. In this case you'll need to revisit the form and view displays an reconfigure the widgets and formatters.", ['%style' => 'Style 1'])); + $this->assertRaw((string) t("There are components relying on %style image style. You may select another style to replace it in all components settings. If you don't provide a replacement, those components will be disabled. In this case you'll need to revisit the form and view displays and reconfigure the widgets and formatters.", ['%style' => 'Style 1'])); // The style cache flush text is there. $this->assertText((string) t('All images that have been generated for this style will be permanently deleted.')); @@ -57,7 +57,7 @@ public function testDeletionMessages() { // Replacement select found. $this->assertFieldByName('replacement'); // Message telling about components relying on this image style found. - $this->assertRaw((string) t("There are components relying on %style image style. You may select another style to replace it in all components settings. If you don't provide a replacement, those components will be disabled. In this case you'll need to revisit the form and view displays an reconfigure the widgets and formatters.", ['%style' => 'Style 2'])); + $this->assertRaw((string) t("There are components relying on %style image style. You may select another style to replace it in all components settings. If you don't provide a replacement, those components will be disabled. In this case you'll need to revisit the form and view displays and reconfigure the widgets and formatters.", ['%style' => 'Style 2'])); // The style cache flush text is there. $this->assertText((string) t('All images that have been generated for this style will be permanently deleted.')); @@ -65,8 +65,8 @@ public function testDeletionMessages() { // Replacement select not found. $this->assertNoFieldByName('replacement'); // Messages telling about components relying on this image style not found. - $this->assertNoRaw((string) t("There are components relying on %style image style. You may select another style to replace it in all components settings. If you don't provide a replacement, those components will be disabled. In this case you'll need to revisit the form and view displays an reconfigure the widgets and formatters.", ['%style' => 'Style 3'])); - $this->assertNoRaw((string) t("There are components relying on %style image style and will be disabled. You'll need to revisit the form and view displays an reconfigure the widgets and formatters.", ['%style' => 'Style 3'])); + $this->assertNoRaw((string) t("There are components relying on %style image style. You may select another style to replace it in all components settings. If you don't provide a replacement, those components will be disabled. In this case you'll need to revisit the form and view displays and reconfigure the widgets and formatters.", ['%style' => 'Style 3'])); + $this->assertNoRaw((string) t("There are components relying on %style image style and will be disabled. You'll need to revisit the form and view displays and reconfigure the widgets and formatters.", ['%style' => 'Style 3'])); // The style cache flush text is there. $this->assertText((string) t('All images that have been generated for this style will be permanently deleted.')); @@ -81,7 +81,7 @@ public function testDeletionMessages() { // Replacement select not found. $this->assertNoFieldByName('replacement'); // Message telling about components relying on this image style found. - $this->assertRaw((string) t("There are components relying on %style image style and will be disabled. You'll need to revisit the form and view displays an reconfigure the widgets and formatters.", ['%style' => 'Style 1'])); + $this->assertRaw((string) t("There are components relying on %style image style and will be disabled. You'll need to revisit the form and view displays and reconfigure the widgets and formatters.", ['%style' => 'Style 1'])); // The style cache flush text is there. $this->assertText((string) t('All images that have been generated for this style will be permanently deleted.')); } @@ -111,10 +111,11 @@ public function testDelete() { // Formatter setting should have been disabled. $this->assertNull($view_display->getComponent('image1')); $this->assertNotNull($view_display->get('hidden')['image1']); - // Widget setting should have been disabled. + // Widget setting should have been preserved, but the image preview was + // disabled. $form_display = EntityFormDisplay::load("node.page.default"); - $this->assertNull($form_display->getComponent('image1')); - $this->assertNotNull($form_display->get('hidden')['image1']); + $this->assertNotNull($widget = $form_display->getComponent('image1')); + $this->assertIdentical($widget['settings']['preview_image_style'], ''); } } diff --git a/core/modules/image/tests/src/Kernel/ImageStyleIntegrationTest.php b/core/modules/image/tests/src/Kernel/ImageStyleIntegrationTest.php index 68d5d6a..304718f 100644 --- a/core/modules/image/tests/src/Kernel/ImageStyleIntegrationTest.php +++ b/core/modules/image/tests/src/Kernel/ImageStyleIntegrationTest.php @@ -96,8 +96,8 @@ public function testEntityDisplayDependency() { $this->assertNotNull($formatter = $view_display->getComponent('sticker')); $this->assertNotNull($widget = $form_display->getComponent('sticker')); // Check that both displays are using now 'replacement_style' for images. - $this->assertSame($formatter['settings']['image_style'], 'replacement_style'); - $this->assertSame($widget['settings']['preview_image_style'], 'replacement_style'); + $this->assertSame('replacement_style', $formatter['settings']['image_style']); + $this->assertSame('replacement_style', $widget['settings']['preview_image_style']); // Delete the 'replacement_style' without setting a replacement image style. $replacement->delete(); @@ -105,11 +105,13 @@ public function testEntityDisplayDependency() { // The entity view and form displays exists after dependency removal. $this->assertNotNull($view_display = EntityViewDisplay::load($view_display->id())); $this->assertNotNull($form_display = EntityFormDisplay::load($form_display->id())); - // The 'sticker' formatter component should be hidden in both displays. + // The 'sticker' formatter component should be hidden in view display. $this->assertNull($view_display->getComponent('sticker')); $this->assertTrue($view_display->get('hidden')['sticker']); - $this->assertNull($form_display->getComponent('sticker')); - $this->assertTrue($form_display->get('hidden')['sticker']); + // The 'sticker' widget component should be active in form displays, but the + // image preview should be disabled. + $this->assertNotNull($widget = $form_display->getComponent('sticker')); + $this->assertSame('', $widget['settings']['preview_image_style']); } }