/**
  * Asserts a view's result & render cache items' cache tags.
  *
  * This methods uses a full view object in order to render the view.
  *
  * @param \Drupal\views\ViewExecutable $view
  *   The view to test, must have caching enabled.
  * @param null|string[] $expected_results_cache
  *   NULL when expecting no results cache item, a set of cache tags expected
  *   to be set on the results cache item otherwise.
  * @param bool $views_caching_is_enabled
  *   Whether to expect an output cache item. If TRUE, the cache tags must
  *   match those in $expected_render_array_cache_tags.
  * @param string[] $expected_render_array_cache_tags
  *   A set of cache tags expected to be set on the built view's render array.
  *
  * @return array
  *   The render array.
  */
 protected function assertViewsCacheTags(ViewExecutable $view, $expected_results_cache, $views_caching_is_enabled, array $expected_render_array_cache_tags)
 {
     /** @var \Drupal\Core\Render\RendererInterface $renderer */
     $renderer = \Drupal::service('renderer');
     /** @var \Drupal\Core\Render\RenderCacheInterface $render_cache */
     $render_cache = \Drupal::service('render_cache');
     $build = $view->buildRenderable();
     $original = $build;
     // Ensure the current request is a GET request so that render caching is
     // active for direct rendering of views, just like for actual requests.
     /** @var \Symfony\Component\HttpFoundation\RequestStack $request_stack */
     $request_stack = \Drupal::service('request_stack');
     $request = new Request();
     $request->server->set('REQUEST_TIME', REQUEST_TIME);
     $view->setRequest($request);
     $request_stack->push($request);
     $renderer->renderRoot($build);
     // Render array cache tags.
     $this->pass('Checking render array cache tags.');
     sort($expected_render_array_cache_tags);
     $this->assertEqual($build['#cache']['tags'], $expected_render_array_cache_tags);
     $this->debugCacheTags($build['#cache']['tags'], $expected_render_array_cache_tags);
     if ($views_caching_is_enabled) {
         $this->pass('Checking Views results cache item cache tags.');
         /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache_plugin */
         $cache_plugin = $view->display_handler->getPlugin('cache');
         // Results cache.
         // Ensure that the views query is built.
         $view->build();
         $results_cache_item = \Drupal::cache('data')->get($cache_plugin->generateResultsKey());
         if (is_array($expected_results_cache)) {
             $this->assertTrue($results_cache_item, 'Results cache item found.');
             if ($results_cache_item) {
                 sort($expected_results_cache);
                 $this->assertEqual($results_cache_item->tags, $expected_results_cache);
                 $this->debugCacheTags($results_cache_item->tags, $expected_results_cache);
             }
         } else {
             $this->assertFalse($results_cache_item, 'Results cache item not found.');
         }
         $this->pass('Checking Views render cache item cache tags.');
         $original['#cache'] += ['contexts' => []];
         $original['#cache']['contexts'] = Cache::mergeContexts($original['#cache']['contexts'], $this->container->getParameter('renderer.config')['required_cache_contexts']);
         $render_cache_item = $render_cache->get($original);
         if ($views_caching_is_enabled === TRUE) {
             $this->assertTrue(!empty($render_cache_item), 'Render cache item found.');
             if ($render_cache_item) {
                 $this->assertEqual($render_cache_item['#cache']['tags'], $expected_render_array_cache_tags);
                 $this->debugCacheTags($render_cache_item['#cache']['tags'], $expected_render_array_cache_tags);
             }
         } else {
             $this->assertFalse($render_cache_item, 'Render cache item not found.');
         }
     }
     $view->destroy();
     $request_stack->pop();
     return $build;
 }
 /**
  * Changes the tid filter to given term and depth.
  *
  * @param integer $tid
  *   The term ID to filter on.
  * @param integer $depth
  *   The depth to search.
  * @param array $expected
  *   The expected views result.
  */
 protected function assertTermWithDepthResult($tid, $depth, array $expected)
 {
     $this->view->destroy();
     $this->view->initDisplay();
     $filters = $this->view->displayHandlers->get('default')->getOption('filters');
     $filters['tid_depth']['depth'] = $depth;
     $filters['tid_depth']['value'] = [$tid];
     $this->view->displayHandlers->get('default')->setOption('filters', $filters);
     $this->executeView($this->view);
     $this->assertIdenticalResultsetHelper($this->view, $expected, ['nid' => 'nid'], 'assertIdentical');
 }
 /**
  * Asserts a view's result & output cache items' cache tags.
  *
  * @param \Drupal\views\ViewExecutable $view
  *   The view to test, must have caching enabled.
  * @param null|string[] $expected_results_cache
  *   NULL when expecting no results cache item, a set of cache tags expected
  *   to be set on the results cache item otherwise.
  * @param bool $views_caching_is_enabled
  *   Whether to expect an output cache item. If TRUE, the cache tags must
  *   match those in $expected_render_array_cache_tags.
  * @param string[] $expected_render_array_cache_tags
  *   A set of cache tags expected to be set on the built view's render array.
  *
  * @return array
  *   The render array
  */
 protected function assertViewsCacheTags(ViewExecutable $view, $expected_results_cache, $views_caching_is_enabled, array $expected_render_array_cache_tags)
 {
     $build = $view->preview();
     // Ensure the current request is a GET request so that render caching is
     // active for direct rendering of views, just like for actual requests.
     /** @var \Symfony\Component\HttpFoundation\RequestStack $request_stack */
     $request_stack = \Drupal::service('request_stack');
     $request_stack->push(new Request());
     \Drupal::service('renderer')->renderRoot($build);
     $request_stack->pop();
     // Render array cache tags.
     $this->pass('Checking render array cache tags.');
     sort($expected_render_array_cache_tags);
     $this->assertEqual($build['#cache']['tags'], $expected_render_array_cache_tags);
     if ($views_caching_is_enabled) {
         $this->pass('Checking Views results cache item cache tags.');
         /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache_plugin */
         $cache_plugin = $view->display_handler->getPlugin('cache');
         // Results cache.
         $results_cache_item = \Drupal::cache('data')->get($cache_plugin->generateResultsKey());
         if (is_array($expected_results_cache)) {
             $this->assertTrue($results_cache_item, 'Results cache item found.');
             if ($results_cache_item) {
                 sort($expected_results_cache);
                 $this->assertEqual($results_cache_item->tags, $expected_results_cache);
             }
         } else {
             $this->assertFalse($results_cache_item, 'Results cache item not found.');
         }
         // Output cache.
         $this->pass('Checking Views output cache item cache tags.');
         $output_cache_item = \Drupal::cache('render')->get($cache_plugin->generateOutputKey());
         if ($views_caching_is_enabled === TRUE) {
             $this->assertTrue($output_cache_item, 'Output cache item found.');
             if ($output_cache_item) {
                 $this->assertEqual($output_cache_item->tags, Cache::mergeTags($expected_render_array_cache_tags, ['rendered']));
             }
         } else {
             $this->assertFalse($output_cache_item, 'Output cache item not found.');
         }
     }
     $view->destroy();
     return $build;
 }
