1<?php 2 3namespace Drupal\Tests\views\Kernel; 4 5use Drupal\Component\Render\FormattableMarkup; 6use Drupal\Core\Form\FormState; 7use Drupal\views\Plugin\views\area\Broken as BrokenArea; 8use Drupal\views\Plugin\views\field\Broken as BrokenField; 9use Drupal\views\Plugin\views\filter\Broken as BrokenFilter; 10use Drupal\views\Plugin\views\filter\Standard; 11use Drupal\views\Views; 12 13/** 14 * Tests basic functions from the Views module. 15 * 16 * @group views 17 */ 18class ModuleTest extends ViewsKernelTestBase { 19 20 /** 21 * Views used by this test. 22 * 23 * @var array 24 */ 25 public static $testViews = ['test_view_status', 'test_view', 'test_argument']; 26 27 /** 28 * Modules to enable. 29 * 30 * @var array 31 */ 32 protected static $modules = ['field', 'user', 'block']; 33 34 /** 35 * Stores the last triggered error. 36 * 37 * @var string 38 * 39 * @see \Drupal\views\Tests\ModuleTest::errorHandler() 40 */ 41 protected $lastErrorMessage; 42 43 /** 44 * Tests the ViewsHandlerManager::getHandler() method. 45 * 46 * @see \Drupal\views\Plugin\ViewsHandlerManager::getHandler() 47 */ 48 public function testViewsGetHandler() { 49 $types = [ 50 'field' => BrokenField::class, 51 'area' => BrokenArea::class, 52 'filter' => BrokenFilter::class, 53 ]; 54 // Test non-existent tables/fields. 55 $items = [ 56 [ 57 'table' => 'table_invalid', 58 'field' => 'id', 59 ], 60 [ 61 'table' => 'views_test_data', 62 'field' => 'field_invalid', 63 ], 64 ]; 65 $form_state = new FormState(); 66 $description_top = '<p>The handler for this item is broken or missing. The following details are available:</p>'; 67 $description_bottom = '<p>Enabling the appropriate module may solve this issue. Otherwise, check to see if there is a module update available.</p>'; 68 foreach ($types as $type => $class) { 69 foreach ($items as $item) { 70 $handler = $this->container->get('plugin.manager.views.' . $type) 71 ->getHandler($item); 72 $this->assertTrue($handler instanceof $class); 73 // Make sure details available at edit form. 74 $form = []; 75 $handler->buildOptionsForm($form, $form_state); 76 $this->assertEquals($description_top, $form['description']['description_top']['#markup']); 77 $this->assertEquals($description_bottom, $form['description']['description_bottom']['#markup']); 78 $details = []; 79 foreach ($item as $key => $value) { 80 $details[] = new FormattableMarkup('@key: @value', ['@key' => $key, '@value' => $value]); 81 } 82 $this->assertEquals($details, $form['description']['detail_list']['#items']); 83 } 84 } 85 86 $views_data = $this->viewsData(); 87 $test_tables = ['views_test_data' => ['id', 'name']]; 88 foreach ($test_tables as $table => $fields) { 89 foreach ($fields as $field) { 90 $data = $views_data[$table][$field]; 91 $item = [ 92 'table' => $table, 93 'field' => $field, 94 ]; 95 foreach ($data as $id => $field_data) { 96 if (!in_array($id, ['title', 'help'])) { 97 $handler = $this->container->get('plugin.manager.views.' . $id)->getHandler($item); 98 $this->assertInstanceHandler($handler, $table, $field, $id); 99 } 100 } 101 } 102 } 103 104 // Test the override handler feature. 105 $item = [ 106 'table' => 'views_test_data', 107 'field' => 'job', 108 ]; 109 $handler = $this->container->get('plugin.manager.views.filter')->getHandler($item, 'standard'); 110 $this->assertInstanceOf(Standard::class, $handler); 111 } 112 113 /** 114 * Tests the load wrapper/helper functions. 115 */ 116 public function testLoadFunctions() { 117 $this->enableModules(['text', 'node']); 118 $this->installEntitySchema('node'); 119 $this->installConfig(['node']); 120 $storage = $this->container->get('entity_type.manager')->getStorage('view'); 121 122 // Test views_view_is_enabled/disabled. 123 $archive = $storage->load('archive'); 124 $this->assertTrue(views_view_is_disabled($archive), 'views_view_is_disabled works as expected.'); 125 // Enable the view and check this. 126 $archive->enable(); 127 $this->assertTrue(views_view_is_enabled($archive), ' views_view_is_enabled works as expected.'); 128 129 // We can store this now, as we have enabled/disabled above. 130 $all_views = $storage->loadMultiple(); 131 132 // Test Views::getAllViews(). 133 ksort($all_views); 134 $this->assertEquals(array_keys($all_views), array_keys(Views::getAllViews()), 'Views::getAllViews works as expected.'); 135 136 // Test Views::getEnabledViews(). 137 $expected_enabled = array_filter($all_views, function ($view) { 138 return views_view_is_enabled($view); 139 }); 140 $this->assertEquals(array_keys($expected_enabled), array_keys(Views::getEnabledViews()), 'Expected enabled views returned.'); 141 142 // Test Views::getDisabledViews(). 143 $expected_disabled = array_filter($all_views, function ($view) { 144 return views_view_is_disabled($view); 145 }); 146 $this->assertEquals(array_keys($expected_disabled), array_keys(Views::getDisabledViews()), 'Expected disabled views returned.'); 147 148 // Test Views::getViewsAsOptions(). 149 // Test the $views_only parameter. 150 $this->assertSame(array_keys($all_views), array_keys(Views::getViewsAsOptions(TRUE)), 'Expected option keys for all views were returned.'); 151 $expected_options = []; 152 foreach ($all_views as $id => $view) { 153 $expected_options[$id] = $view->label(); 154 } 155 $this->assertSame($expected_options, Views::getViewsAsOptions(TRUE), 'Expected options array was returned.'); 156 157 // Test the default. 158 $this->assertEquals($this->formatViewOptions($all_views), Views::getViewsAsOptions(), 'Expected options array for all views was returned.'); 159 // Test enabled views. 160 $this->assertEquals($this->formatViewOptions($expected_enabled), Views::getViewsAsOptions(FALSE, 'enabled'), 'Expected enabled options array was returned.'); 161 // Test disabled views. 162 $this->assertEquals($this->formatViewOptions($expected_disabled), Views::getViewsAsOptions(FALSE, 'disabled'), 'Expected disabled options array was returned.'); 163 164 // Test the sort parameter. 165 $all_views_sorted = $all_views; 166 ksort($all_views_sorted); 167 $this->assertSame(array_keys($all_views_sorted), array_keys(Views::getViewsAsOptions(TRUE, 'all', NULL, FALSE, TRUE)), 'All view id keys returned in expected sort order'); 168 169 // Test $exclude_view parameter. 170 $this->assertArrayNotHasKey('archive', Views::getViewsAsOptions(TRUE, 'all', 'archive')); 171 $this->assertArrayNotHasKey('archive:default', Views::getViewsAsOptions(FALSE, 'all', 'archive:default')); 172 $this->assertArrayNotHasKey('archive', Views::getViewsAsOptions(TRUE, 'all', $archive->getExecutable())); 173 174 // Test the $opt_group parameter. 175 $expected_opt_groups = []; 176 foreach ($all_views as $view) { 177 foreach ($view->get('display') as $display) { 178 $expected_opt_groups[$view->id()][$view->id() . ':' . $display['id']] = (string) t('@view : @display', ['@view' => $view->id(), '@display' => $display['id']]); 179 } 180 } 181 $this->assertEquals($expected_opt_groups, Views::getViewsAsOptions(FALSE, 'all', NULL, TRUE), 'Expected option array for an option group returned.'); 182 } 183 184 /** 185 * Tests view enable and disable procedural wrapper functions. 186 */ 187 public function testStatusFunctions() { 188 $view = Views::getView('test_view_status')->storage; 189 190 $this->assertFalse($view->status(), 'The view status is disabled.'); 191 192 views_enable_view($view); 193 $this->assertTrue($view->status(), 'A view has been enabled.'); 194 $this->assertEquals(views_view_is_enabled($view), $view->status(), 'views_view_is_enabled is correct.'); 195 196 views_disable_view($view); 197 $this->assertFalse($view->status(), 'A view has been disabled.'); 198 $this->assertEquals(views_view_is_disabled($view), !$view->status(), 'views_view_is_disabled is correct.'); 199 } 200 201 /** 202 * Tests the \Drupal\views\Views::fetchPluginNames() method. 203 */ 204 public function testViewsFetchPluginNames() { 205 // All style plugins should be returned, as we have not specified a type. 206 $plugins = Views::fetchPluginNames('style'); 207 $definitions = $this->container->get('plugin.manager.views.style')->getDefinitions(); 208 $expected = []; 209 foreach ($definitions as $id => $definition) { 210 $expected[$id] = $definition['title']; 211 } 212 asort($expected); 213 $this->assertSame(array_keys($expected), array_keys($plugins)); 214 215 // Test using the 'test' style plugin type only returns the test_style and 216 // mapping_test plugins. 217 $plugins = Views::fetchPluginNames('style', 'test'); 218 $this->assertSame(['mapping_test', 'test_style', 'test_template_style'], array_keys($plugins)); 219 220 // Test a non existent style plugin type returns no plugins. 221 $plugins = Views::fetchPluginNames('style', $this->randomString()); 222 $this->assertSame([], $plugins); 223 } 224 225 /** 226 * Tests the \Drupal\views\Views::pluginList() method. 227 */ 228 public function testViewsPluginList() { 229 $plugin_list = Views::pluginList(); 230 // Only plugins used by 'test_view' should be in the plugin list. 231 foreach (['display:default', 'pager:none'] as $key) { 232 list($plugin_type, $plugin_id) = explode(':', $key); 233 $plugin_def = $this->container->get("plugin.manager.views.$plugin_type")->getDefinition($plugin_id); 234 235 $this->assertTrue(isset($plugin_list[$key]), new FormattableMarkup('The expected @key plugin list key was found.', ['@key' => $key])); 236 $plugin_details = $plugin_list[$key]; 237 238 $this->assertEquals($plugin_type, $plugin_details['type'], 'The expected plugin type was found.'); 239 $this->assertEquals($plugin_def['title'], $plugin_details['title'], 'The expected plugin title was found.'); 240 $this->assertEquals($plugin_def['provider'], $plugin_details['provider'], 'The expected plugin provider was found.'); 241 $this->assertContains('test_view', $plugin_details['views'], 'The test_view View was found in the list of views using this plugin.'); 242 } 243 } 244 245 /** 246 * Tests views.module: views_embed_view(). 247 */ 248 public function testViewsEmbedView() { 249 /** @var \Drupal\Core\Render\RendererInterface $renderer */ 250 $renderer = \Drupal::service('renderer'); 251 252 $result = views_embed_view('test_argument'); 253 $renderer->renderPlain($result); 254 $this->assertCount(5, $result['view_build']['#view']->result); 255 256 $result = views_embed_view('test_argument', 'default', 1); 257 $renderer->renderPlain($result); 258 $this->assertCount(1, $result['view_build']['#view']->result); 259 260 $result = views_embed_view('test_argument', 'default', '1,2'); 261 $renderer->renderPlain($result); 262 $this->assertCount(2, $result['view_build']['#view']->result); 263 264 $result = views_embed_view('test_argument', 'default', '1,2', 'John'); 265 $renderer->renderPlain($result); 266 $this->assertCount(1, $result['view_build']['#view']->result); 267 268 $result = views_embed_view('test_argument', 'default', '1,2', 'John,George'); 269 $renderer->renderPlain($result); 270 $this->assertCount(2, $result['view_build']['#view']->result); 271 } 272 273 /** 274 * Tests the \Drupal\views\ViewsExecutable::preview() method. 275 */ 276 public function testViewsPreview() { 277 $view = Views::getView('test_argument'); 278 $result = $view->preview('default'); 279 $this->assertCount(5, $result['#view']->result); 280 281 $view = Views::getView('test_argument'); 282 $result = $view->preview('default', ['0' => 1]); 283 $this->assertCount(1, $result['#view']->result); 284 285 $view = Views::getView('test_argument'); 286 $result = $view->preview('default', ['3' => 1]); 287 $this->assertCount(1, $result['#view']->result); 288 289 $view = Views::getView('test_argument'); 290 $result = $view->preview('default', ['0' => '1,2']); 291 $this->assertCount(2, $result['#view']->result); 292 293 $view = Views::getView('test_argument'); 294 $result = $view->preview('default', ['3' => '1,2']); 295 $this->assertCount(2, $result['#view']->result); 296 297 $view = Views::getView('test_argument'); 298 $result = $view->preview('default', ['0' => '1,2', '1' => 'John']); 299 $this->assertCount(1, $result['#view']->result); 300 301 $view = Views::getView('test_argument'); 302 $result = $view->preview('default', ['3' => '1,2', '4' => 'John']); 303 $this->assertCount(1, $result['#view']->result); 304 305 $view = Views::getView('test_argument'); 306 $result = $view->preview('default', ['0' => '1,2', '1' => 'John,George']); 307 $this->assertCount(2, $result['#view']->result); 308 309 $view = Views::getView('test_argument'); 310 $result = $view->preview('default', ['3' => '1,2', '4' => 'John,George']); 311 $this->assertCount(2, $result['#view']->result); 312 } 313 314 /** 315 * Helper to return an expected views option array. 316 * 317 * @param array $views 318 * An array of Drupal\views\Entity\View objects for which to 319 * create an options array. 320 * 321 * @return array 322 * A formatted options array that matches the expected output. 323 */ 324 protected function formatViewOptions(array $views = []) { 325 $expected_options = []; 326 foreach ($views as $view) { 327 foreach ($view->get('display') as $display) { 328 $expected_options[$view->id() . ':' . $display['id']] = (string) t('View: @view - Display: @display', 329 ['@view' => $view->id(), '@display' => $display['id']]); 330 } 331 } 332 333 return $expected_options; 334 } 335 336 /** 337 * Ensure that a certain handler is an instance of a certain table/field. 338 */ 339 public function assertInstanceHandler($handler, $table, $field, $id) { 340 $table_data = $this->container->get('views.views_data')->get($table); 341 $field_data = $table_data[$field][$id]; 342 343 $this->assertEquals($handler->getPluginId(), $field_data['id']); 344 } 345 346} 347