diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php index 1d18ee1..ac6b0ef 100644 --- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php @@ -951,7 +951,7 @@ protected function getAllPlugins($only_overrides = FALSE) { * {@inheritdoc} */ public function calculateDependencies() { - $this->addDependencies(parent::calculateDependencies()); + $this->dependencies = parent::calculateDependencies(); // Collect all the dependencies of handlers and plugins. Only calculate // their dependencies if they are configured by this display. $plugins = array_merge($this->getAllHandlers(TRUE), $this->getAllPlugins(TRUE)); diff --git a/core/modules/views/src/Plugin/views/field/Field.php b/core/modules/views/src/Plugin/views/field/Field.php index 7077ed8..33675df 100644 --- a/core/modules/views/src/Plugin/views/field/Field.php +++ b/core/modules/views/src/Plugin/views/field/Field.php @@ -8,13 +8,11 @@ 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; @@ -44,6 +42,7 @@ * @ViewsField("field") */ class Field extends FieldPluginBase implements CacheableDependencyInterface, MultiItemsFieldHandlerInterface { + use FieldAPIHandlerTrait; use PluginDependencyTrait; @@ -476,14 +475,9 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { $form['field_api_classes']['#description'] .= ' ' . $this->t('Checking this option will cause the group Display Type and Separator values to be ignored.'); } - // Get the currently selected formatter. - $format = $this->options['type']; - - $settings = $this->options['settings'] + $this->formatterPluginManager->getDefaultSettings($format); - // Get the settings form. $settings_form = array('#value' => array()); - if ($formatter = $this->getFormatterInstance($field, $format, $settings)) { + if ($formatter = $this->getFormatterInstance()) { $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'); @@ -945,26 +939,22 @@ 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 + * The field formatter instance. */ - protected function getFormatterInstance(FieldDefinitionInterface $field_definition, $formatter, array $formatter_settings) { - $options = array( - 'field_definition' => $field_definition, + protected function getFormatterInstance() { + $settings = $this->options['settings'] + $this->formatterPluginManager->getDefaultSettings($this->options['type']); + + $options = [ + 'field_definition' => $this->getFieldDefinition(), 'configuration' => [ - 'type' => $formatter, - 'settings' => $formatter_settings, + 'type' => $this->options['type'], + 'settings' => $settings, 'label' => '', 'weight' => 0, ], 'view_mode' => '_custom', - ); + ]; return $this->formatterPluginManager->getInstance($options); } @@ -983,7 +973,7 @@ public function calculateDependencies() { if (!empty($this->options['type'])) { $this->dependencies['module'][] = $this->formatterPluginManager->getDefinition($this->options['type'])['provider']; - if (($formatter = $this->getFormatterInstance($this->getFieldDefinition(), $this->options['type'], $this->options['settings'])) && $formatter instanceof DependentPluginInterface) { + if (($formatter = $this->getFormatterInstance()) && $formatter instanceof DependentPluginInterface) { $this->calculatePluginDependencies($formatter); } } diff --git a/core/modules/views/src/Tests/DependenciesTest.php b/core/modules/views/src/Tests/DependenciesTest.php deleted file mode 100644 index 4820086..0000000 --- a/core/modules/views/src/Tests/DependenciesTest.php +++ /dev/null @@ -1,137 +0,0 @@ -enableViewsTestModule(); - - // Create Basic page and Article node types. - if ($this->profile != 'standard') { - $this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']); - $this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']); - } - - $this->adminUser = $this->drupalCreateUser(['access content', 'access administration pages', 'administer site configuration', 'administer content types', 'administer node fields', 'administer nodes', 'create article content', 'edit any article content', 'delete any article content', 'administer image styles', 'administer node display']); - $this->drupalLogin($this->adminUser); - - // Create an image field that uses the new style. - $field_name = 'field_image'; - $this->createImageField($field_name, 'article'); - - ViewTestData::createTestViews(get_class($this), ['views_test_config']); - } - - /** - * Tests Image Style Dependency. - */ - public function testImageStyleDependency() { - $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()); - } - - /** - * Create a new image field. - * - * @param string $name - * The name of the new field (all lowercase), exclude the "field_" prefix. - * @param string $type_name - * The node type that this field will be added to. - * @param array $storage_settings - * (optional) A list of field storage settings that will be added to the defaults. - * @param array $field_settings - * (optional) A list of instance settings that will be added to the instance defaults. - * @param array $widget_settings - * (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 = [], $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(); - - $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(); - - EntityFormDisplay::load("node.$type_name.default") - ->setComponent($name, [ - 'type' => 'image_image', - 'settings' => $widget_settings, - ]) - ->save(); - - EntityViewDisplay::load("node.$type_name.default") - ->setComponent($name) - ->save(); - - return $field_config; - } - -} diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.entity_test_fields_dependencies.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.entity_test_fields_dependencies.yml deleted file mode 100644 index 3598a5a..0000000 --- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.entity_test_fields_dependencies.yml +++ /dev/null @@ -1,179 +0,0 @@ -langcode: en -status: true -dependencies: - config: - - field.storage.node.field_image - module: - - image - - node - - user -id: entity_test_fields_dependencies -label: 'Show Image Fields' -module: views -description: '' -tag: '' -base_table: node_field_data -base_field: nid -core: 8.x -display: - default: - display_plugin: default - id: default - display_title: Master - position: 0 - display_options: - access: - type: perm - options: - perm: 'access content' - cache: - type: tag - options: { } - query: - type: views_query - options: - disable_sql_rewrite: false - distinct: false - replica: false - query_comment: '' - query_tags: { } - exposed_form: - type: basic - options: - submit_button: Apply - reset_button: false - reset_button_label: Reset - exposed_sorts_label: 'Sort by' - expose_sort_order: true - sort_asc_label: Asc - sort_desc_label: Desc - pager: - type: full - options: - items_per_page: 10 - offset: 0 - id: 0 - total_pages: null - expose: - items_per_page: false - items_per_page_label: 'Items per page' - items_per_page_options: '5, 10, 25, 50' - items_per_page_options_all: false - items_per_page_options_all_label: '- All -' - offset: false - offset_label: Offset - tags: - previous: '‹ Previous' - next: 'Next ›' - first: '« First' - last: 'Last »' - quantity: 9 - style: - type: default - row: - type: fields - fields: - field_image: - id: field_image - table: node__field_image - field: field_image - relationship: none - group_type: group - admin_label: '' - label: '' - exclude: false - alter: - alter_text: false - text: '' - make_link: false - path: '' - absolute: false - external: false - replace_spaces: false - path_case: none - trim_whitespace: false - alt: '' - rel: '' - link_class: '' - prefix: '' - suffix: '' - target: '' - nl2br: false - max_length: 0 - word_boundary: true - ellipsis: true - more_link: false - more_link_text: '' - more_link_path: '' - strip_tags: false - trim: false - preserve_tags: '' - html: false - element_type: '' - element_class: '' - element_label_type: '' - element_label_class: '' - element_label_colon: false - element_wrapper_type: '' - element_wrapper_class: '' - element_default_classes: true - empty: '' - hide_empty: false - empty_zero: false - hide_alter_empty: true - click_sort_column: target_id - type: image - settings: - image_style: thumbnail - image_link: '' - group_column: '' - group_columns: { } - group_rows: true - delta_limit: 0 - delta_offset: 0 - delta_reversed: false - delta_first_last: false - multi_type: separator - separator: ', ' - field_api_classes: false - plugin_id: field - filters: { } - sorts: { } - title: 'Show Image Fields' - header: { } - footer: { } - empty: { } - relationships: { } - arguments: { } - display_extenders: { } - filter_groups: - operator: AND - groups: { } - cache_metadata: - max-age: -1 - contexts: - - 'languages:language_content' - - 'languages:language_interface' - - url.query_args - - 'user.node_grants:view' - - user.permissions - tags: - - 'config:field.storage.node.field_image' - page_1: - display_plugin: page - id: page_1 - display_title: Page - position: 1 - display_options: - display_extenders: { } - path: show-image-fields - cache_metadata: - max-age: -1 - contexts: - - 'languages:language_content' - - 'languages:language_interface' - - url.query_args - - 'user.node_grants:view' - - user.permissions - tags: - - 'config:field.storage.node.field_image' diff --git a/core/modules/views/tests/src/Kernel/ViewsIntegrationTest.php b/core/modules/views/tests/src/Kernel/ViewsIntegrationTest.php new file mode 100644 index 0000000..9f98ba2 --- /dev/null +++ b/core/modules/views/tests/src/Kernel/ViewsIntegrationTest.php @@ -0,0 +1,81 @@ + 'foo']); + $style->save(); + + // Create a new image field 'bar' to be used in 'entity_test_fields' view. + FieldStorageConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => 'bar', + 'type' => 'image', + ])->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'bundle' => 'entity_test', + 'field_name' => 'bar', + ])->save(); + + /** @var \Drupal\views\ViewEntityInterface $view */ + $view = View::load('entity_test_fields'); + $display =& $view->getDisplay('default'); + + // Add the 'bar' image field to 'entity_test_fields' view. + $display['display_options']['fields']['bar'] = [ + 'id' => 'bar', + 'field' => 'bar', + 'plugin_id' => 'field', + 'table' => 'entity_test__bar', + 'entity_type' => 'entity_test', + 'entity_field' => 'bar', + 'type' => 'image', + 'settings' => ['image_style' => 'foo', 'image_link' => ''], + ]; + $view->save(); + + $dependencies = $view->getDependencies() + ['config' => []]; + + // Checks that style 'foo' is a dependency of view 'entity_test_fields'. + $this->assertTrue(in_array('image.style.foo', $dependencies['config'])); + + // Delete the 'foo' image style. + $style->delete(); + + // Checks that the view has been deleted too. + $this->assertNull(View::load('entity_test_fields')); + } + +} diff --git a/core/modules/views/tests/src/Kernel/ViewsKernelTestBase.php b/core/modules/views/tests/src/Kernel/ViewsKernelTestBase.php new file mode 100644 index 0000000..9d6e47a --- /dev/null +++ b/core/modules/views/tests/src/Kernel/ViewsKernelTestBase.php @@ -0,0 +1,156 @@ +installSchema('system', ['router', 'sequences', 'key_value_expire']); + $this->setUpFixtures(); + + if ($import_test_views) { + ViewTestData::createTestViews(get_class($this), ['views_test_config']); + } + } + /** + * Sets up the configuration and schema of views and views_test_data modules. + * + * Because the schema of views_test_data.module is dependent on the test + * using it, it cannot be enabled normally. + */ + protected function setUpFixtures() { + // First install the system module. Many Views have Page displays have menu + // links, and for those to work, the system menus must already be present. + $this->installConfig(['system']); + + /** @var \Drupal\Core\State\StateInterface $state */ + $state = $this->container->get('state'); + // Define the schema and views data variable before enabling the test module. + $state->set('views_test_data_schema', $this->schemaDefinition()); + $state->set('views_test_data_views_data', $this->viewsData()); + + $this->installConfig(['views', 'views_test_config', 'views_test_data']); + foreach ($this->schemaDefinition() as $table => $schema) { + $this->installSchema('views_test_data', $table); + } + + $this->container->get('router.builder')->rebuild(); + + // Load the test dataset. + $data_set = $this->dataSet(); + $query = Database::getConnection()->insert('views_test_data') + ->fields(array_keys($data_set[0])); + foreach ($data_set as $record) { + $query->values($record); + } + $query->execute(); + } + + /** + * Orders a nested array containing a result set based on a given column. + * + * @param array $result_set + * An array of rows from a result set, with each row as an associative + * array keyed by column name. + * @param string $column + * The column name by which to sort the result set. + * @param bool $reverse + * (optional) Boolean indicating whether to sort the result set in reverse + * order. Defaults to FALSE. + * + * @return array + * The sorted result set. + */ + protected function orderResultSet($result_set, $column, $reverse = FALSE) { + $order = $reverse ? -1 : 1; + usort($result_set, function ($a, $b) use ($column, $order) { + if ($a[$column] == $b[$column]) { + return 0; + } + return $order * (($a[$column] < $b[$column]) ? -1 : 1); + }); + return $result_set; + } + + /** + * Executes a view with debugging. + * + * @param \Drupal\views\ViewExecutable $view + * The view object. + * @param array $args + * (optional) An array of the view arguments to use for the view. + */ + protected function executeView($view, array $args = []) { + $view->setDisplay(); + $view->preExecute($args); + $view->execute(); + $verbose_message = '
Executed view: ' . ((string) $view->build_info['query']). '
'; + if ($view->build_info['query'] instanceof SelectInterface) { + $verbose_message .= '
Arguments: ' . print_r($view->build_info['query']->getArguments(), TRUE) . '
'; + } + $this->verbose($verbose_message); + } + + /** + * Returns the schema definition. + */ + protected function schemaDefinition() { + return ViewTestData::schemaDefinition(); + } + + /** + * Returns the views data definition. + */ + protected function viewsData() { + return ViewTestData::viewsData(); + } + + /** + * Returns a very simple test dataset. + */ + protected function dataSet() { + return ViewTestData::dataSet(); + } + +}