diff --git a/core/modules/views/src/Plugin/views/field/Field.php b/core/modules/views/src/Plugin/views/field/Field.php index 2e1b8da..45d0b1e 100644 --- a/core/modules/views/src/Plugin/views/field/Field.php +++ b/core/modules/views/src/Plugin/views/field/Field.php @@ -7,11 +7,14 @@ namespace Drupal\views\Plugin\views\field; +use Drupal\Component\Plugin\DependentPluginInterface; +use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\Xss; use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Field\FieldTypePluginManagerInterface; use Drupal\Core\Field\FormatterPluginManager; @@ -23,7 +26,6 @@ use Drupal\Core\Render\RendererInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\TypedData\TypedDataInterface; -use Drupal\image\Entity\ImageStyle; use Drupal\views\FieldAPIHandlerTrait; use Drupal\views\Entity\Render\EntityFieldRenderer; use Drupal\views\Plugin\views\display\DisplayPluginBase; @@ -477,20 +479,9 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { $settings = $this->options['settings'] + $this->formatterPluginManager->getDefaultSettings($format); - $options = array( - 'field_definition' => $field, - 'configuration' => array( - 'type' => $format, - 'settings' => $settings, - 'label' => '', - 'weight' => 0, - ), - 'view_mode' => '_custom', - ); - // Get the settings form. $settings_form = array('#value' => array()); - if ($formatter = $this->formatterPluginManager->getInstance($options)) { + if ($formatter = $this->getFormatterInstance($field, $format, $settings)) { $settings_form = $formatter->settingsForm($form, $form_state); // Convert field UI selector states to work in the Views field form. FormHelper::rewriteStatesSelector($settings_form, "fields[{$field->getName()}][settings_edit_form]", 'options'); @@ -950,6 +941,33 @@ protected function addSelfTokens(&$tokens, $item) { } /** + * Returns the field formatter instance. + * + * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition + * The field definition + * @param string $formatter + * The formatter type. + * @param array $formatter_settings + * The formatter settings. + * + * @return \Drupal\Core\Field\FormatterInterface|null + */ + protected function getFormatterInstance(FieldDefinitionInterface $field_definition, $formatter, array $formatter_settings) { + $options = array( + 'field_definition' => $field_definition, + 'configuration' => [ + 'type' => $formatter, + 'settings' => $formatter_settings, + 'label' => '', + 'weight' => 0, + ], + 'view_mode' => '_custom', + ); + + return $this->formatterPluginManager->getInstance($options); + } + + /** * {@inheritdoc} */ public function calculateDependencies() { @@ -962,19 +980,10 @@ public function calculateDependencies() { // Add the module providing the formatter. if (!empty($this->options['type'])) { $dependencies['module'][] = $this->formatterPluginManager->getDefinition($this->options['type'])['provider']; - } - // Add the image style. - $field = $this->getFieldDefinition(); - $style_id = ''; - if ($field->getType() == 'image') { - $style_id = $this->displayHandler->getOption('fields')[$field->getName()]['settings']['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(); + if (($formatter = $this->getFormatterInstance($this->getFieldDefinition(), $this->options['type'], $this->options['settings'])) && $formatter instanceof DependentPluginInterface) { + $dependencies = NestedArray::mergeDeep($dependencies, $formatter->calculateDependencies()); + } } return $dependencies; diff --git a/core/modules/views/src/Tests/DependenciesTest.php b/core/modules/views/src/Tests/DependenciesTest.php index d94cde4..4820086 100644 --- a/core/modules/views/src/Tests/DependenciesTest.php +++ b/core/modules/views/src/Tests/DependenciesTest.php @@ -7,7 +7,12 @@ namespace Drupal\views\Tests; +use Drupal\Core\Entity\Entity\EntityFormDisplay; +use Drupal\Core\Entity\Entity\EntityViewDisplay; +use Drupal\field\Entity\FieldConfig; +use Drupal\field\Entity\FieldStorageConfig; use Drupal\node\Entity\Node; +use Drupal\views\Entity\View; /** * Tests general rendering of a view. @@ -34,13 +39,6 @@ class DependenciesTest extends ViewTestBase { protected $adminUser; /** - * The style name to delete. - * - * @var string - */ - protected $style_name = 'thumbnail'; - - /** * {@inheritdoc} */ protected function setUp() { @@ -61,23 +59,29 @@ protected function setUp() { $field_name = 'field_image'; $this->createImageField($field_name, 'article'); - // Create a new node with an image attached. - $test_image = current($this->drupalGetTestFiles('image')); - $nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName()); - Node::load($nid); - - ViewTestData::createTestViews(get_class($this), array('views_test_config')); + ViewTestData::createTestViews(get_class($this), ['views_test_config']); } /** * Tests Image Style Dependency. */ public function testImageStyleDependency() { - - $this->drupalGet('admin/config/media/image-styles/manage/' . $this->style_name . '/delete'); + $this->drupalGet('admin/config/media/image-styles/manage/thumbnail/delete'); // A warning shows that the view will be deleted. $this->assertRaw('Show Image Fields'); + + /** @var \Drupal\views\Entity\View $view */ + $view = View::load('entity_test_fields_dependencies'); + $expected = [ + 'module' => ['image', 'node', 'user'], + 'config' => [ + 'field.storage.node.field_image', + 'image.style.thumbnail', + ], + ]; + $view->calculateDependencies(); + $this->assertEqual($expected, $view->getDependencies()); } /** @@ -88,92 +92,46 @@ public function testImageStyleDependency() { * @param string $type_name * The node type that this field will be added to. * @param array $storage_settings - * A list of field storage settings that will be added to the defaults. + * (optional) A list of field storage settings that will be added to the defaults. * @param array $field_settings - * A list of instance settings that will be added to the instance defaults. + * (optional) 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. + * (optional) A list of widget settings that will be added to the widget defaults. + * + * @return \Drupal\field\FieldConfigInterface + * The created field config. */ - function createImageField($name, $type_name, $storage_settings = array(), $field_settings = array(), $widget_settings = array()) { - entity_create('field_storage_config', array( + function createImageField($name, $type_name, $storage_settings = [], $field_settings = [], $widget_settings = []) { + FieldStorageConfig::create([ 'field_name' => $name, 'entity_type' => 'node', 'type' => 'image', 'settings' => $storage_settings, 'cardinality' => !empty($storage_settings['cardinality']) ? $storage_settings['cardinality'] : 1, - ))->save(); + ])->save(); - $field_config = entity_create('field_config', array( + $field_config = FieldConfig::create([ 'field_name' => $name, 'label' => $name, 'entity_type' => 'node', 'bundle' => $type_name, 'required' => !empty($field_settings['required']), 'settings' => $field_settings, - )); + ]); $field_config->save(); - entity_get_form_display('node', $type_name, 'default') - ->setComponent($name, array( + EntityFormDisplay::load("node.$type_name.default") + ->setComponent($name, [ 'type' => 'image_image', 'settings' => $widget_settings, - )) + ]) ->save(); - entity_get_display('node', $type_name, 'default') + EntityViewDisplay::load("node.$type_name.default") ->setComponent($name) ->save(); return $field_config; - - } - - /** - * Preview an image in a node. - * - * @param \Drupal\Core\Image\ImageInterface $image - * A file object representing the image to upload. - * @param string $field_name - * Name of the image field the image should be attached to. - * @param string $type - * The type of node to create. - */ - function previewNodeImage($image, $field_name, $type) { - $edit = array( - 'title[0][value]' => $this->randomMachineName(), - ); - $edit['files[' . $field_name . '_0]'] = drupal_realpath($image->uri); - $this->drupalPostForm('node/add/' . $type, $edit, t('Preview')); } - /** - * Upload an image to a node. - * - * @param $image - * A file object representing the image to upload. - * @param $field_name - * Name of the image field the image should be attached to. - * @param $type - * The type of node to create. - * @param $alt - * The alt text for the image. Use if the field settings require alt text. - */ - function uploadNodeImage($image, $field_name, $type, $alt = '') { - $edit = array( - 'title[0][value]' => $this->randomMachineName(), - ); - $edit['files[' . $field_name . '_0]'] = drupal_realpath($image->uri); - $this->drupalPostForm('node/add/' . $type, $edit, t('Save and publish')); - if ($alt) { - // Add alt text. - $this->drupalPostForm(NULL, [$field_name . '[0][alt]' => $alt], t('Save and publish')); - } - - // Retrieve ID of the newly created node from the current URL. - $matches = array(); - preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches); - return isset($matches[1]) ? $matches[1] : FALSE; - } - - }