diff --git a/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php index a92c58315f1099bcb85d9c2287d3c9e847850d47..9ac576e433e20cf8c0c1d75b34e6fedc76c389d2 100644 --- a/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php +++ b/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php @@ -38,6 +38,13 @@ abstract class DisplayPluginBase extends PluginBase { var $handlers = array(); + /** + * An array of instantiated plugins used in this display. + * + * @var array + */ + protected $plugins = array(); + /** * Stores all available display extenders. */ @@ -722,11 +729,7 @@ public function getOption($option) { * @return bool */ public function usesFields() { - $style = $this->getOption('style'); - $plugin = $this->getPlugin('style', $style['type']); - if ($plugin) { - return $plugin->usesFields(); - } + return $this->getPlugin('style')->usesFields(); } /** @@ -734,54 +737,35 @@ public function usesFields() { * * @param string $type * The type of the plugin. - * @param string $name - * The name of the plugin defined in hook_views_plugins. * - * @return views_plugin|FALSE - */ - public function getPlugin($type = 'style', $name = NULL) { - static $cache = array(); - if (!isset($cache[$type][$name])) { - switch ($type) { - case 'query': - $views_data = views_fetch_data($this->view->storage->base_table); - $name = !empty($views_data['table']['base']['query class']) ? $views_data['table']['base']['query class'] : 'views_query'; - default: - $option_name = $type; - $options = $this->getOption($type); - if (!$name) { - $name = $options['type']; - } + * @return Drupal\views\Plugin\views\PluginBase + */ + public function getPlugin($type) { + // Look up the name to attempt to load it from the static cache. + $options = $this->getOption($type); + $name = $options['type']; - $options = $options['options']; + if (!isset($this->plugins[$type][$name])) { + $views_data = views_fetch_data($this->view->storage->base_table); + if ($type == 'query') { + $name = !empty($views_data['table']['base']['query class']) ? $views_data['table']['base']['query class'] : 'views_query'; } - if ($type != 'query') { - $plugin = views_get_plugin($type, $name); - } - else { - $plugin = views_get_plugin('query', $name); - } + $plugin = drupal_container()->get("plugin.manager.views.$type")->createInstance($name); - if (!$plugin) { - return; - } if ($type != 'query') { - $plugin->init($this->view, $this, $options); + $plugin->init($this->view, $this, $options['options']); } else { - $display_id = $this->isDefaulted($option_name) ? $this->display['id'] : 'default'; - if (!isset($this->base_field)) { - $views_data = views_fetch_data($this->view->storage->base_table); $this->view->storage->base_field = !empty($views_data['table']['base']['field']) ? $views_data['table']['base']['field'] : ''; } - $plugin->init($this->view->storage->base_table, $this->view->storage->base_field, $options); + $plugin->init($this->view->storage->base_table, $this->view->storage->base_field, $options['options']); } - $cache[$type][$name] = $plugin; + $this->plugins[$type][$name] = $plugin; } - return $cache[$type][$name]; + return $this->plugins[$type][$name]; } /** @@ -1056,12 +1040,9 @@ public function optionsSummary(&$categories, &$options) { 'desc' => t('Change the title that this display will use.'), ); - $style_options = $this->getOption('style'); - $name = $style_options['type']; - $style_plugin = views_get_plugin_definition('style', $name); $style_plugin_instance = $this->getPlugin('style'); - $style_summary = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin_instance->summaryTitle(); - $style_title = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin_instance->pluginTitle(); + $style_summary = empty($style_plugin_instance->definition['title']) ? t('Missing style plugin') : $style_plugin_instance->summaryTitle(); + $style_title = empty($style_plugin_instance->definition['title']) ? t('Missing style plugin') : $style_plugin_instance->pluginTitle(); $style = ''; @@ -1079,12 +1060,9 @@ public function optionsSummary(&$categories, &$options) { } if ($style_plugin_instance->usesRowPlugin()) { - $row_options = $this->getOption('row'); - $name = $row_options['type']; - $row_plugin = views_get_plugin_definition('row', $name); - $row_plugin_instance = $this->getPlugin('row', $name); - $row_summary = empty($row_plugin['title']) ? t('Missing style plugin') : $row_plugin_instance->summaryTitle(); - $row_title = empty($row_plugin['title']) ? t('Missing style plugin') : $row_plugin_instance->pluginTitle(); + $row_plugin_instance = $this->getPlugin('row'); + $row_summary = empty($row_plugin_instance->definition['title']) ? t('Missing style plugin') : $row_plugin_instance->summaryTitle(); + $row_title = empty($row_plugin_instance->definition['title']) ? t('Missing style plugin') : $row_plugin_instance->pluginTitle(); $options['row'] = array( 'category' => 'format', @@ -1570,15 +1548,14 @@ public function buildOptionsForm(&$form, &$form_state) { break; case 'style': $form['#title'] .= t('How should this view be styled'); - $style = $this->getOption('style'); - $form['style_plugin'] = array( + $style_plugin = $this->getPlugin('style'); + $form['style'] = array( '#type' => 'radios', '#options' => views_fetch_plugin_names('style', $this->getStyleType(), array($this->view->storage->base_table)), - '#default_value' => $style['type'], + '#default_value' => $style_plugin->definition['id'], '#description' => t('If the style you choose has settings, be sure to click the settings button that will appear next to it in the View summary.'), ); - $style_plugin = $this->getPlugin('style', $style['type']); if ($style_plugin->usesOptions()) { $form['markup'] = array( '#prefix' => '<div class="form-item description">', @@ -1613,14 +1590,13 @@ public function buildOptionsForm(&$form, &$form_state) { break; case 'row': $form['#title'] .= t('How should each row in this view be styled'); - $row = $this->getOption('row'); - $form['row_plugin'] = array( + $row_plugin_instance = $this->getPlugin('row'); + $form['row'] = array( '#type' => 'radios', '#options' => views_fetch_plugin_names('row', $this->getStyleType(), array($this->view->storage->base_table)), - '#default_value' => $row['type'], + '#default_value' => $row_plugin_instance->definition['id'], ); - $row_plugin_instance = $this->getPlugin('row', $row['type']); if ($row_plugin_instance->usesOptions()) { $form['markup'] = array( '#prefix' => '<div class="form-item description">', @@ -1770,8 +1746,7 @@ public function buildOptionsForm(&$form, &$form_state) { } } - $name = $this->getOption('style_plugin'); - $plugin = $this->getPlugin('style', $name); + $plugin = $this->getPlugin('style'); if ($plugin) { $funcs[] = $this->optionLink(t('Style output'), 'analyze-theme-style') . ': ' . $this->formatThemes($plugin->themeFunctions(), $plugin->additionalThemeFunctions()); $themes = $plugin->additionalThemeFunctions(); @@ -1782,8 +1757,7 @@ public function buildOptionsForm(&$form, &$form_state) { } if ($plugin->usesRowPlugin()) { - $name = $this->getOption('row_plugin'); - $row_plugin = $this->getPlugin('row', $name); + $row_plugin = $this->getPlugin('row'); if ($row_plugin) { $funcs[] = $this->optionLink(t('Row style output'), 'analyze-theme-row') . ': ' . $this->formatThemes($row_plugin->themeFunctions()); $themes = $row_plugin->additionalThemeFunctions(); @@ -1885,8 +1859,7 @@ public function buildOptionsForm(&$form, &$form_state) { $form['#title'] .= t('Theming information (style)'); $output = '<p>' . t('Back to !info.', array('!info' => $this->optionLink(t('theming information'), 'analyze-theme'))) . '</p>'; - $name = $this->getOption('style_plugin'); - $plugin = $this->getPlugin('style', $name); + $plugin = $this->getPlugin('style'); if (empty($plugin->definition['theme'])) { $output .= t('This display has no style theming information'); @@ -1913,8 +1886,7 @@ public function buildOptionsForm(&$form, &$form_state) { $form['#title'] .= t('Theming information (row style)'); $output = '<p>' . t('Back to !info.', array('!info' => $this->optionLink(t('theming information'), 'analyze-theme'))) . '</p>'; - $name = $this->getOption('row_plugin'); - $plugin = $this->getPlugin('row', $name); + $plugin = $this->getPlugin('row'); if (empty($plugin->definition['theme'])) { $output .= t('This display has no row style theming information'); @@ -2248,10 +2220,10 @@ public function submitOptionsForm(&$form, &$form_state) { // This if prevents resetting options to default if they don't change // the plugin. $row = $this->getOption('row'); - if ($row['type'] != $form_state['values'][$section]['type']) { - $plugin = views_get_plugin('row', $form_state['values'][$section]['type']); + if ($row['type'] != $form_state['values'][$section]) { + $plugin = views_get_plugin('row', $form_state['values'][$section]); if ($plugin) { - $row = array('type' => $form_state['values'][$section]['type']); + $row = array('type' => $form_state['values'][$section]); $this->setOption($section, $row); // send ajax form to options page if we use it. @@ -2265,10 +2237,10 @@ public function submitOptionsForm(&$form, &$form_state) { // This if prevents resetting options to default if they don't change // the plugin. $style = $this->getOption('style'); - if ($style['type'] != $form_state['values'][$section]['type']) { - $plugin = views_get_plugin('style', $form_state['values'][$section]['type']); + if ($style['type'] != $form_state['values'][$section]) { + $plugin = views_get_plugin('style', $form_state['values'][$section]); if ($plugin) { - $row = array('type' => $form_state['values'][$section]['type']); + $row = array('type' => $form_state['values'][$section]); $this->setOption($section, $row); // send ajax form to options page if we use it. if ($plugin->usesOptions()) { @@ -2596,8 +2568,7 @@ public function validate() { } // Validate style plugin - $name = $this->getOption('style_plugin'); - $style = $this->getPlugin('style', $name); + $style = $this->getPlugin('style'); if (empty($style)) { $errors[] = t('Display "@display" has an invalid style plugin.', array('@display' => $this->display['display_title'])); } diff --git a/lib/Drupal/views/Plugin/views/display/Feed.php b/lib/Drupal/views/Plugin/views/display/Feed.php index 9a4165aaf889648a3fac0d6f11bfaf443bf92187..1af8deb154a6d5ac88b30f12d199cf5f3b57ee6d 100644 --- a/lib/Drupal/views/Plugin/views/display/Feed.php +++ b/lib/Drupal/views/Plugin/views/display/Feed.php @@ -240,8 +240,7 @@ public function attachTo($display_id) { // Defer to the feed style; it may put in meta information, and/or // attach a feed icon. - $name = $this->getOption('style_plugin'); - $plugin = $this->getPlugin('style', $name); + $plugin = $this->getPlugin('style'); if ($plugin) { $clone = $this->view->cloneView(); $clone->setDisplay($this->display['id']); diff --git a/lib/Drupal/views/Plugin/views/style/StylePluginBase.php b/lib/Drupal/views/Plugin/views/style/StylePluginBase.php index 8f110673c92d037f4427c3065df5c2ef05a81039..65c83d84ff2787523446217aaa38fd04c7a2cf43 100644 --- a/lib/Drupal/views/Plugin/views/style/StylePluginBase.php +++ b/lib/Drupal/views/Plugin/views/style/StylePluginBase.php @@ -662,8 +662,7 @@ public function validate() { $errors = parent::validate(); if ($this->usesRowPlugin()) { - $name = $this->displayHandler->getOption('row_plugin'); - $plugin = $this->displayHandler->getPlugin('row', $name); + $plugin = $this->displayHandler->getPlugin('row'); if (empty($plugin)) { $errors[] = t('Style @style requires a row style but the row plugin is invalid.', array('@style' => $this->definition['title'])); } diff --git a/lib/Drupal/views/Tests/UI/RowUITest.php b/lib/Drupal/views/Tests/UI/RowUITest.php new file mode 100644 index 0000000000000000000000000000000000000000..7d7b2457cc8f09877d1f5f17dd94a4c199e30834 --- /dev/null +++ b/lib/Drupal/views/Tests/UI/RowUITest.php @@ -0,0 +1,61 @@ +<?php + +/** + * @file + * Definition of Drupal\views\Tests\UI\RowUITest. + */ + +namespace Drupal\views\Tests\UI; + +/** + * Tests the UI of row plugins. + * + * @see Drupal\views_test_data\Plugin\views\row\RowTest. + */ +class RowUITest extends UITestBase { + + public static function getInfo() { + return array( + 'name' => 'Row: UI', + 'description' => 'Tests the UI of row plugins.', + 'group' => 'Views UI', + ); + } + + /** + * Tests changing the row plugin and changing some options of a row. + */ + public function testRowUI() { + $view = $this->getView(); + $view_edit_url = "admin/structure/views/view/{$view->storage->name}/edit"; + + $row_plugin_url = "admin/structure/views/nojs/display/{$view->storage->name}/default/row"; + $row_options_url = "admin/structure/views/nojs/display/{$view->storage->name}/default/row_options"; + + $this->drupalGet($row_plugin_url); + $this->assertFieldByName('row', 'fields', 'The default row plugin selected in the UI should be fields.'); + + $edit = array( + 'row' => 'test_row' + ); + $this->drupalPost(NULL, $edit, t('Apply')); + $this->assertFieldByName('row_options[test_option]', NULL, 'Make sure the custom settings form from the test plugin appears.'); + $random_name = $this->randomName(); + $edit = array( + 'row_options[test_option]' => $random_name + ); + $this->drupalPost(NULL, $edit, t('Apply')); + $this->drupalGet($row_options_url); + $this->assertFieldByName('row_options[test_option]', $random_name, 'Make sure the custom settings form field has the expected value stored.'); + + $this->drupalPost($view_edit_url, array(), t('Save')); + $this->assertLink(t('Test row plugin'), 0, 'Make sure the test row plugin is shown in the UI'); + + $view = views_get_view($view->storage->name); + $view->initDisplay(); + $row = $view->display_handler->getOption('row'); + $this->assertEqual($row['type'], 'test_row', 'Make sure that the test_row got saved as used row plugin.'); + $this->assertEqual($row['options']['test_option'], $random_name, 'Make sure that the custom settings field got saved as expected.'); + } + +} diff --git a/lib/Drupal/views/Tests/UI/StyleUITest.php b/lib/Drupal/views/Tests/UI/StyleUITest.php new file mode 100644 index 0000000000000000000000000000000000000000..5255af9dc72f86b289bd8f19fbcaaa7916d13248 --- /dev/null +++ b/lib/Drupal/views/Tests/UI/StyleUITest.php @@ -0,0 +1,61 @@ +<?php + +/** + * @file + * Definition of Drupal\views\Tests\UI\StyleUITest. + */ + +namespace Drupal\views\Tests\UI; + +/** + * Tests the UI of style plugins. + * + * @see Drupal\views_test_data\Plugin\views\style\StyleTest. + */ +class StyleUITest extends UITestBase { + + public static function getInfo() { + return array( + 'name' => 'Style: UI', + 'description' => 'Tests the UI of style plugins.', + 'group' => 'Views UI', + ); + } + + /** + * Tests changing the style plugin and changing some options of a style. + */ + public function testStyleUI() { + $view = $this->getView(); + $view_edit_url = "admin/structure/views/view/{$view->storage->name}/edit"; + + $style_plugin_url = "admin/structure/views/nojs/display/{$view->storage->name}/default/style"; + $style_options_url = "admin/structure/views/nojs/display/{$view->storage->name}/default/style_options"; + + $this->drupalGet($style_plugin_url); + $this->assertFieldByName('style', 'default', 'The default style plugin selected in the UI should be unformatted list.'); + + $edit = array( + 'style' => 'test_style' + ); + $this->drupalPost(NULL, $edit, t('Apply')); + $this->assertFieldByName('style_options[test_option]', NULL, 'Make sure the custom settings form from the test plugin appears.'); + $random_name = $this->randomName(); + $edit = array( + 'style_options[test_option]' => $random_name + ); + $this->drupalPost(NULL, $edit, t('Apply')); + $this->drupalGet($style_options_url); + $this->assertFieldByName('style_options[test_option]', $random_name, 'Make sure the custom settings form field has the expected value stored.'); + + $this->drupalPost($view_edit_url, array(), t('Save')); + $this->assertLink(t('Test style plugin'), 0, 'Make sure the test style plugin is shown in the UI'); + + $view = views_get_view($view->storage->name); + $view->initDisplay(); + $style = $view->display_handler->getOption('style'); + $this->assertEqual($style['type'], 'test_style', 'Make sure that the test_style got saved as used style plugin.'); + $this->assertEqual($style['options']['test_option'], $random_name, 'Make sure that the custom settings field got saved as expected.'); + } + +} diff --git a/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/row/RowTest.php b/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/row/RowTest.php index 3176d6be84a88e0712f86afe143bb7bd31304f84..771ac8f32074fda587c82fb8ef82f7e632df372b 100644 --- a/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/row/RowTest.php +++ b/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/row/RowTest.php @@ -33,6 +33,29 @@ class RowTest extends RowPluginBase { */ public $output; + /** + * Overrides Drupal\views\Plugin\views\row\RowPluginBase::defineOptions(). + */ + protected function defineOptions() { + $options = parent::defineOptions(); + $options['test_option'] = array('default' => ''); + + return $options; + } + + /** + * Overrides Drupal\views\Plugin\views\row\RowPluginBase::buildOptionsForm(). + */ + public function buildOptionsForm(&$form, &$form_state) { + parent::buildOptionsForm($form, $form_state); + + $form['test_option'] = array( + '#type' => 'textfield', + '#description' => t('This is a textfield for test_option.'), + '#default_value' => $this->options['test_option'], + ); + } + /** * Sets the output property. * diff --git a/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/style/StyleTest.php b/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/style/StyleTest.php index 27b21933fae342cc543a445ca922b8c84563ca15..59dc396ad240da3e208d6cbe2014da88a494127b 100644 --- a/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/style/StyleTest.php +++ b/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/style/StyleTest.php @@ -33,6 +33,29 @@ class StyleTest extends StylePluginBase { */ public $output; + /** + * Overrides Drupal\views\Plugin\views\style\StylePluginBase::defineOptions(). + */ + protected function defineOptions() { + $options = parent::defineOptions(); + $options['test_option'] = array('default' => ''); + + return $options; + } + + /** + * Overrides Drupal\views\Plugin\views\style\StylePluginBase::buildOptionsForm(). + */ + public function buildOptionsForm(&$form, &$form_state) { + parent::buildOptionsForm($form, $form_state); + + $form['test_option'] = array( + '#type' => 'textfield', + '#description' => t('This is a textfield for test_option.'), + '#default_value' => $this->options['test_option'], + ); + } + function usesRowPlugin() { return parent::usesRowPlugin(); } diff --git a/views_ui/lib/Drupal/views_ui/ViewUI.php b/views_ui/lib/Drupal/views_ui/ViewUI.php index fcd5d2f1a46ae649e8e73799aa5a1913a127d9dd..6c92498833e109dff7eb06783380b19c66000da7 100644 --- a/views_ui/lib/Drupal/views_ui/ViewUI.php +++ b/views_ui/lib/Drupal/views_ui/ViewUI.php @@ -917,8 +917,7 @@ public function getFormBucket($type, $display) { break; case 'field': // Fetch the style plugin info so we know whether to list fields or not. - $style = $this->displayHandlers[$display['id']]->getOption('style'); - $style_plugin = $this->displayHandlers[$display['id']]->getPlugin('style', $style['type']); + $style_plugin = $this->displayHandlers[$display['id']]->getPlugin('style'); $uses_fields = $style_plugin && $style_plugin->usesFields(); if (!$uses_fields) { $build['fields'][] = array(