Example #4
0
 public function renderPreview($display_id, $args = array())
 {
     // Save the current path so it can be restored before returning from this function.
     $old_q = current_path();
     // Determine where the query and performance statistics should be output.
     $config = \Drupal::config('views.settings');
     $show_query = $config->get('ui.show.sql_query.enabled');
     $show_info = $config->get('ui.show.preview_information');
     $show_location = $config->get('ui.show.sql_query.where');
     $show_stats = $config->get('ui.show.performance_statistics');
     if ($show_stats) {
         $show_stats = $config->get('ui.show.sql_query.where');
     }
     $combined = $show_query && $show_stats;
     $rows = array('query' => array(), 'statistics' => array());
     $output = '';
     $errors = $this->executable->validate();
     $this->executable->destroy();
     if (empty($errors)) {
         $this->ajax = TRUE;
         $this->executable->live_preview = TRUE;
         // AJAX happens via HTTP POST but everything expects exposed data to
         // be in GET. Copy stuff but remove ajax-framework specific keys.
         // If we're clicking on links in a preview, though, we could actually
         // have some input in the query parameters, so we merge request() and
         // query() to ensure we get it all.
         $exposed_input = array_merge(\Drupal::request()->request->all(), \Drupal::request()->query->all());
         foreach (array('view_name', 'view_display_id', 'view_args', 'view_path', 'view_dom_id', 'pager_element', 'view_base_path', 'ajax_html_ids', 'ajax_page_state', 'form_id', 'form_build_id', 'form_token') as $key) {
             if (isset($exposed_input[$key])) {
                 unset($exposed_input[$key]);
             }
         }
         $this->executable->setExposedInput($exposed_input);
         if (!$this->executable->setDisplay($display_id)) {
             return t('Invalid display id @display', array('@display' => $display_id));
         }
         $this->executable->setArguments($args);
         // Store the current view URL for later use:
         if ($this->executable->display_handler->getOption('path')) {
             $path = $this->executable->getUrl();
         }
         // Make view links come back to preview.
         $this->override_path = 'admin/structure/views/view/' . $this->id() . '/preview/' . $display_id;
         // Also override the current path so we get the pager.
         $original_path = current_path();
         $q = _current_path($this->override_path);
         if ($args) {
             $q .= '/' . implode('/', $args);
             _current_path($q);
         }
         // Suppress contextual links of entities within the result set during a
         // Preview.
         // @todo We'll want to add contextual links specific to editing the View, so
         //   the suppression may need to be moved deeper into the Preview pipeline.
         views_ui_contextual_links_suppress_push();
         $show_additional_queries = $config->get('ui.show.additional_queries');
         Timer::start('entity.view.preview_form');
         if ($show_additional_queries) {
             $this->startQueryCapture();
         }
         // Execute/get the view preview.
         $preview = $this->executable->preview($display_id, $args);
         $preview = drupal_render($preview);
         if ($show_additional_queries) {
             $this->endQueryCapture();
         }
         $this->render_time = Timer::stop('entity.view.preview_form');
         views_ui_contextual_links_suppress_pop();
         // Reset variables.
         unset($this->override_path);
         _current_path($original_path);
         // Prepare the query information and statistics to show either above or
         // below the view preview.
         if ($show_info || $show_query || $show_stats) {
             // Get information from the preview for display.
             if (!empty($this->executable->build_info['query'])) {
                 if ($show_query) {
                     $query_string = $this->executable->build_info['query'];
                     // Only the sql default class has a method getArguments.
                     $quoted = array();
                     if ($this->executable->query instanceof Sql) {
                         $quoted = $query_string->getArguments();
                         $connection = Database::getConnection();
                         foreach ($quoted as $key => $val) {
                             if (is_array($val)) {
                                 $quoted[$key] = implode(', ', array_map(array($connection, 'quote'), $val));
                             } else {
                                 $quoted[$key] = $connection->quote($val);
                             }
                         }
                     }
                     $rows['query'][] = array(array('data' => array('#type' => 'inline_template', '#template' => "<strong>{% trans 'Query' %}</strong>")), array('data' => array('#type' => 'inline_template', '#template' => '<pre>{{ query }}</pre>', '#context' => array('query' => strtr($query_string, $quoted)))));
                     if (!empty($this->additionalQueries)) {
                         $queries = '<strong>' . t('These queries were run during view rendering:') . '</strong>';
                         foreach ($this->additionalQueries as $query) {
                             if ($queries) {
                                 $queries .= "\n";
                             }
                             $query_string = strtr($query['query'], $query['args']);
                             $queries .= t('[@time ms] @query', array('@time' => round($query['time'] * 100000, 1) / 100000.0, '@query' => $query_string));
                         }
                         $rows['query'][] = array(array('data' => array('#type' => 'inline_template', '#template' => "<strong>{% trans 'Other queries' %}</strong>")), SafeMarkup::set('<pre>' . $queries . '</pre>'));
                     }
                 }
                 if ($show_info) {
                     $rows['query'][] = array(array('data' => array('#type' => 'inline_template', '#template' => "<strong>{% trans 'Title' %}</strong>")), Xss::filterAdmin($this->executable->getTitle()));
                     if (isset($path)) {
                         $path = _l($path, $path);
                     } else {
                         $path = t('This display has no path.');
                     }
                     $rows['query'][] = array(SafeMarkup::set('<strong>' . t('Path') . '</strong>'), $path);
                 }
                 if ($show_stats) {
                     $rows['statistics'][] = array('<strong>' . t('Query build time') . '</strong>', t('@time ms', array('@time' => intval($this->executable->build_time * 100000) / 100)));
                     $rows['statistics'][] = array('<strong>' . t('Query execute time') . '</strong>', t('@time ms', array('@time' => intval($this->executable->execute_time * 100000) / 100)));
                     $rows['statistics'][] = array('<strong>' . t('View render time') . '</strong>', t('@time ms', array('@time' => intval($this->executable->render_time * 100000) / 100)));
                 }
                 \Drupal::moduleHandler()->alter('views_preview_info', $rows, $this->executable);
             } else {
                 // No query was run. Display that information in place of either the
                 // query or the performance statistics, whichever comes first.
                 if ($combined || $show_location === 'above') {
                     $rows['query'] = array(array(SafeMarkup::set('<strong>' . t('Query') . '</strong>'), t('No query was run')));
                 } else {
                     $rows['statistics'] = array(array(SafeMarkup::set('<strong>' . t('Query') . '</strong>'), t('No query was run')));
                 }
             }
         }
     } else {
         foreach ($errors as $display_errors) {
             foreach ($display_errors as $error) {
                 drupal_set_message($error, 'error');
             }
         }
         $preview = t('Unable to preview due to validation errors.');
     }
     // Assemble the preview, the query info, and the query statistics in the
     // requested order.
     $table = array('#type' => 'table', '#prefix' => '<div class="views-query-info">', '#suffix' => '</div>');
     if ($show_location === 'above' || $show_location === 'below') {
         if ($combined) {
             $table['#rows'] = array_merge($rows['query'], $rows['statistics']);
         } else {
             $table['#rows'] = $rows['query'];
         }
     } elseif ($show_stats === 'above' || $show_stats === 'below') {
         $table['#rows'] = $rows['statistics'];
     }
     if ($show_location === 'above' || $show_stats === 'above') {
         $output .= drupal_render($table) . $preview;
     } elseif ($show_location === 'below' || $show_stats === 'below') {
         $output .= $preview . drupal_render($table);
     }
     _current_path($old_q);
     return $output;
 }
