annotate core/modules/views/tests/src/Kernel/FieldApiDataTest.php @ 5:12f9dff5fda9 tip

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