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

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\Tests\views\Kernel;
Chris@0 4
Chris@0 5 use Drupal\entity_test\Entity\EntityTestMul;
Chris@0 6 use Drupal\field\Entity\FieldConfig;
Chris@0 7 use Drupal\field\Entity\FieldStorageConfig;
Chris@0 8 use Drupal\language\Entity\ConfigurableLanguage;
Chris@0 9 use Drupal\views\Views;
Chris@0 10
Chris@0 11 /**
Chris@0 12 * Tests aggregate functionality of views, for example count.
Chris@0 13 *
Chris@0 14 * @group views
Chris@0 15 */
Chris@0 16 class QueryGroupByTest extends ViewsKernelTestBase {
Chris@0 17
Chris@0 18 /**
Chris@0 19 * Views used by this test.
Chris@0 20 *
Chris@0 21 * @var array
Chris@0 22 */
Chris@0 23 public static $testViews = ['test_group_by_in_filters', 'test_aggregate_count', 'test_group_by_count', 'test_group_by_count_multicardinality', 'test_group_by_field_not_within_bundle'];
Chris@0 24
Chris@0 25 /**
Chris@0 26 * Modules to enable.
Chris@0 27 *
Chris@0 28 * @var array
Chris@0 29 */
Chris@0 30 public static $modules = ['entity_test', 'system', 'field', 'user', 'language'];
Chris@0 31
Chris@0 32 /**
Chris@0 33 * The storage for the test entity type.
Chris@0 34 *
Chris@0 35 * @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage
Chris@0 36 */
Chris@0 37 public $storage;
Chris@0 38
Chris@0 39 /**
Chris@0 40 * {@inheritdoc}
Chris@0 41 */
Chris@0 42 protected function setUp($import_test_views = TRUE) {
Chris@0 43 parent::setUp();
Chris@0 44
Chris@0 45 $this->installEntitySchema('user');
Chris@0 46 $this->installEntitySchema('entity_test');
Chris@0 47 $this->installEntitySchema('entity_test_mul');
Chris@0 48
Chris@0 49 $this->storage = $this->container->get('entity.manager')->getStorage('entity_test');
Chris@0 50
Chris@0 51 ConfigurableLanguage::createFromLangcode('it')->save();
Chris@0 52 }
Chris@0 53
Chris@0 54 /**
Chris@0 55 * Tests aggregate count feature.
Chris@0 56 */
Chris@0 57 public function testAggregateCount() {
Chris@0 58 $this->setupTestEntities();
Chris@0 59
Chris@0 60 $view = Views::getView('test_aggregate_count');
Chris@0 61 $this->executeView($view);
Chris@0 62
Chris@0 63 $this->assertEqual(count($view->result), 2, 'Make sure the count of items is right.');
Chris@0 64
Chris@0 65 $types = [];
Chris@0 66 foreach ($view->result as $item) {
Chris@0 67 // num_records is a alias for id.
Chris@0 68 $types[$item->entity_test_name] = $item->num_records;
Chris@0 69 }
Chris@0 70
Chris@0 71 $this->assertEqual($types['name1'], 4, 'Groupby the name: name1 returned the expected amount of results.');
Chris@0 72 $this->assertEqual($types['name2'], 3, 'Groupby the name: name2 returned the expected amount of results.');
Chris@0 73 }
Chris@0 74
Chris@0 75 /**
Chris@0 76 * Provides a test helper which runs a view with some aggregation function.
Chris@0 77 *
Chris@0 78 * @param string|null $aggregation_function
Chris@0 79 * Which aggregation function should be used, for example sum or count. If
Chris@0 80 * NULL is passed the aggregation will be tested with no function.
Chris@0 81 * @param array $values
Chris@0 82 * The expected views result.
Chris@0 83 */
Chris@0 84 public function groupByTestHelper($aggregation_function, $values) {
Chris@0 85 $this->setupTestEntities();
Chris@0 86
Chris@0 87 $view = Views::getView('test_group_by_count');
Chris@0 88 $view->setDisplay();
Chris@0 89 // There is no need for a function in order to have aggregation.
Chris@0 90 if (empty($aggregation_function)) {
Chris@0 91 // The test table has 2 fields ('id' and 'name'). We'll remove 'id'
Chris@0 92 // because it's unique and will test aggregation on 'name'.
Chris@0 93 unset($view->displayHandlers->get('default')->options['fields']['id']);
Chris@0 94 }
Chris@0 95 else {
Chris@0 96 $view->displayHandlers->get('default')->options['fields']['id']['group_type'] = $aggregation_function;
Chris@0 97 }
Chris@0 98
Chris@0 99 $this->executeView($view);
Chris@0 100
Chris@0 101 $this->assertEqual(count($view->result), 2, 'Make sure the count of items is right.');
Chris@0 102 // Group by name to identify the right count.
Chris@0 103 $results = [];
Chris@0 104 foreach ($view->result as $item) {
Chris@0 105 $results[$item->entity_test_name] = $item->id;
Chris@0 106 }
Chris@0 107 $this->assertEqual($results['name1'], $values[0], format_string('Aggregation with @aggregation_function and groupby name: name1 returned the expected amount of results', ['@aggregation_function' => $aggregation_function]));
Chris@0 108 $this->assertEqual($results['name2'], $values[1], format_string('Aggregation with @aggregation_function and groupby name: name2 returned the expected amount of results', ['@aggregation_function' => $aggregation_function]));
Chris@0 109 }
Chris@0 110
Chris@0 111 /**
Chris@0 112 * Helper method that creates some test entities.
Chris@0 113 */
Chris@0 114 protected function setupTestEntities() {
Chris@0 115 // Create 4 entities with name1 and 3 entities with name2.
Chris@0 116 $entity_1 = [
Chris@0 117 'name' => 'name1',
Chris@0 118 ];
Chris@0 119
Chris@0 120 $this->storage->create($entity_1)->save();
Chris@0 121 $this->storage->create($entity_1)->save();
Chris@0 122 $this->storage->create($entity_1)->save();
Chris@0 123 $this->storage->create($entity_1)->save();
Chris@0 124
Chris@0 125 $entity_2 = [
Chris@0 126 'name' => 'name2',
Chris@0 127 ];
Chris@0 128 $this->storage->create($entity_2)->save();
Chris@0 129 $this->storage->create($entity_2)->save();
Chris@0 130 $this->storage->create($entity_2)->save();
Chris@0 131 }
Chris@0 132
Chris@0 133 /**
Chris@0 134 * Tests the count aggregation function.
Chris@0 135 */
Chris@0 136 public function testGroupByCount() {
Chris@0 137 $this->groupByTestHelper('count', [4, 3]);
Chris@0 138 }
Chris@0 139
Chris@0 140 /**
Chris@0 141 * Tests the sum aggregation function.
Chris@0 142 */
Chris@0 143 public function testGroupBySum() {
Chris@0 144 $this->groupByTestHelper('sum', [10, 18]);
Chris@0 145 }
Chris@0 146
Chris@0 147 /**
Chris@0 148 * Tests the average aggregation function.
Chris@0 149 */
Chris@0 150 public function testGroupByAverage() {
Chris@0 151 $this->groupByTestHelper('avg', [2.5, 6]);
Chris@0 152 }
Chris@0 153
Chris@0 154 /**
Chris@0 155 * Tests the min aggregation function.
Chris@0 156 */
Chris@0 157 public function testGroupByMin() {
Chris@0 158 $this->groupByTestHelper('min', [1, 5]);
Chris@0 159 }
Chris@0 160
Chris@0 161 /**
Chris@0 162 * Tests the max aggregation function.
Chris@0 163 */
Chris@0 164 public function testGroupByMax() {
Chris@0 165 $this->groupByTestHelper('max', [4, 7]);
Chris@0 166 }
Chris@0 167
Chris@0 168 /**
Chris@0 169 * Tests aggregation with no specific function.
Chris@0 170 */
Chris@0 171 public function testGroupByNone() {
Chris@0 172 $this->groupByTestHelper(NULL, [1, 5]);
Chris@0 173 }
Chris@0 174
Chris@0 175 /**
Chris@0 176 * Tests groupby with filters.
Chris@0 177 */
Chris@0 178 public function testGroupByCountOnlyFilters() {
Chris@0 179 // Check if GROUP BY and HAVING are included when a view
Chris@0 180 // doesn't display SUM, COUNT, MAX, etc. functions in SELECT statement.
Chris@0 181
Chris@0 182 for ($x = 0; $x < 10; $x++) {
Chris@0 183 $this->storage->create(['name' => 'name1'])->save();
Chris@0 184 }
Chris@0 185
Chris@0 186 $view = Views::getView('test_group_by_in_filters');
Chris@0 187 $this->executeView($view);
Chris@0 188
Chris@0 189 $this->assertTrue(strpos($view->build_info['query'], 'GROUP BY'), 'Make sure that GROUP BY is in the query');
Chris@0 190 $this->assertTrue(strpos($view->build_info['query'], 'HAVING'), 'Make sure that HAVING is in the query');
Chris@0 191 }
Chris@0 192
Chris@0 193 /**
Chris@0 194 * Tests grouping on base field.
Chris@0 195 */
Chris@0 196 public function testGroupByBaseField() {
Chris@0 197 $this->setupTestEntities();
Chris@0 198
Chris@0 199 $view = Views::getView('test_group_by_count');
Chris@0 200 $view->setDisplay();
Chris@0 201 // This tests that the GROUP BY portion of the query is properly formatted
Chris@0 202 // to include the base table to avoid ambiguous field errors.
Chris@0 203 $view->displayHandlers->get('default')->options['fields']['name']['group_type'] = 'min';
Chris@0 204 unset($view->displayHandlers->get('default')->options['fields']['id']['group_type']);
Chris@0 205 $this->executeView($view);
Chris@0 206 $this->assertTrue(strpos($view->build_info['query'], 'GROUP BY entity_test.id'), 'GROUP BY field includes the base table name when grouping on the base field.');
Chris@0 207 }
Chris@0 208
Chris@0 209 /**
Chris@0 210 * Tests grouping a field with cardinality > 1.
Chris@0 211 */
Chris@0 212 public function testGroupByFieldWithCardinality() {
Chris@0 213 $field_storage = FieldStorageConfig::create([
Chris@0 214 'type' => 'integer',
Chris@0 215 'field_name' => 'field_test',
Chris@0 216 'cardinality' => 4,
Chris@0 217 'entity_type' => 'entity_test_mul',
Chris@0 218 ]);
Chris@0 219 $field_storage->save();
Chris@0 220 $field = FieldConfig::create([
Chris@0 221 'field_name' => 'field_test',
Chris@0 222 'entity_type' => 'entity_test_mul',
Chris@0 223 'bundle' => 'entity_test_mul',
Chris@0 224 ]);
Chris@0 225 $field->save();
Chris@0 226
Chris@0 227 $entities = [];
Chris@0 228 $entity = EntityTestMul::create([
Chris@0 229 'field_test' => [1, 1, 1],
Chris@0 230 ]);
Chris@0 231 $entity->save();
Chris@0 232 $entities[] = $entity;
Chris@0 233
Chris@0 234 $entity = EntityTestMul::create([
Chris@0 235 'field_test' => [2, 2, 2],
Chris@0 236 ]);
Chris@0 237 $entity->save();
Chris@0 238 $entities[] = $entity;
Chris@0 239
Chris@0 240 $entity = EntityTestMul::create([
Chris@0 241 'field_test' => [2, 2, 2],
Chris@0 242 ]);
Chris@0 243 $entity->save();
Chris@0 244 $entities[] = $entity;
Chris@0 245
Chris@0 246 $view = Views::getView('test_group_by_count_multicardinality');
Chris@0 247 $this->executeView($view);
Chris@0 248 $this->assertEqual(2, count($view->result));
Chris@0 249
Chris@0 250 $this->assertEqual('3', $view->getStyle()->getField(0, 'id'));
Chris@0 251 $this->assertEqual('1', $view->getStyle()->getField(0, 'field_test'));
Chris@0 252 $this->assertEqual('6', $view->getStyle()->getField(1, 'id'));
Chris@0 253 $this->assertEqual('2', $view->getStyle()->getField(1, 'field_test'));
Chris@0 254
Chris@0 255 $entities[2]->field_test[0]->value = 3;
Chris@0 256 $entities[2]->field_test[1]->value = 4;
Chris@0 257 $entities[2]->field_test[2]->value = 5;
Chris@0 258 $entities[2]->save();
Chris@0 259
Chris@0 260 $view = Views::getView('test_group_by_count_multicardinality');
Chris@0 261 $this->executeView($view);
Chris@0 262 $this->assertEqual(5, count($view->result));
Chris@0 263
Chris@0 264 $this->assertEqual('3', $view->getStyle()->getField(0, 'id'));
Chris@0 265 $this->assertEqual('1', $view->getStyle()->getField(0, 'field_test'));
Chris@0 266 $this->assertEqual('3', $view->getStyle()->getField(1, 'id'));
Chris@0 267 $this->assertEqual('2', $view->getStyle()->getField(1, 'field_test'));
Chris@0 268 $this->assertEqual('1', $view->getStyle()->getField(2, 'id'));
Chris@0 269 $this->assertEqual('3', $view->getStyle()->getField(2, 'field_test'));
Chris@0 270 $this->assertEqual('1', $view->getStyle()->getField(3, 'id'));
Chris@0 271 $this->assertEqual('4', $view->getStyle()->getField(3, 'field_test'));
Chris@0 272 $this->assertEqual('1', $view->getStyle()->getField(4, 'id'));
Chris@0 273 $this->assertEqual('5', $view->getStyle()->getField(4, 'field_test'));
Chris@0 274
Chris@0 275 // Check that translated values are correctly retrieved and are not grouped
Chris@0 276 // into the original entity.
Chris@0 277 $translation = $entity->addTranslation('it');
Chris@0 278 $translation->field_test = [6, 6, 6];
Chris@0 279 $translation->save();
Chris@0 280
Chris@0 281 $view = Views::getView('test_group_by_count_multicardinality');
Chris@0 282 $this->executeView($view);
Chris@0 283
Chris@0 284 $this->assertEqual(6, count($view->result));
Chris@0 285 $this->assertEqual('3', $view->getStyle()->getField(5, 'id'));
Chris@0 286 $this->assertEqual('6', $view->getStyle()->getField(5, 'field_test'));
Chris@0 287 }
Chris@0 288
Chris@0 289 /**
Chris@0 290 * Tests groupby with a field not existing on some bundle.
Chris@0 291 */
Chris@0 292 public function testGroupByWithFieldsNotExistingOnBundle() {
Chris@0 293 $field_storage = FieldStorageConfig::create([
Chris@0 294 'type' => 'integer',
Chris@0 295 'field_name' => 'field_test',
Chris@0 296 'cardinality' => 4,
Chris@0 297 'entity_type' => 'entity_test_mul',
Chris@0 298 ]);
Chris@0 299 $field_storage->save();
Chris@0 300 $field = FieldConfig::create([
Chris@0 301 'field_name' => 'field_test',
Chris@0 302 'entity_type' => 'entity_test_mul',
Chris@0 303 'bundle' => 'entity_test_mul',
Chris@0 304 ]);
Chris@0 305 $field->save();
Chris@0 306
Chris@0 307 $entities = [];
Chris@0 308 $entity = EntityTestMul::create([
Chris@0 309 'field_test' => [1],
Chris@0 310 'type' => 'entity_test_mul',
Chris@0 311 ]);
Chris@0 312 $entity->save();
Chris@0 313 $entities[] = $entity;
Chris@0 314
Chris@0 315 $entity = EntityTestMul::create([
Chris@0 316 'type' => 'entity_test_mul2',
Chris@0 317 ]);
Chris@0 318 $entity->save();
Chris@0 319 $entities[] = $entity;
Chris@0 320
Chris@0 321 $view = Views::getView('test_group_by_field_not_within_bundle');
Chris@0 322 $this->executeView($view);
Chris@0 323
Chris@0 324 $this->assertEqual(2, count($view->result));
Chris@0 325 // The first result is coming from entity_test_mul2, so no field could be
Chris@0 326 // rendered.
Chris@0 327 $this->assertEqual('', $view->getStyle()->getField(0, 'field_test'));
Chris@0 328 // The second result is coming from entity_test_mul, so its field value
Chris@0 329 // could be rendered.
Chris@0 330 $this->assertEqual('1', $view->getStyle()->getField(1, 'field_test'));
Chris@0 331 }
Chris@0 332
Chris@0 333 }