Example #5
0
 /**
  * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::attachTo().
  */
 public function attachTo(ViewExecutable $clone, $display_id)
 {
     $displays = $this->getOption('displays');
     if (empty($displays[$display_id])) {
         return;
     }
     // Defer to the feed style; it may put in meta information, and/or
     // attach a feed icon.
     $clone->setDisplay($this->display['id']);
     $clone->buildTitle();
     if ($plugin = $clone->display_handler->getPlugin('style')) {
         $plugin->attachTo($display_id, $this->getPath(), $clone->getTitle());
     }
     // Clean up.
     $clone->destroy();
     unset($clone);
 }
Example #6
0
 /**
  * {@inheritdoc}
  */
 public function attachTo(ViewExecutable $clone, $display_id, array &$build)
 {
     $displays = $this->getOption('displays');
     if (empty($displays[$display_id])) {
         return;
     }
     // Defer to the feed style; it may put in meta information, and/or
     // attach a feed icon.
     $clone->setArguments($this->view->args);
     $clone->setDisplay($this->display['id']);
     $clone->buildTitle();
     if ($plugin = $clone->display_handler->getPlugin('style')) {
         $plugin->attachTo($build, $display_id, $clone->getUrl(), $clone->getTitle());
         foreach ($clone->feedIcons as $feed_icon) {
             $this->view->feedIcons[] = $feed_icon;
         }
     }
     // Clean up.
     $clone->destroy();
     unset($clone);
 }