public function ViewUI::renderPreview in Drupal 9
Same name and namespace in other branches
- 8 core/modules/views_ui/src/ViewUI.php \Drupal\views_ui\ViewUI::renderPreview()
File
- core/
modules/ views_ui/ src/ ViewUI.php, line 515
Class
- ViewUI
- Stores UI related temporary settings.
Namespace
Drupal\views_uiCode
public function renderPreview($display_id, $args = []) {
// Save the current path so it can be restored before returning from this function.
$request_stack = \Drupal::requestStack();
$current_request = $request_stack
->getCurrentRequest();
$executable = $this
->getExecutable();
// 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 = [
'query' => [],
'statistics' => [],
];
$errors = $executable
->validate();
$executable
->destroy();
if (empty($errors)) {
$this->ajax = TRUE;
$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 ([
'view_name',
'view_display_id',
'view_args',
'view_path',
'view_dom_id',
'pager_element',
'view_base_path',
AjaxResponseSubscriber::AJAX_REQUEST_PARAMETER,
'ajax_page_state',
'form_id',
'form_build_id',
'form_token',
] as $key) {
if (isset($exposed_input[$key])) {
unset($exposed_input[$key]);
}
}
$executable
->setExposedInput($exposed_input);
if (!$executable
->setDisplay($display_id)) {
return [
'#markup' => t('Invalid display id @display', [
'@display' => $display_id,
]),
];
}
$executable
->setArguments($args);
// Store the current view URL for later use:
if ($executable
->hasUrl() && $executable->display_handler
->getOption('path')) {
$path = $executable
->getUrl();
}
// Make view links come back to preview.
// Also override the current path so we get the pager, and make sure the
// Request object gets all of the proper values from $_SERVER.
$request = Request::createFromGlobals();
$request->attributes
->set(RouteObjectInterface::ROUTE_NAME, 'entity.view.preview_form');
$request->attributes
->set(RouteObjectInterface::ROUTE_OBJECT, \Drupal::service('router.route_provider')
->getRouteByName('entity.view.preview_form'));
$request->attributes
->set('view', $this->storage);
$request->attributes
->set('display_id', $display_id);
$raw_parameters = new ParameterBag();
$raw_parameters
->set('view', $this
->id());
$raw_parameters
->set('display_id', $display_id);
$request->attributes
->set('_raw_variables', $raw_parameters);
foreach ($args as $key => $arg) {
$request->attributes
->set('arg_' . $key, $arg);
}
$request_stack
->push($request);
// 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 = $executable
->preview($display_id, $args);
if ($show_additional_queries) {
$this
->endQueryCapture();
}
$this->render_time = Timer::stop('entity.view.preview_form')['time'];
views_ui_contextual_links_suppress_pop();
// Prepare the query information and statistics to show either above or
// below the view preview.
// Initialize the empty rows arrays so we can safely merge them later.
$rows['query'] = [];
$rows['statistics'] = [];
if ($show_info || $show_query || $show_stats) {
// Get information from the preview for display.
if (!empty($executable->build_info['query'])) {
if ($show_query) {
$query_string = $executable->build_info['query'];
// Only the sql default class has a method getArguments.
$quoted = [];
if ($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([
$connection,
'quote',
], $val));
}
else {
$quoted[$key] = $connection
->quote($val);
}
}
}
$rows['query'][] = [
[
'data' => [
'#type' => 'inline_template',
'#template' => "<strong>{% trans 'Query' %}</strong>",
],
],
[
'data' => [
'#type' => 'inline_template',
'#template' => '<pre>{{ query }}</pre>',
'#context' => [
'query' => strtr($query_string, $quoted),
],
],
],
];
if (!empty($this->additionalQueries)) {
$queries[] = [
'#prefix' => '<strong>',
'#markup' => t('These queries were run during view rendering:'),
'#suffix' => '</strong>',
];
foreach ($this->additionalQueries as $query) {
$query_string = strtr($query['query'], $query['args']);
$queries[] = [
'#prefix' => "\n",
'#markup' => t('[@time ms] @query', [
'@time' => round($query['time'] * 100000, 1) / 100000.0,
'@query' => $query_string,
]),
];
}
$rows['query'][] = [
[
'data' => [
'#type' => 'inline_template',
'#template' => "<strong>{% trans 'Other queries' %}</strong>",
],
],
[
'data' => [
'#prefix' => '<pre>',
'queries' => $queries,
'#suffix' => '</pre>',
],
],
];
}
}
if ($show_info) {
$rows['query'][] = [
[
'data' => [
'#type' => 'inline_template',
'#template' => "<strong>{% trans 'Title' %}</strong>",
],
],
[
'data' => [
'#markup' => $executable
->getTitle(),
],
],
];
if (isset($path)) {
// @todo Views should expect and store a leading /. See:
// https://www.drupal.org/node/2423913
$path = Link::fromTextAndUrl($path
->toString(), $path)
->toString();
}
else {
$path = t('This display has no path.');
}
$rows['query'][] = [
[
'data' => [
'#prefix' => '<strong>',
'#markup' => t('Path'),
'#suffix' => '</strong>',
],
],
[
'data' => [
'#markup' => $path,
],
],
];
}
if ($show_stats) {
$rows['statistics'][] = [
[
'data' => [
'#type' => 'inline_template',
'#template' => "<strong>{% trans 'Query build time' %}</strong>",
],
],
t('@time ms', [
'@time' => intval($executable->build_time * 100000) / 100,
]),
];
$rows['statistics'][] = [
[
'data' => [
'#type' => 'inline_template',
'#template' => "<strong>{% trans 'Query execute time' %}</strong>",
],
],
t('@time ms', [
'@time' => intval($executable->execute_time * 100000) / 100,
]),
];
$rows['statistics'][] = [
[
'data' => [
'#type' => 'inline_template',
'#template' => "<strong>{% trans 'View render time' %}</strong>",
],
],
t('@time ms', [
'@time' => intval($this->render_time * 100) / 100,
]),
];
}
\Drupal::moduleHandler()
->alter('views_preview_info', $rows, $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'][] = [
[
'data' => [
'#prefix' => '<strong>',
'#markup' => t('Query'),
'#suffix' => '</strong>',
],
],
[
'data' => [
'#markup' => t('No query was run'),
],
],
];
}
else {
$rows['statistics'][] = [
[
'data' => [
'#prefix' => '<strong>',
'#markup' => t('Query'),
'#suffix' => '</strong>',
],
],
[
'data' => [
'#markup' => t('No query was run'),
],
],
];
}
}
}
}
else {
foreach ($errors as $display_errors) {
foreach ($display_errors as $error) {
\Drupal::messenger()
->addError($error);
}
}
$preview = [
'#markup' => t('Unable to preview due to validation errors.'),
];
}
// Assemble the preview, the query info, and the query statistics in the
// requested order.
$table = [
'#type' => 'table',
'#prefix' => '<div class="views-query-info">',
'#suffix' => '</div>',
'#rows' => array_merge($rows['query'], $rows['statistics']),
];
if ($show_location == 'above') {
$output = [
'table' => $table,
'preview' => $preview,
];
}
else {
$output = [
'preview' => $preview,
'table' => $table,
];
}
// Ensure that we just remove an additional request we pushed earlier.
// This could happen if $errors was not empty.
if ($request_stack
->getCurrentRequest() != $current_request) {
$request_stack
->pop();
}
return $output;
}