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.');
+ }
+ }
+
}