annotate core/modules/views/tests/src/Kernel/FieldApiDataTest.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents af1871eacc83
children
rev   line source
Chris@18 1 <?php
Chris@18 2
Chris@18 3 namespace Drupal\Tests\views\Kernel;
Chris@18 4
Chris@18 5 use Drupal\Component\Render\MarkupInterface;
Chris@18 6 use Drupal\field\Entity\FieldConfig;
Chris@18 7 use Drupal\field\Entity\FieldStorageConfig;
Chris@18 8 use Drupal\language\Entity\ConfigurableLanguage;
Chris@18 9 use Drupal\language\Entity\ContentLanguageSettings;
Chris@18 10 use Drupal\node\Entity\Node;
Chris@18 11 use Drupal\node\Entity\NodeType;
Chris@18 12 use Drupal\views\Views;
Chris@18 13
Chris@18 14 /**
Chris@18 15 * Tests the Field Views data.
Chris@18 16 *
Chris@18 17 * @group views
Chris@18 18 */
Chris@18 19 class FieldApiDataTest extends ViewsKernelTestBase {
Chris@18 20
Chris@18 21 /**
Chris@18 22 * {@inheritdoc}
Chris@18 23 */
Chris@18 24 public static $modules = [
Chris@18 25 'field',
Chris@18 26 'filter',
Chris@18 27 'language',
Chris@18 28 'node',
Chris@18 29 'user',
Chris@18 30 ];
Chris@18 31
Chris@18 32 /**
Chris@18 33 * {@inheritdoc}
Chris@18 34 */
Chris@18 35 public static $testViews = ['test_field_config_translation_filter'];
Chris@18 36
Chris@18 37 /**
Chris@18 38 * {@inheritdoc}
Chris@18 39 */
Chris@18 40 protected function setUp($import_test_views = TRUE) {
Chris@18 41 parent::setUp($import_test_views);
Chris@18 42 $this->installEntitySchema('user');
Chris@18 43 $this->installEntitySchema('node');
Chris@18 44 $this->installSchema('node', ['node_access']);
Chris@18 45 }
Chris@18 46
Chris@18 47 /**
Chris@18 48 * Unit testing the views data structure.
Chris@18 49 *
Chris@18 50 * We check data structure for both node and node revision tables.
Chris@18 51 */
Chris@18 52 public function testViewsData() {
Chris@18 53 $field_storage_string = FieldStorageConfig::create([
Chris@18 54 'field_name' => 'field_string',
Chris@18 55 'entity_type' => 'node',
Chris@18 56 'type' => 'string',
Chris@18 57 ]);
Chris@18 58 $field_storage_string->save();
Chris@18 59
Chris@18 60 $field_storage_string_long = FieldStorageConfig::create([
Chris@18 61 'field_name' => 'field_string_long',
Chris@18 62 'entity_type' => 'node',
Chris@18 63 'type' => 'string_long',
Chris@18 64 ]);
Chris@18 65 $field_storage_string_long->save();
Chris@18 66
Chris@18 67 NodeType::create(['type' => 'page'])->save();
Chris@18 68 NodeType::create(['type' => 'article'])->save();
Chris@18 69
Chris@18 70 // Attach the field to nodes.
Chris@18 71 FieldConfig::create([
Chris@18 72 'field_name' => 'field_string',
Chris@18 73 'entity_type' => 'node',
Chris@18 74 'bundle' => 'page',
Chris@18 75 'label' => 'GiraffeA" label',
Chris@18 76 ])->save();
Chris@18 77
Chris@18 78 // Attach the string_long field to the page node type.
Chris@18 79 FieldConfig::create([
Chris@18 80 'field_name' => 'field_string_long',
Chris@18 81 'entity_type' => 'node',
Chris@18 82 'bundle' => 'page',
Chris@18 83 'label' => 'string_long label',
Chris@18 84 ])->save();
Chris@18 85
Chris@18 86 // Attach the same field to a different bundle with a different label.
Chris@18 87 FieldConfig::create([
Chris@18 88 'field_name' => 'field_string',
Chris@18 89 'entity_type' => 'node',
Chris@18 90 'bundle' => 'article',
Chris@18 91 'label' => 'GiraffeB" label',
Chris@18 92 ])->save();
Chris@18 93
Chris@18 94 // Now create some example nodes/users for the view result.
Chris@18 95 for ($i = 0; $i < 5; $i++) {
Chris@18 96 $edit = [
Chris@18 97 'field_string' => [(['value' => $this->randomMachineName()])],
Chris@18 98 ];
Chris@18 99 $nodes[] = Node::create(['type' => 'page'] + $edit);
Chris@18 100 }
Chris@18 101
Chris@18 102 /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
Chris@18 103 $table_mapping = $this->container->get('entity_type.manager')
Chris@18 104 ->getStorage('node')
Chris@18 105 ->getTableMapping();
Chris@18 106
Chris@18 107 $current_table = $table_mapping->getDedicatedDataTableName($field_storage_string);
Chris@18 108 $revision_table = $table_mapping->getDedicatedRevisionTableName($field_storage_string);
Chris@18 109 $data = $this->getViewsData();
Chris@18 110
Chris@18 111 $this->assertArrayHasKey($current_table, $data);
Chris@18 112 $this->assertArrayHasKey($revision_table, $data);
Chris@18 113
Chris@18 114 // The node field should join against node_field_data.
Chris@18 115 $this->assertArrayHasKey('node_field_data', $data[$current_table]['table']['join']);
Chris@18 116 $this->assertArrayHasKey('node_field_revision', $data[$revision_table]['table']['join']);
Chris@18 117
Chris@18 118 $expected_join = [
Chris@18 119 'table' => $current_table,
Chris@18 120 'left_field' => 'nid',
Chris@18 121 'field' => 'entity_id',
Chris@18 122 'extra' => [
Chris@18 123 ['field' => 'deleted', 'value' => 0, 'numeric' => TRUE],
Chris@18 124 ['left_field' => 'langcode', 'field' => 'langcode'],
Chris@18 125 ],
Chris@18 126 ];
Chris@18 127 $this->assertSame($expected_join, $data[$current_table]['table']['join']['node_field_data']);
Chris@18 128 $expected_join = [
Chris@18 129 'table' => $revision_table,
Chris@18 130 'left_field' => 'vid',
Chris@18 131 'field' => 'revision_id',
Chris@18 132 'extra' => [
Chris@18 133 ['field' => 'deleted', 'value' => 0, 'numeric' => TRUE],
Chris@18 134 ['left_field' => 'langcode', 'field' => 'langcode'],
Chris@18 135 ],
Chris@18 136 ];
Chris@18 137 $this->assertSame($expected_join, $data[$revision_table]['table']['join']['node_field_revision']);
Chris@18 138
Chris@18 139 // Test click sortable for string field.
Chris@18 140 $this->assertTrue($data[$current_table][$field_storage_string->getName()]['field']['click sortable']);
Chris@18 141 // Click sort should only be on the primary field.
Chris@18 142 $this->assertTrue(empty($data[$revision_table][$field_storage_string->getName()]['field']['click sortable']));
Chris@18 143 // Test click sortable for long text field.
Chris@18 144 $data_long = $this->getViewsData('field_string_long');
Chris@18 145 $current_table_long = $table_mapping->getDedicatedDataTableName($field_storage_string_long);
Chris@18 146 $this->assertTrue($data_long[$current_table_long][$field_storage_string_long->getName()]['field']['click sortable']);
Chris@18 147
Chris@18 148 $this->assertInstanceOf(MarkupInterface::class, $data[$current_table][$field_storage_string->getName()]['help']);
Chris@18 149 $this->assertEquals('Appears in: page, article. Also known as: Content: GiraffeB&quot; label', $data[$current_table][$field_storage_string->getName()]['help']);
Chris@18 150
Chris@18 151 $this->assertInstanceOf(MarkupInterface::class, $data[$current_table][$field_storage_string->getName() . '_value']['help']);
Chris@18 152 $this->assertEquals('Appears in: page, article. Also known as: Content: GiraffeA&quot; label (field_string)', $data[$current_table][$field_storage_string->getName() . '_value']['help']);
Chris@18 153
Chris@18 154 // Since each label is only used once, views_entity_field_label() will
Chris@18 155 // return a label using alphabetical sorting.
Chris@18 156 $this->assertEquals('GiraffeA&quot; label (field_string)', $data[$current_table][$field_storage_string->getName() . '_value']['title']);
Chris@18 157
Chris@18 158 // Attach the same field to a different bundle with a different label.
Chris@18 159 NodeType::create(['type' => 'news'])->save();
Chris@18 160 FieldConfig::create([
Chris@18 161 'field_name' => $field_storage_string->getName(),
Chris@18 162 'entity_type' => 'node',
Chris@18 163 'bundle' => 'news',
Chris@18 164 'label' => 'GiraffeB" label',
Chris@18 165 ])->save();
Chris@18 166 $this->container->get('views.views_data')->clear();
Chris@18 167 $data = $this->getViewsData();
Chris@18 168
Chris@18 169 // Now the 'GiraffeB&quot; label' is used twice and therefore will be
Chris@18 170 // selected by views_entity_field_label().
Chris@18 171 $this->assertEquals('GiraffeB&quot; label (field_string)', $data[$current_table][$field_storage_string->getName() . '_value']['title']);
Chris@18 172 $this->assertInstanceOf(MarkupInterface::class, $data[$current_table][$field_storage_string->getName()]['help']);
Chris@18 173 $this->assertEquals('Appears in: page, article, news. Also known as: Content: GiraffeA&quot; label', $data[$current_table][$field_storage_string->getName()]['help']);
Chris@18 174 }
Chris@18 175
Chris@18 176 /**
Chris@18 177 * Gets the views data for the field created in setUp().
Chris@18 178 *
Chris@18 179 * @param string $field_storage_key
Chris@18 180 * (optional) The optional field name.
Chris@18 181 *
Chris@18 182 * @return array
Chris@18 183 * Views data.
Chris@18 184 */
Chris@18 185 protected function getViewsData($field_storage_key = 'field_string') {
Chris@18 186 $views_data = $this->container->get('views.views_data');
Chris@18 187 $data = [];
Chris@18 188
Chris@18 189 // Check the table and the joins of the first field. Attached to node only.
Chris@18 190 /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
Chris@18 191 $table_mapping = $this->container->get('entity_type.manager')->getStorage('node')->getTableMapping();
Chris@18 192 $field_storage = FieldStorageConfig::loadByName('node', $field_storage_key);
Chris@18 193 $current_table = $table_mapping->getDedicatedDataTableName($field_storage);
Chris@18 194 $revision_table = $table_mapping->getDedicatedRevisionTableName($field_storage);
Chris@18 195 $data[$current_table] = $views_data->get($current_table);
Chris@18 196 $data[$revision_table] = $views_data->get($revision_table);
Chris@18 197 return $data;
Chris@18 198 }
Chris@18 199
Chris@18 200 /**
Chris@18 201 * Tests filtering entries with different translatability.
Chris@18 202 */
Chris@18 203 public function testEntityFieldFilter() {
Chris@18 204 NodeType::create(['type' => 'bundle1'])->save();
Chris@18 205 NodeType::create(['type' => 'bundle2'])->save();
Chris@18 206
Chris@18 207 // Create some example content.
Chris@18 208 ConfigurableLanguage::create(['id' => 'es'])->save();
Chris@18 209 ConfigurableLanguage::create(['id' => 'fr'])->save();
Chris@18 210
Chris@18 211 ContentLanguageSettings::loadByEntityTypeBundle('node', 'bundle1')
Chris@18 212 ->setDefaultLangcode('es')
Chris@18 213 ->setLanguageAlterable(TRUE)
Chris@18 214 ->save();
Chris@18 215 ContentLanguageSettings::loadByEntityTypeBundle('node', 'bundle2')
Chris@18 216 ->setDefaultLangcode('es')
Chris@18 217 ->setLanguageAlterable(TRUE)
Chris@18 218 ->save();
Chris@18 219
Chris@18 220 $field_translation_map = [
Chris@18 221 1 => ['bundle1' => TRUE, 'bundle2' => TRUE],
Chris@18 222 2 => ['bundle1' => FALSE, 'bundle2' => FALSE],
Chris@18 223 3 => ['bundle1' => TRUE, 'bundle2' => FALSE],
Chris@18 224 ];
Chris@18 225
Chris@18 226 for ($i = 1; $i < 4; $i++) {
Chris@18 227 $field_name = "field_name_$i";
Chris@18 228 FieldStorageConfig::create([
Chris@18 229 'field_name' => $field_name,
Chris@18 230 'entity_type' => 'node',
Chris@18 231 'type' => 'string',
Chris@18 232 ])->save();
Chris@18 233
Chris@18 234 foreach (['bundle1', 'bundle2'] as $bundle) {
Chris@18 235 FieldConfig::create([
Chris@18 236 'field_name' => $field_name,
Chris@18 237 'entity_type' => 'node',
Chris@18 238 'bundle' => $bundle,
Chris@18 239 'translatable' => $field_translation_map[$i][$bundle],
Chris@18 240 ])->save();
Chris@18 241 }
Chris@18 242 }
Chris@18 243
Chris@18 244 $node1 = Node::create([
Chris@18 245 'title' => 'Test title bundle1',
Chris@18 246 'type' => 'bundle1',
Chris@18 247 'langcode' => 'es',
Chris@18 248 'field_name_1' => 'field name 1: es',
Chris@18 249 'field_name_2' => 'field name 2: es',
Chris@18 250 'field_name_3' => 'field name 3: es',
Chris@18 251 ]);
Chris@18 252 $node1->save();
Chris@18 253 /** @var \Drupal\node\NodeInterface $translation */
Chris@18 254 $node1->addTranslation('fr', [
Chris@18 255 'title' => $node1->title->value,
Chris@18 256 'field_name_1' => 'field name 1: fr',
Chris@18 257 'field_name_3' => 'field name 3: fr',
Chris@18 258 ])->save();
Chris@18 259
Chris@18 260 $node2 = Node::create([
Chris@18 261 'title' => 'Test title bundle2',
Chris@18 262 'type' => 'bundle2',
Chris@18 263 'langcode' => 'es',
Chris@18 264 'field_name_1' => 'field name 1: es',
Chris@18 265 'field_name_2' => 'field name 2: es',
Chris@18 266 'field_name_3' => 'field name 3: es',
Chris@18 267 ]);
Chris@18 268 $node2->save();
Chris@18 269
Chris@18 270 $node2->addTranslation('fr', [
Chris@18 271 'title' => $node2->title->value,
Chris@18 272 'field_name_1' => 'field name 1: fr',
Chris@18 273 ])->save();
Chris@18 274
Chris@18 275 $map = [
Chris@18 276 'nid' => 'nid',
Chris@18 277 'langcode' => 'langcode',
Chris@18 278 ];
Chris@18 279
Chris@18 280 $view = Views::getView('test_field_config_translation_filter');
Chris@18 281
Chris@18 282 // Filter by 'field name 1: es'.
Chris@18 283 $view->setDisplay('embed_1');
Chris@18 284 $this->executeView($view);
Chris@18 285 $expected = [
Chris@18 286 [
Chris@18 287 'nid' => $node1->id(),
Chris@18 288 'langcode' => 'es',
Chris@18 289 ],
Chris@18 290 [
Chris@18 291 'nid' => $node2->id(),
Chris@18 292 'langcode' => 'es',
Chris@18 293 ],
Chris@18 294 ];
Chris@18 295
Chris@18 296 $this->assertIdenticalResultset($view, $expected, $map);
Chris@18 297 $view->destroy();
Chris@18 298
Chris@18 299 // Filter by 'field name 1: fr'.
Chris@18 300 $view->setDisplay('embed_2');
Chris@18 301 $this->executeView($view);
Chris@18 302 $expected = [
Chris@18 303 [
Chris@18 304 'nid' => $node1->id(),
Chris@18 305 'langcode' => 'fr',
Chris@18 306 ],
Chris@18 307 [
Chris@18 308 'nid' => $node2->id(),
Chris@18 309 'langcode' => 'fr',
Chris@18 310 ],
Chris@18 311 ];
Chris@18 312
Chris@18 313 $this->assertIdenticalResultset($view, $expected, $map);
Chris@18 314 $view->destroy();
Chris@18 315
Chris@18 316 // Filter by 'field name 2: es'.
Chris@18 317 $view->setDisplay('embed_3');
Chris@18 318 $this->executeView($view);
Chris@18 319 $expected = [
Chris@18 320 [
Chris@18 321 'nid' => $node1->id(),
Chris@18 322 'langcode' => 'es',
Chris@18 323 ],
Chris@18 324 [
Chris@18 325 'nid' => $node1->id(),
Chris@18 326 'langcode' => 'fr',
Chris@18 327 ],
Chris@18 328 [
Chris@18 329 'nid' => $node2->id(),
Chris@18 330 'langcode' => 'es',
Chris@18 331 ],
Chris@18 332 [
Chris@18 333 'nid' => $node2->id(),
Chris@18 334 'langcode' => 'fr',
Chris@18 335 ],
Chris@18 336 ];
Chris@18 337
Chris@18 338 $this->assertIdenticalResultset($view, $expected, $map);
Chris@18 339 $view->destroy();
Chris@18 340
Chris@18 341 // Filter by 'field name 2: fr', which doesn't exist.
Chris@18 342 $view->setDisplay('embed_4');
Chris@18 343 $this->executeView($view);
Chris@18 344 $expected = [];
Chris@18 345
Chris@18 346 $this->assertIdenticalResultset($view, $expected, $map);
Chris@18 347 $view->destroy();
Chris@18 348
Chris@18 349 // Filter by 'field name 3: es'.
Chris@18 350 $view->setDisplay('embed_5');
Chris@18 351 $this->executeView($view);
Chris@18 352 $expected = [
Chris@18 353 [
Chris@18 354 'nid' => $node1->id(),
Chris@18 355 'langcode' => 'es',
Chris@18 356 ],
Chris@18 357 [
Chris@18 358 'nid' => $node2->id(),
Chris@18 359 'langcode' => 'es',
Chris@18 360 ],
Chris@18 361 // Why is this one returned?
Chris@18 362 [
Chris@18 363 'nid' => $node2->id(),
Chris@18 364 'langcode' => 'fr',
Chris@18 365 ],
Chris@18 366 ];
Chris@18 367
Chris@18 368 $this->assertIdenticalResultset($view, $expected, $map);
Chris@18 369 $view->destroy();
Chris@18 370
Chris@18 371 // Filter by 'field name 3: fr'.
Chris@18 372 $view->setDisplay('embed_6');
Chris@18 373 $this->executeView($view);
Chris@18 374 $expected = [
Chris@18 375 [
Chris@18 376 'nid' => $node1->id(),
Chris@18 377 'langcode' => 'fr',
Chris@18 378 ],
Chris@18 379 ];
Chris@18 380
Chris@18 381 $this->assertIdenticalResultset($view, $expected, $map);
Chris@18 382 $view->destroy();
Chris@18 383 }
Chris@18 384
Chris@18 385 }