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