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