diff --git a/core/modules/node/config/views.view.content.yml b/core/modules/node/config/views.view.content.yml index 39f6d60..487b04b 100644 --- a/core/modules/node/config/views.view.content.yml +++ b/core/modules/node/config/views.view.content.yml @@ -279,6 +279,7 @@ display: text: Translate optional: '1' plugin_id: content_translation_link + provider: content_translation dropbutton: id: dropbutton table: views diff --git a/core/modules/views/lib/Drupal/views/Plugin/ViewsHandlerManager.php b/core/modules/views/lib/Drupal/views/Plugin/ViewsHandlerManager.php index 4ac2fac..0a1fb76 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/ViewsHandlerManager.php +++ b/core/modules/views/lib/Drupal/views/Plugin/ViewsHandlerManager.php @@ -77,7 +77,7 @@ public function __construct($handler_type, \Traversable $namespaces, ViewsData $ public function getHandler($item, $override = NULL) { $table = $item['table']; $field = $item['field']; - $optional = isset($item['optional']) ? $item['optional'] : FALSE; + $optional = !empty($item['optional']); // Get the plugin manager for this type. $data = $this->viewsData->get($table); @@ -118,7 +118,7 @@ public function getHandler($item, $override = NULL) { } // Finally, use the 'broken' handler. - return $this->createInstance('broken'); + return $this->createInstance('broken', array('optional' => $optional, 'original_configuration' => $item)); } } diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php index 58a7e53..76805c4 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php @@ -77,11 +77,19 @@ public $relationship = NULL; /** + * Whether or not this handler is optional. + * + * @var bool + */ + protected $optional = FALSE; + + /** * Constructs a Handler object. */ public function __construct(array $configuration, $plugin_id, array $plugin_definition) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->is_handler = TRUE; + $this->optional = !empty($configuration['optional']); } /** @@ -156,6 +164,15 @@ protected function defineOptions() { } /** + * Returns whether this handler is optional. + * + * @return bool + */ + public function isOptional() { + return $this->optional; + } + + /** * Return a string representing this handler's name in the UI. */ public function adminLabel($short = FALSE) { diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/area/Broken.php b/core/modules/views/lib/Drupal/views/Plugin/views/area/Broken.php index 64a63a0..b71bce9 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/area/Broken.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/area/Broken.php @@ -8,6 +8,7 @@ namespace Drupal\views\Plugin\views\area; use Drupal\Component\Annotation\PluginID; +use Drupal\views\ViewExecutable; /** * A special handler to take the place of missing or broken handlers. @@ -19,7 +20,10 @@ class Broken extends AreaPluginBase { public function adminLabel($short = FALSE) { - return t('Broken/missing handler'); + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + ); + return $this->isOptional() ? t('Optional handler is missing (Module: @module)', $args) : t('Broken/missing handler (Module: @module)', $args); } public function defineOptions() { return array(); } @@ -33,6 +37,16 @@ public function render($empty = FALSE) { return array(); } public function buildOptionsForm(&$form, &$form_state) { + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + '@table' => $this->definition['original_configuration']['table'], + '@field' => $this->definition['original_configuration']['field'], + ); + $item = $this->isOptional() ? t('Optional handler is missing (Module: @module, Table: @table, Field: @field)', $args) : t('Broken/missing handler (Module: @module, Table: @table, Field: @Field)', $args); + + $types = ViewExecutable::viewsHandlerTypes(); + $form['#title'] = t('Configure @type: @item', array('@type' => $types[$this->areaType]['lstitle'], '@item' => $item)); + $form['markup'] = array( '#markup' => '
' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '
', ); diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/argument/Broken.php b/core/modules/views/lib/Drupal/views/Plugin/views/argument/Broken.php index d74ab95..2e39ecb 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/argument/Broken.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/argument/Broken.php @@ -19,13 +19,25 @@ class Broken extends ArgumentPluginBase { public function adminLabel($short = FALSE) { - return t('Broken/missing handler'); + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + ); + return $this->isOptional() ? t('Optional handler is missing (Module: @module)', $args) : t('Broken/missing handler (Module: @module)', $args); } public function defineOptions() { return array(); } public function ensureMyTable() { /* No table to ensure! */ } public function query($group_by = FALSE) { /* No query to run */ } public function buildOptionsForm(&$form, &$form_state) { + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + '@table' => $this->definition['original_configuration']['table'], + '@field' => $this->definition['original_configuration']['field'], + ); + $item = $this->isOptional() ? t('Optional handler is missing (Module: @module, Table: @table, Field: @field)', $args) : t('Broken/missing handler (Module: @module, Table: @table, Field: @field)', $args); + + $form['#title'] = t('Configure @type: @item', array('@type' => t('argument'), '@item' => $item)); + $form['markup'] = array( '#markup' => '
' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '
', ); diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/field/Broken.php b/core/modules/views/lib/Drupal/views/Plugin/views/field/Broken.php index 6310248..c1cca74 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/field/Broken.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/Broken.php @@ -19,13 +19,25 @@ class Broken extends FieldPluginBase { public function adminLabel($short = FALSE) { - return t('Broken/missing handler'); + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + ); + return $this->isOptional() ? t('Optional handler is missing (Module: @module)', $args) : t('Broken/missing handler (Module: @module)', $args); } public function defineOptions() { return array(); } public function ensureMyTable() { /* No table to ensure! */ } public function query($group_by = FALSE) { /* No query to run */ } public function buildOptionsForm(&$form, &$form_state) { + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + '@table' => $this->definition['original_configuration']['table'], + '@field' => $this->definition['original_configuration']['field'], + ); + $item = $this->isOptional() ? t('Optional handler is missing (Module: @module, Table: @table, Field: @field)', $args) : t('Broken/missing handler (Module: @module, Table: @table, Field: @field)', $args); + + $form['#title'] = t('Configure @type: @item', array('@type' => t('field'), '@item' => $item)); + $form['markup'] = array( '#markup' => '
' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '
', ); diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/filter/Broken.php b/core/modules/views/lib/Drupal/views/Plugin/views/filter/Broken.php index 701cabb..729501a 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/filter/Broken.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/filter/Broken.php @@ -27,13 +27,25 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o } public function adminLabel($short = FALSE) { - return t('Broken/missing handler'); + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + ); + return $this->isOptional() ? t('Optional handler is missing (Module: @module)', $args) : t('Broken/missing handler (Module: @module)', $args); } public function defineOptions() { return array(); } public function ensureMyTable() { /* No table to ensure! */ } public function query($group_by = FALSE) { /* No query to run */ } public function buildOptionsForm(&$form, &$form_state) { + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + '@table' => $this->definition['original_configuration']['table'], + '@field' => $this->definition['original_configuration']['field'], + ); + $item = $this->isOptional() ? t('Optional handler is missing (Module: @module, Table: @table, Field: @field)', $args) : t('Broken/missing handler (Module: @module, Table: @table, Field: @field)', $args); + + $form['#title'] = t('Configure @type: @item', array('@type' => t('filter'), '@item' => $item)); + $form['markup'] = array( '#markup' => '
' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '
', ); diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/relationship/Broken.php b/core/modules/views/lib/Drupal/views/Plugin/views/relationship/Broken.php index c891f00..7ec5eee 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/relationship/Broken.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/relationship/Broken.php @@ -19,13 +19,25 @@ class Broken extends RelationshipPluginBase { public function adminLabel($short = FALSE) { - return t('Broken/missing handler'); + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + ); + return $this->isOptional() ? t('Optional handler is missing (Module: @module)', $args) : t('Broken/missing handler (Module: @module)', $args); } public function defineOptions() { return array(); } public function ensureMyTable() { /* No table to ensure! */ } public function query() { /* No query to run */ } public function buildOptionsForm(&$form, &$form_state) { + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + '@table' => $this->definition['original_configuration']['table'], + '@field' => $this->definition['original_configuration']['field'], + ); + $item = $this->isOptional() ? t('Optional handler is missing (Module: @module, Table: @table, Field: @field)', $args) : t('Broken/missing handler (Module: @module, Table: @table, Field: @field)', $args); + + $form['#title'] = t('Configure @type: @item', array('@type' => t('relationship'), '@item' => $item)); + $form['markup'] = array( '#markup' => '
' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '
', ); diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/sort/Broken.php b/core/modules/views/lib/Drupal/views/Plugin/views/sort/Broken.php index 341bc8b..bf9ec75 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/sort/Broken.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/sort/Broken.php @@ -19,13 +19,25 @@ class Broken extends SortPluginBase { public function adminLabel($short = FALSE) { - return t('Broken/missing handler'); + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + ); + return $this->isOptional() ? t('Optional handler is missing (Module: @module)', $args) : t('Broken/missing handler (Module: @module)', $args); } public function defineOptions() { return array(); } public function ensureMyTable() { /* No table to ensure! */ } public function query($group_by = FALSE) { /* No query to run */ } public function buildOptionsForm(&$form, &$form_state) { + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + '@table' => $this->definition['original_configuration']['table'], + '@field' => $this->definition['original_configuration']['field'], + ); + $item = $this->isOptional() ? t('Optional handler is missing (Module: @module, Table: @table, Field: @field)', $args) : t('Broken/missing handler (Module: @module, Table: @table, Field: @field)', $args); + + $form['#title'] = t('Configure @type: @item', array('@type' => t('sort'), '@item' => $item)); + $form['markup'] = array( '#markup' => '
' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '
', ); diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_broken.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_broken.yml new file mode 100644 index 0000000..e5870e5 --- /dev/null +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_broken.yml @@ -0,0 +1,89 @@ +base_table: views_test_data +core: '8' +description: '' +status: '1' +display: + default: + display_options: + defaults: + fields: '0' + pager: '0' + pager_options: '0' + sorts: '0' + fields: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + provider: views + filters: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + provider: views + arguments: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + provider: views + sorts: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + order: ASC + provider: views + relationships: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + provider: views + header: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + provider: views + footer: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + provider: views + empty: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + provider: views + pager: + options: + offset: '0' + type: none + pager_options: { } + display_plugin: default + display_title: Master + id: default + position: '0' +label: 'Test view' +id: test_view_broken +tag: '' diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_optional.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_optional.yml new file mode 100644 index 0000000..7068998 --- /dev/null +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_optional.yml @@ -0,0 +1,97 @@ +base_table: views_test_data +core: '8' +description: '' +status: '1' +display: + default: + display_options: + defaults: + fields: '0' + pager: '0' + pager_options: '0' + sorts: '0' + fields: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + optional: 1 + provider: views + filters: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + optional: 1 + provider: views + arguments: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + optional: 1 + provider: views + sorts: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + order: ASC + optional: 1 + provider: views + relationships: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + optional: 1 + provider: views + header: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + optional: 1 + provider: views + footer: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + optional: 1 + provider: views + empty: + id_broken: + field: id_broken + id: id_broken + relationship: none + table: views_test_data + plugin_id: numeric + optional: 1 + provider: views + pager: + options: + offset: '0' + type: none + pager_options: { } + display_plugin: default + display_title: Master + id: default + position: '0' +label: 'Test view' +id: test_view_optional +tag: '' diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php index 1125b2f..d2c9aef 100644 --- a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php +++ b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php @@ -142,8 +142,6 @@ public function buildForm(array $form, array &$form_state) { ); } - $form['#title'] = t('Configure @type: @item', array('@type' => $types[$type]['lstitle'], '@item' => $handler->adminLabel())); - if (!empty($handler->definition['help'])) { $form['options']['form_description'] = array( '#markup' => $handler->definition['help'], @@ -157,6 +155,16 @@ public function buildForm(array $form, array &$form_state) { // Get form from the handler. $handler->buildOptionsForm($form['options'], $form_state); + + // Allow handlers to override the config item form title. + if (isset($form['options']['#title'])) { + $form['#title'] = $form['options']['#title']; + } + else { + $form['#title'] = t('Configure @type: @item', array('@type' => $types[$type]['lstitle'], '@item' => $handler->adminLabel())); + } + + $form_state['handler'] = &$handler; } diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Tests/HandlerTest.php b/core/modules/views_ui/lib/Drupal/views_ui/Tests/HandlerTest.php index f331257..e6f429d 100644 --- a/core/modules/views_ui/lib/Drupal/views_ui/Tests/HandlerTest.php +++ b/core/modules/views_ui/lib/Drupal/views_ui/Tests/HandlerTest.php @@ -7,6 +7,7 @@ namespace Drupal\views_ui\Tests; +use Drupal\Component\Utility\String; use Drupal\views\ViewExecutable; /** @@ -21,7 +22,7 @@ class HandlerTest extends UITestBase { * * @var array */ - public static $testViews = array('test_view_empty'); + public static $testViews = array('test_view_empty', 'test_view_broken', 'test_view_optional'); public static function getInfo() { return array( @@ -143,4 +144,55 @@ public function testUICRUD() { $this->assertTrue(isset($display['display_options'][$type_info['plural']][$id]), 'Ensure the field was added to the view itself.'); } + /** + * Test broken handlers. + */ + public function testBrokenHandlers() { + $this->drupalGet('admin/structure/views/view/test_view_broken/edit'); + + $handler_types = ViewExecutable::viewsHandlerTypes(); + foreach ($handler_types as $type => $type_info) { + $href = "admin/structure/views/nojs/config-item/test_view_broken/default/$type/id_broken"; + + $result = $this->xpath('//a[contains(@href, :href)]', array(':href' => $href)); + $this->assertEqual(count($result), 1, String::format('Handler (%type) edit link found.', array('%type' => $type))); + $args = array( + '@module' => 'views', + '@table' => 'views_test_data', + '@field' => 'id_broken', + ); + + $this->assertTrue(strpos((string) $result[0], t('Broken/missing handler (Module: @module)', $args)) !== FALSE, 'Ensure the broken handler text was found.'); + + $this->drupalGet($href); + $result = $this->xpath('//h1'); + $this->assertTrue(strpos((string) $result[0], t('Broken/missing handler (Module: @module, Table: @table, Field: @field)', $args)) !== FALSE, 'Ensure the broken handler text was found.'); + } + } + + /** + * Test optional handlers. + */ + public function testOptionalHandlers() { + $this->drupalGet('admin/structure/views/view/test_view_optional/edit'); + + $handler_types = ViewExecutable::viewsHandlerTypes(); + foreach ($handler_types as $type => $type_info) { + $href = "admin/structure/views/nojs/config-item/test_view_optional/default/$type/id_broken"; + $result = $this->xpath('//a[contains(@href, :href)]', array(':href' => $href)); + $this->assertEqual(count($result), 1, String::format('Handler (%type) edit link found.', array('%type' => $type))); + $args = array( + '@module' => 'views', + '@table' => 'views_test_data', + '@field' => 'id_broken', + ); + + $this->assertTrue(strpos((string) $result[0], t('Optional handler is missing (Module: @module)', $args)) !== FALSE, 'Ensure the optional handler text was found.'); + + $this->drupalGet($href); + $result = $this->xpath('//h1'); + $this->assertTrue(strpos((string) $result[0], t('Broken/missing handler (Module: @module, Table: @table, Field: @field)', $args)) !== FALSE, 'Ensure the broken handler text was found.'); + } + } + }