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 a96bc47da49..3b88f0601b6 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php @@ -873,7 +873,7 @@ abstract class HandlerBase extends PluginBase { // Create a new handler and unpack the options from the form onto it. We // can use that for storage. - $handler = views_get_handler($item['table'], $item['field'], $handler_type, $override); + $handler = views_get_handler($item, $handler_type, $override); $handler->init($executable, $executable->display_handler, $item); // Add the incoming options to existing options because items using diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php index be42ee55767..36456217ade 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php @@ -876,8 +876,7 @@ abstract class DisplayPluginBase extends PluginBase { $handler_type = $type; } - $handler = views_get_handler($info['table'], $info['field'], $handler_type, $override); - if ($handler) { + if ($handler = views_get_handler($info, $handler_type, $override)) { // Special override for area types so they know where they come from. if ($handler instanceof AreaPluginBase) { $handler->areaType = $type; diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/exposed_form/InputRequired.php b/core/modules/views/lib/Drupal/views/Plugin/views/exposed_form/InputRequired.php index 3afcabcfddc..9cb023a2081 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/exposed_form/InputRequired.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/exposed_form/InputRequired.php @@ -83,7 +83,7 @@ class InputRequired extends ExposedFormPluginBase { 'content' => $this->options['text_input_required'], 'format' => $this->options['text_input_required_format'], ); - $handler = views_get_handler('views', 'area', 'area'); + $handler = views_get_handler($options, 'area'); $handler->init($this->view, $options); $this->displayHandler->handlers['empty'] = array( 'area' => $handler, diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/row/RowPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/row/RowPluginBase.php index e2ac1299260..635122c5269 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/row/RowPluginBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/row/RowPluginBase.php @@ -71,7 +71,7 @@ abstract class RowPluginBase extends PluginBase { $relationship_options = array(); foreach ($relationships as $relationship) { - $relationship_handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship'); + $relationship_handler = views_get_handler($relationship, 'relationship'); // If this relationship is valid for this type, add it to the list. $data = Views::viewsData()->get($relationship['table']); diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/sort/GroupByNumeric.php b/core/modules/views/lib/Drupal/views/Plugin/views/sort/GroupByNumeric.php index ad270f1d703..31452f57f0c 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/sort/GroupByNumeric.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/sort/GroupByNumeric.php @@ -25,7 +25,7 @@ class GroupByNumeric extends SortPluginBase { parent::init($view, $display, $options); // Initialize the original handler. - $this->handler = views_get_handler($options['table'], $options['field'], 'sort'); + $this->handler = views_get_handler($options, 'sort'); $this->handler->init($view, $display, $options); } diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php index 5dfa29b4a1c..d5f2eac70e9 100644 --- a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php @@ -525,15 +525,21 @@ class FieldUnitTest extends ViewUnitTestBase { */ public function testClickSortable() { // Test that click_sortable is TRUE by default. - $plugin = views_get_handler('views_test_data', 'name', 'field'); + $item = array( + 'table' => 'views_test_data', + 'field' => 'name', + ); + $plugin = views_get_handler($item, 'field'); $this->assertTrue($plugin->click_sortable(), 'TRUE as a default value is correct.'); // Test that click_sortable is TRUE by when set TRUE in the data. - $plugin = views_get_handler('views_test_data', 'id', 'field'); + $item['field'] = 'id'; + $plugin = views_get_handler($item, 'field'); $this->assertTrue($plugin->click_sortable(), 'TRUE as a views data value is correct.'); // Test that click_sortable is FALSE by when set FALSE in the data. - $plugin = views_get_handler('views_test_data', 'job', 'field'); + $item['field'] = 'job'; + $plugin = views_get_handler($item, 'field'); $this->assertFalse($plugin->click_sortable(), 'FALSE as a views data value is correct.'); } diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/HandlerAllTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/HandlerAllTest.php index 4e77b357566..78e768c4959 100644 --- a/core/modules/views/lib/Drupal/views/Tests/Handler/HandlerAllTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/Handler/HandlerAllTest.php @@ -72,11 +72,15 @@ class HandlerAllTest extends HandlerTestBase { foreach ($info as $field => $field_info) { // Table is a reserved key for the metainformation. if ($field != 'table' && !in_array("$base_table:$field", $exclude)) { + $item = array( + 'table' => $base_table, + 'field' => $field, + ); foreach ($object_types as $type) { if (isset($field_info[$type]['id'])) { $options = array(); if ($type == 'filter') { - $handler = views_get_handler($base_table, $field, $type); + $handler = views_get_handler($item, $type); if ($handler instanceof InOperator) { $options['value'] = array(1); } diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/HandlerTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/HandlerTest.php index 28cc00c21a5..05b3665be15 100644 --- a/core/modules/views/lib/Drupal/views/Tests/Handler/HandlerTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/Handler/HandlerTest.php @@ -101,7 +101,11 @@ class HandlerTest extends ViewTestBase { $null = NULL; $this->assertEqual($empty_stdclass, HandlerBase::breakPhraseString('', $null)); - $handler = views_get_handler('node', 'title', 'argument'); + $item = array( + 'table' => 'node', + 'field' => 'title', + ); + $handler = views_get_handler($item, 'argument'); $this->assertEqual($handler, HandlerBase::breakPhraseString('', $handler), 'The breakPhraseString() method works correctly.'); // test ors @@ -156,7 +160,11 @@ class HandlerTest extends ViewTestBase { // check defaults $this->assertEqual($empty_stdclass, HandlerBase::breakPhrase('', $null)); - $handler = views_get_handler('node', 'title', 'argument'); + $item = array( + 'table' => 'node', + 'field' => 'title', + ); + $handler = views_get_handler($item, 'argument'); $this->assertEqual($handler, HandlerBase::breakPhrase('', $handler), 'The breakPhrase() method works correctly.'); // Generate three random numbers which can be used below; diff --git a/core/modules/views/lib/Drupal/views/Tests/ModuleTest.php b/core/modules/views/lib/Drupal/views/Tests/ModuleTest.php index 7831e3d7188..769efdd32c8 100644 --- a/core/modules/views/lib/Drupal/views/Tests/ModuleTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/ModuleTest.php @@ -10,6 +10,7 @@ namespace Drupal\views\Tests; /** * Tests basic functions from the Views module. */ +use Drupal\views\Plugin\views\filter\Standard; use Drupal\views\Views; class ModuleTest extends ViewUnitTestBase { @@ -21,6 +22,15 @@ class ModuleTest extends ViewUnitTestBase { */ public static $testViews = array('test_view_status'); + /** + * Stores the last triggered error, for example via debug(). + * + * @var string + * + * @see \Drupal\views\Tests\ModuleTest::errorHandler() + */ + protected $lastErrorMessage; + public static function getInfo() { return array( 'name' => 'Views Module tests', @@ -31,11 +41,17 @@ class ModuleTest extends ViewUnitTestBase { /** * Tests the views_get_handler method. + * + * @see views_get_handler() */ - function testviews_get_handler() { + public function testViewsGetHandler() { $types = array('field', 'area', 'filter'); foreach ($types as $type) { - $handler = views_get_handler($this->randomName(), $this->randomName(), $type); + $item = array( + 'table' => $this->randomName(), + 'field' => $this->randomName(), + ); + $handler = views_get_handler($item, $type); $this->assertEqual('Drupal\views\Plugin\views\\' . $type . '\Broken', get_class($handler), t('Make sure that a broken handler of type: @type are created', array('@type' => $type))); } @@ -44,9 +60,13 @@ class ModuleTest extends ViewUnitTestBase { foreach ($test_tables as $table => $fields) { foreach ($fields as $field) { $data = $views_data[$table][$field]; + $item = array( + 'table' => $table, + 'field' => $field, + ); foreach ($data as $id => $field_data) { if (!in_array($id, array('title', 'help'))) { - $handler = views_get_handler($table, $field, $id); + $handler = views_get_handler($item, $id); $this->assertInstanceHandler($handler, $table, $field, $id); } } @@ -54,8 +74,73 @@ class ModuleTest extends ViewUnitTestBase { } // Test the override handler feature. - $handler = views_get_handler('views_test_data', 'job', 'filter', 'standard'); - $this->assertEqual('Drupal\\views\\Plugin\\views\\filter\\Standard', get_class($handler)); + $item = array( + 'table' => 'views_test_data', + 'field' => 'job', + ); + $handler = views_get_handler($item, 'filter', 'standard'); + $this->assertTrue($handler instanceof Standard); + + // Test non-existent tables/fields. + set_error_handler(array($this, 'customErrorHandler')); + $item = array( + 'table' => 'views_test_data', + 'field' => 'field_invalid', + ); + views_get_handler($item, 'field'); + $this->assertTrue(strpos($this->lastErrorMessage, format_string("Missing handler: @table @field @type", array('@table' => 'views_test_data', '@field' => 'field_invalid', '@type' => 'field'))) !== FALSE, 'An invalid field name throws a debug message.'); + unset($this->lastErrorMessage); + + $item = array( + 'table' => 'table_invalid', + 'field' => 'id', + ); + views_get_handler($item, 'filter'); + $this->assertEqual(strpos($this->lastErrorMessage, format_string("Missing handler: @table @field @type", array('@table' => 'table_invalid', '@field' => 'id', '@type' => 'filter'))) !== FALSE, 'An invalid table name throws a debug message.'); + unset($this->lastErrorMessage); + + $item = array( + 'table' => 'table_invalid', + 'field' => 'id', + 'optional' => FALSE, + ); + views_get_handler($item, 'filter'); + $this->assertEqual(strpos($this->lastErrorMessage, format_string("Missing handler: @table @field @type", array('@table' => 'table_invalid', '@field' => 'id', '@type' => 'filter'))) !== FALSE, 'An invalid table name throws a debug message.'); + unset($this->lastErrorMessage); + + $item = array( + 'table' => 'table_invalid', + 'field' => 'id', + 'optional' => TRUE, + ); + + views_get_handler($item, 'filter'); + $this->assertFalse($this->lastErrorMessage, "An optional handler does not throw a debug message."); + unset($this->lastErrorMessage); + + restore_error_handler(); + } + + /** + * Defines an error handler which is used in the test. + * + * @param int $error_level + * The level of the error raised. + * @param string $message + * The error message. + * @param string $filename + * The filename that the error was raised in. + * @param int $line + * The line number the error was raised at. + * @param array $context + * An array that points to the active symbol table at the point the error + * occurred. + * + * Because this is registered in set_error_handler(), it has to be public. + * @see set_error_handler() + */ + public function customErrorHandler($error_level, $message, $filename, $line, $context) { + $this->lastErrorMessage = $message; } /** diff --git a/core/modules/views/views.module b/core/modules/views/views.module index 7f383262107..d3373187c49 100644 --- a/core/modules/views/views.module +++ b/core/modules/views/views.module @@ -880,21 +880,26 @@ function views_library_info() { /** * Fetch a handler from the data cache. * - * @param $table - * The name of the table this handler is from. - * @param $field - * The name of the field this handler is from. - * @param $type + * @param array $item + * An associative array representing the handler to be retrieved: + * - table: The name of the table containing the handler. + * - field: The name of the field the handler represents. + * - optional: (optional) Whether or not this handler is optional. If a + * handler is missing and not optional, a debug message will be displayed. + * Defaults to FALSE. + * @param string $type * The type of handler. i.e, sort, field, argument, filter, relationship - * @param $override - * Override the actual handler object with this class. Used for - * aggregation when the handler is redirected to the aggregation - * handler. + * @param string|null $override + * (optional) Override the actual handler object with this plugin ID. Used for + * aggregation when the handler is redirected to the aggregation handler. * * @return views_handler * An instance of a handler object. May be views_handler_broken. */ -function views_get_handler($table, $field, $type, $override = NULL) { +function views_get_handler($item, $type, $override = NULL) { + $table = $item['table']; + $field = $item['field']; + $optional = isset($item['optional']) ? $item['optional'] : FALSE; // Get the plugin manager for this type. $manager = Views::pluginManager($type);; $data = Views::viewsData()->get($table); @@ -931,8 +936,11 @@ function views_get_handler($table, $field, $type, $override = NULL) { } } + if (!$optional) { + debug(t("Missing handler: @table @field @type", array('@table' => $table, '@field' => $field, '@type' => $type))); + } + // Finally, use the 'broken' handler. - debug(t("Missing handler: @table @field @type", array('@table' => $table, '@field' => $field, '@type' => $type))); return $manager->createInstance('broken'); } diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php index 93564b744a0..606fe442e32 100644 --- a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php +++ b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php @@ -96,7 +96,7 @@ class ConfigItem extends ViewsFormBase { if ($type == 'relationship' && $id == $relationship['id']) { break; } - $relationship_handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship'); + $relationship_handler = views_get_handler($relationship, 'relationship'); // ignore invalid/broken relationships. if (empty($relationship_handler)) { continue; @@ -225,7 +225,7 @@ class ConfigItem extends ViewsFormBase { // Create a new handler and unpack the options from the form onto it. We // can use that for storage. - $handler = views_get_handler($item['table'], $item['field'], $handler_type, $override); + $handler = views_get_handler($item, $handler_type, $override); $handler->init($executable, $executable->display_handler, $item); // Add the incoming options to existing options because items using diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItemGroup.php b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItemGroup.php index 96229d42af9..465c2daa3ec 100644 --- a/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItemGroup.php +++ b/core/modules/views/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItemGroup.php @@ -99,7 +99,7 @@ class ConfigItemGroup extends ViewsFormBase { $type = $form_state['type']; $id = $form_state['id']; - $handler = views_get_handler($item['table'], $item['field'], $type); + $handler = views_get_handler($item, $type); $executable = $form_state['view']->get('executable'); $handler->init($executable, $executable->display_handler, $item); diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php index 066f8d0af22..f0b60f9a1f0 100644 --- a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php +++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewUI.php @@ -458,7 +458,11 @@ class ViewUI implements ViewStorageInterface { if (isset($types[$type]['type'])) { $key = $types[$type]['type']; } - $handler = views_get_handler($table, $field, $key); + $item = array( + 'table' => $table, + 'field' => $field, + ); + $handler = views_get_handler($item, $key); if ($this->executable->displayHandlers->get('default')->useGroupBy() && $handler->usesGroupBy()) { $this->addFormToStack('config-item-group', $form_state['display_id'], $type, $id); }