Further Drupal 8.6.4 changes. Some core files were not committed before a commit...
[yaffs-website] / web / core / modules / views / tests / src / Kernel / Plugin / CacheTest.php
1 <?php
2
3 namespace Drupal\Tests\views\Kernel\Plugin;
4
5 use Drupal\Core\Render\RenderContext;
6 use Drupal\node\Entity\Node;
7 use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
8 use Drupal\views\Views;
9 use Drupal\views_test_data\Plugin\views\filter\FilterTest as FilterPlugin;
10
11 /**
12  * Tests pluggable caching for views.
13  *
14  * @group views
15  * @see views_plugin_cache
16  */
17 class CacheTest extends ViewsKernelTestBase {
18
19   /**
20    * Views used by this test.
21    *
22    * @var array
23    */
24   public static $testViews = ['test_view', 'test_cache', 'test_groupwise_term_ui', 'test_display', 'test_filter'];
25
26   /**
27    * Modules to enable.
28    *
29    * @var array
30    */
31   public static $modules = ['taxonomy', 'text', 'user', 'node'];
32
33   /**
34    * {@inheritdoc}
35    */
36   protected function setUp($import_test_views = TRUE) {
37     parent::setUp($import_test_views);
38
39     $this->installEntitySchema('node');
40     $this->installEntitySchema('taxonomy_term');
41     $this->installEntitySchema('user');
42
43     // Setup the current time properly.
44     \Drupal::request()->server->set('REQUEST_TIME', time());
45   }
46
47   /**
48    * {@inheritdoc}
49    */
50   protected function viewsData() {
51     $data = parent::viewsData();
52
53     $data['views_test_data']['test_cache_context'] = [
54       'real field' => 'name',
55       'title' => 'Test cache context',
56       'filter' => [
57         'id' => 'views_test_test_cache_context',
58       ],
59     ];
60
61     return $data;
62   }
63
64   /**
65    * Tests time based caching.
66    *
67    * @see views_plugin_cache_time
68    */
69   public function testTimeResultCaching() {
70     $view = Views::getView('test_cache');
71     $view->setDisplay();
72     $view->display_handler->overrideOption('cache', [
73       'type' => 'time',
74       'options' => [
75         'results_lifespan' => '3600',
76         'output_lifespan' => '3600',
77       ],
78     ]);
79
80     // Test the default (non-paged) display.
81     $this->executeView($view);
82     // Verify the result.
83     $this->assertEqual(5, count($view->result), 'The number of returned rows match.');
84
85     // Add another man to the beatles.
86     $record = [
87       'name' => 'Rod Davis',
88       'age' => 29,
89       'job' => 'Banjo',
90     ];
91     db_insert('views_test_data')->fields($record)->execute();
92
93     // The result should be the same as before, because of the caching. (Note
94     // that views_test_data records don't have associated cache tags, and hence
95     // the results cache items aren't invalidated.)
96     $view->destroy();
97     $this->executeView($view);
98     // Verify the result.
99     $this->assertEqual(5, count($view->result), 'The number of returned rows match.');
100   }
101
102   /**
103    * Tests result caching with filters.
104    *
105    * @see views_plugin_cache_time
106    */
107   public function testTimeResultCachingWithFilter() {
108     // Check that we can find the test filter plugin.
109     $plugin = $this->container->get('plugin.manager.views.filter')->createInstance('test_filter');
110     $this->assertTrue($plugin instanceof FilterPlugin, 'Test filter plugin found.');
111
112     $view = Views::getView('test_filter');
113     $view->initDisplay();
114     $view->display_handler->overrideOption('cache', [
115       'type' => 'time',
116       'options' => [
117         'results_lifespan' => '3600',
118         'output_lifespan' => '3600',
119       ],
120     ]);
121
122     // Change the filtering.
123     $view->displayHandlers->get('default')->overrideOption('filters', [
124       'test_filter' => [
125         'id' => 'test_filter',
126         'table' => 'views_test_data',
127         'field' => 'name',
128         'operator' => '=',
129         'value' => 'John',
130         'group' => 0,
131       ],
132     ]);
133
134     $this->executeView($view);
135
136     // Get the cache item.
137     $cid1 = $view->display_handler->getPlugin('cache')->generateResultsKey();
138
139     // Build the expected result.
140     $dataset = [['name' => 'John']];
141
142     // Verify the result.
143     $this->assertEqual(1, count($view->result), 'The number of returned rows match.');
144     $this->assertIdenticalResultSet($view, $dataset, [
145       'views_test_data_name' => 'name',
146     ]);
147
148     $view->destroy();
149
150     $view->initDisplay();
151
152     // Change the filtering.
153     $view->displayHandlers->get('default')->overrideOption('filters', [
154       'test_filter' => [
155         'id' => 'test_filter',
156         'table' => 'views_test_data',
157         'field' => 'name',
158         'operator' => '=',
159         'value' => 'Ringo',
160         'group' => 0,
161       ],
162     ]);
163
164     $this->executeView($view);
165
166     // Get the cache item.
167     $cid2 = $view->display_handler->getPlugin('cache')->generateResultsKey();
168     $this->assertNotEqual($cid1, $cid2, "Results keys are different.");
169
170     // Build the expected result.
171     $dataset = [['name' => 'Ringo']];
172
173     // Verify the result.
174     $this->assertEqual(1, count($view->result), 'The number of returned rows match.');
175     $this->assertIdenticalResultSet($view, $dataset, [
176       'views_test_data_name' => 'name',
177     ]);
178   }
179
180   /**
181    * Tests result caching with a pager.
182    */
183   public function testTimeResultCachingWithPager() {
184     $view = Views::getView('test_cache');
185     $view->setDisplay();
186     $view->display_handler->overrideOption('cache', [
187       'type' => 'time',
188       'options' => [
189         'results_lifespan' => '3600',
190         'output_lifespan' => '3600',
191       ],
192     ]);
193
194     $mapping = ['views_test_data_name' => 'name'];
195
196     $view->setDisplay('page_1');
197     $view->setCurrentPage(0);
198     $this->executeView($view);
199     $this->assertIdenticalResultset($view, [['name' => 'John'], ['name' => 'George']], $mapping);
200     $view->destroy();
201
202     $view->setDisplay('page_1');
203     $view->setCurrentPage(1);
204     $this->executeView($view);
205     $this->assertIdenticalResultset($view, [['name' => 'Ringo'], ['name' => 'Paul']], $mapping);
206     $view->destroy();
207
208     $view->setDisplay('page_1');
209     $view->setCurrentPage(0);
210     $this->executeView($view);
211     $this->assertIdenticalResultset($view, [['name' => 'John'], ['name' => 'George']], $mapping);
212     $view->destroy();
213
214     $view->setDisplay('page_1');
215     $view->setCurrentPage(2);
216     $this->executeView($view);
217     $this->assertIdenticalResultset($view, [['name' => 'Meredith']], $mapping);
218     $view->destroy();
219   }
220
221   /**
222    * Tests no caching.
223    *
224    * @see views_plugin_cache_time
225    */
226   public function testNoneResultCaching() {
227     // Create a basic result which just 2 results.
228     $view = Views::getView('test_cache');
229     $view->setDisplay();
230     $view->display_handler->overrideOption('cache', [
231       'type' => 'none',
232       'options' => [],
233     ]);
234
235     $this->executeView($view);
236     // Verify the result.
237     $this->assertEqual(5, count($view->result), 'The number of returned rows match.');
238
239     // Add another man to the beatles.
240     $record = [
241       'name' => 'Rod Davis',
242       'age' => 29,
243       'job' => 'Banjo',
244     ];
245     db_insert('views_test_data')->fields($record)->execute();
246
247     // The Result changes, because the view is not cached.
248     $view = Views::getView('test_cache');
249     $view->setDisplay();
250     $view->display_handler->overrideOption('cache', [
251       'type' => 'none',
252       'options' => [],
253     ]);
254
255     $this->executeView($view);
256     // Verify the result.
257     $this->assertEqual(6, count($view->result), 'The number of returned rows match.');
258   }
259
260   /**
261    * Tests css/js storage and restoring mechanism.
262    */
263   public function testHeaderStorage() {
264     // Create a view with output caching enabled.
265     // Some hook_views_pre_render in views_test_data.module adds the test css/js file.
266     // so they should be added to the css/js storage.
267     $view = Views::getView('test_view');
268     $view->setDisplay();
269     $view->storage->set('id', 'test_cache_header_storage');
270     $view->display_handler->overrideOption('cache', [
271       'type' => 'time',
272       'options' => [
273         'output_lifespan' => '3600',
274       ],
275     ]);
276
277     $output = $view->buildRenderable();
278     /** @var \Drupal\Core\Render\RendererInterface $renderer */
279     $renderer = \Drupal::service('renderer');
280     $renderer->executeInRenderContext(new RenderContext(), function () use (&$output, $renderer) {
281       return $renderer->render($output);
282     });
283
284     unset($view->pre_render_called);
285     $view->destroy();
286
287     $view->setDisplay();
288     $output = $view->buildRenderable();
289     $renderer->executeInRenderContext(new RenderContext(), function () use (&$output, $renderer) {
290       return $renderer->render($output);
291     });
292
293     $this->assertTrue(in_array('views_test_data/test', $output['#attached']['library']), 'Make sure libraries are added for cached views.');
294     $this->assertEqual(['foo' => 'bar'], $output['#attached']['drupalSettings'], 'Make sure drupalSettings are added for cached views.');
295     // Note: views_test_data_views_pre_render() adds some cache tags.
296     $this->assertEqual(['config:views.view.test_cache_header_storage', 'views_test_data:1'], $output['#cache']['tags']);
297     $this->assertEqual(['non-existing-placeholder-just-for-testing-purposes' => ['#lazy_builder' => ['views_test_data_placeholders', ['bar']]]], $output['#attached']['placeholders']);
298     $this->assertFalse(!empty($view->build_info['pre_render_called']), 'Make sure hook_views_pre_render is not called for the cached view.');
299   }
300
301   /**
302    * Tests that Subqueries are cached as expected.
303    */
304   public function testSubqueryStringCache() {
305     // Execute the view.
306     $view = Views::getView('test_groupwise_term_ui');
307     $view->setDisplay();
308     $this->executeView($view);
309     // Request for the cache.
310     $cid = 'views_relationship_groupwise_max:test_groupwise_term_ui:default:tid_representative';
311     $cache = \Drupal::cache('data')->get($cid);
312     $this->assertEqual($cid, $cache->cid, 'Subquery String cached as expected.');
313   }
314
315   /**
316    * Tests the data contained in cached items.
317    */
318   public function testCacheData() {
319     for ($i = 1; $i <= 5; $i++) {
320       Node::create([
321         'title' => $this->randomMachineName(8),
322         'type' => 'page',
323       ])->save();
324     }
325
326     $view = Views::getView('test_display');
327     $view->setDisplay();
328     $view->display_handler->overrideOption('cache', [
329       'type' => 'time',
330       'options' => [
331         'results_lifespan' => '3600',
332         'output_lifespan' => '3600',
333       ],
334     ]);
335     $this->executeView($view);
336
337     // Get the cache item.
338     $cid = $view->display_handler->getPlugin('cache')->generateResultsKey();
339     $cache = \Drupal::cache('data')->get($cid);
340
341     // Assert there are results, empty results would mean this test case would
342     // pass otherwise.
343     $this->assertTrue(count($cache->data['result']), 'Results saved in cached data.');
344
345     // Assert each row doesn't contain '_entity' or '_relationship_entities'
346     // items.
347     foreach ($cache->data['result'] as $row) {
348       $this->assertIdentical($row->_entity, NULL, 'Cached row "_entity" property is NULL');
349       $this->assertIdentical($row->_relationship_entities, [], 'Cached row "_relationship_entities" property is empty');
350     }
351   }
352
353   /**
354    * Tests the cache context integration for views result cache.
355    */
356   public function testCacheContextIntegration() {
357     $view = Views::getView('test_cache');
358     $view->setDisplay('page_2');
359     \Drupal::state()->set('views_test_cache_context', 'George');
360     $this->executeView($view);
361
362     $map = ['views_test_data_name' => 'name'];
363     $this->assertIdenticalResultset($view, [['name' => 'George']], $map);
364
365     // Update the entry in the DB to ensure that result caching works.
366     \Drupal::database()->update('views_test_data')
367       ->condition('name', 'George')
368       ->fields(['name' => 'egroeG'])
369       ->execute();
370
371     $view = Views::getView('test_cache');
372     $view->setDisplay('page_2');
373     $this->executeView($view);
374     $this->assertIdenticalResultset($view, [['name' => 'George']], $map);
375
376     // Now change the cache context value, a different query should be executed.
377     $view = Views::getView('test_cache');
378     $view->setDisplay('page_2');
379     \Drupal::state()->set('views_test_cache_context', 'Paul');
380     $this->executeView($view);
381
382     $this->assertIdenticalResultset($view, [['name' => 'Paul']], $map);
383   }
384
385   /**
386    * Tests that cacheability metadata is carried over from argument defaults.
387    */
388   public function testArgumentDefaultCache() {
389     $view = Views::getView('test_view');
390
391     // Add a new argument and set the test plugin for the argument_default.
392     $options = [
393       'default_argument_type' => 'argument_default_test',
394       'default_argument_options' => [
395         'value' => 'John',
396       ],
397       'default_action' => 'default',
398     ];
399     $view->addHandler('default', 'argument', 'views_test_data', 'name', $options);
400     $view->initHandlers();
401
402     $output = $view->preview();
403
404     /** @var \Drupal\Core\Render\RendererInterface $renderer */
405     $renderer = \Drupal::service('renderer');
406
407     $renderer->renderPlain($output);
408     $this->assertEquals(['config:views.view.test_view', 'example_tag'], $output['#cache']['tags']);
409   }
410
411 }