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 }
|