function ViewUI::renderPreview

Same name and namespace in other branches
  1. 9 core/modules/views_ui/src/ViewUI.php \Drupal\views_ui\ViewUI::renderPreview()
  2. 10 core/modules/views_ui/src/ViewUI.php \Drupal\views_ui\ViewUI::renderPreview()
  3. 11.x core/modules/views_ui/src/ViewUI.php \Drupal\views_ui\ViewUI::renderPreview()

File

core/modules/views_ui/src/ViewUI.php, line 518

Class

ViewUI
Stores UI related temporary settings.

Namespace

Drupal\views_ui

Code

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

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.