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..50cfb87 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,9 +37,32 @@ public function render($empty = FALSE) { return array(); } public function buildOptionsForm(&$form, &$form_state) { - $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.') . '
', + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + '@table' => $this->definition['original_configuration']['table'], + '@field' => $this->definition['original_configuration']['field'], ); + + if ($this->isOptional()) { + $form['markup'] = array( + '#markup' => '
' . t('The handler for this item is optional. The following handler is optional: +- Module: @module +- Table: @table +- Field: @field + +Enabling the appropriate module will may solve this issue. Otherwise try to look whether there is a module update available.', $args) . '
', + ); + } + else { + $form['markup'] = array( + '#markup' => '
' . t('The handler for this item is broken or missing. The following handler is missing: +- Module: @module +- Table: @table +- Field: @field + +Enabling the appropriate module may solve this issue. Otherwise try to look whether there is a module update available.', $args) . '
', + ); + } } /** 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..55c9c53 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,16 +19,42 @@ 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) { - $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.') . '
', + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + '@table' => $this->definition['original_configuration']['table'], + '@field' => $this->definition['original_configuration']['field'], ); + + if ($this->isOptional()) { + $form['markup'] = array( + '#markup' => '
' . t('The handler for this item is optional. The following handler is optional: +- Module: @module +- Table: @table +- Field: @field + +Enabling the appropriate module will may solve this issue. Otherwise try to look whether there is a module update available.', $args) . '
', + ); + } + else { + $form['markup'] = array( + '#markup' => '
' . t('The handler for this item is broken or missing. The following handler is missing: +- Module: @module +- Table: @table +- Field: @field + +Enabling the appropriate module may solve this issue. Otherwise try to look whether there is a module update available.', $args) . '
', + ); + } } /** 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..9afa63b 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,16 +19,42 @@ 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) { - $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.') . '
', + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + '@table' => $this->definition['original_configuration']['table'], + '@field' => $this->definition['original_configuration']['field'], ); + + if ($this->isOptional()) { + $form['markup'] = array( + '#markup' => '
' . t('The handler for this item is optional. The following handler is optional: +- Module: @module +- Table: @table +- Field: @field + +Enabling the appropriate module will may solve this issue. Otherwise try to look whether there is a module update available.', $args) . '
', + ); + } + else { + $form['markup'] = array( + '#markup' => '
' . t('The handler for this item is broken or missing. The following handler is missing: +- Module: @module +- Table: @table +- Field: @field + +Enabling the appropriate module may solve this issue. Otherwise try to look whether there is a module update available.', $args) . '
', + ); + } } /** 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..23b9dab 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,16 +27,42 @@ 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) { - $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.') . '
', + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + '@table' => $this->definition['original_configuration']['table'], + '@field' => $this->definition['original_configuration']['field'], ); + + if ($this->isOptional()) { + $form['markup'] = array( + '#markup' => '
' . t('The handler for this item is optional. The following handler is optional: +- Module: @module +- Table: @table +- Field: @field + +Enabling the appropriate module will may solve this issue. Otherwise try to look whether there is a module update available.', $args) . '
', + ); + } + else { + $form['markup'] = array( + '#markup' => '
' . t('The handler for this item is broken or missing. The following handler is missing: +- Module: @module +- Table: @table +- Field: @field + +Enabling the appropriate module may solve this issue. Otherwise try to look whether there is a module update available.', $args) . '
', + ); + } } /** 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..6312fec 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,16 +19,42 @@ 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) { - $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.') . '
', + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + '@table' => $this->definition['original_configuration']['table'], + '@field' => $this->definition['original_configuration']['field'], ); + + if ($this->isOptional()) { + $form['markup'] = array( + '#markup' => '
' . t('The handler for this item is optional. The following handler is optional: +- Module: @module +- Table: @table +- Field: @field + +Enabling the appropriate module will may solve this issue. Otherwise try to look whether there is a module update available.', $args) . '
', + ); + } + else { + $form['markup'] = array( + '#markup' => '
' . t('The handler for this item is broken or missing. The following handler is missing: +- Module: @module +- Table: @table +- Field: @field + +Enabling the appropriate module may solve this issue. Otherwise try to look whether there is a module update available.', $args) . '
', + ); + } } /** 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..4bd460d 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,16 +19,42 @@ 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) { - $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.') . '
', + $args = array( + '@module' => $this->definition['original_configuration']['provider'], + '@table' => $this->definition['original_configuration']['table'], + '@field' => $this->definition['original_configuration']['field'], ); + + if ($this->isOptional()) { + $form['markup'] = array( + '#markup' => '
' . t('The handler for this item is optional. The following handler is optional: +- Module: @module +- Table: @table +- Field: @field + +Enabling the appropriate module will may solve this issue. Otherwise try to look whether there is a module update available.', $args) . '
', + ); + } + else { + $form['markup'] = array( + '#markup' => '
' . t('The handler for this item is broken or missing. The following handler is missing: +- Module: @module +- Table: @table +- Field: @field + +Enabling the appropriate module may solve this issue. Otherwise try to look whether there is a module update available.', $args) . '
', + ); + } } /** 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..5d10958 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 @@ -102,11 +102,12 @@ public function buildForm(array $form, array &$form_state) { // If this relationship is valid for this type, add it to the list. $data = Views::viewsData()->get($relationship['table']); - $base = $data[$relationship['field']]['relationship']['base']; - $base_fields = Views::viewsDataHelper()->fetchFields($base, $form_state['type'], $executable->display_handler->useGroupBy()); - if (isset($base_fields[$item['table'] . '.' . $item['field']])) { - $relationship_handler->init($executable, $executable->display_handler, $relationship); - $relationship_options[$relationship['id']] = $relationship_handler->adminLabel(); + if (isset($data[$relationship['field']]['relationship']['base']) && $base = $data[$relationship['field']]['relationship']['base']) { + $base_fields = Views::viewsDataHelper()->fetchFields($base, $form_state['type'], $executable->display_handler->useGroupBy()); + if (isset($base_fields[$item['table'] . '.' . $item['field']])) { + $relationship_handler->init($executable, $executable->display_handler, $relationship); + $relationship_options[$relationship['id']] = $relationship_handler->adminLabel(); + } } } @@ -142,8 +143,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'], 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..dca09c3 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( @@ -73,7 +74,7 @@ protected function viewsData() { /** * Tests UI CRUD. */ - public function testUICRUD() { + public function ptestUICRUD() { $handler_types = ViewExecutable::viewsHandlerTypes(); foreach ($handler_types as $type => $type_info) { // Test adding handlers. @@ -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.'); + } + } + }