Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
DisplayLinkController
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 2
306
0.00% covered (danger)
0.00%
0 / 1
 __invoke
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 1
210
 extractViewAndDisplayFromClass
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace Drupal\visitors\Controller;
4
5use Drupal\Core\Ajax\AjaxResponse;
6use Drupal\Core\Ajax\ReplaceCommand;
7use Drupal\Core\Controller\ControllerBase;
8use Drupal\views\Views;
9use Symfony\Component\HttpFoundation\Request;
10
11/**
12 * Display Link Controller.
13 *
14 * Returns the display link for a given view and display.
15 */
16class DisplayLinkController extends ControllerBase {
17
18  /**
19   * Single-action controller.
20   */
21  public function __invoke(Request $request, string $view_id, string $display_id) {
22    $blocks['path'] = [
23      '#view_id'      => $view_id,
24      '#view_display' => $display_id,
25    ];
26
27    // Store AJAX parameters to exclude from sort links in a static variable
28    // that can be accessed by our theme preprocessing hook.
29    $ajax_params_to_remove = [
30      'class',
31      '_wrapper_format',
32      'ajax_form',
33      '_drupal_ajax',
34    ];
35
36    // Store these in a static variable for the theme hook.
37    $excluded_params = &drupal_static('visitors_excluded_sort_params', []);
38    $excluded_params = $ajax_params_to_remove;
39
40    // Get the referrer URL and extract sort/order parameters.
41    $referrer = $request->headers->get('referer');
42    $referrer_path = '';
43    $sort_args = [];
44
45    if ($referrer) {
46      $referrer_parts = parse_url($referrer);
47      $referrer_path = $referrer_parts['path'] ?? '';
48
49      // Extract query parameters from referrer.
50      if (!empty($referrer_parts['query'])) {
51        parse_str($referrer_parts['query'], $referrer_query);
52
53        // Check if referrer has sort/order parameters.
54        if (isset($referrer_query['order'])) {
55          $sort_args['order'] = $referrer_query['order'];
56        }
57        if (isset($referrer_query['sort'])) {
58          $sort_args['sort'] = $referrer_query['sort'];
59        }
60      }
61
62      $referrer_path_static = &drupal_static('visitors_referrer_path', '');
63      $referrer_path_static = $referrer_path;
64    }
65
66    // Apply sort parameters from referrer to the view.
67    if (!empty($sort_args)) {
68      // Load the view manually to apply sorting.
69      $view = Views::getView($view_id);
70      if ($view && $view->access($display_id)) {
71        $view->setDisplay($display_id);
72
73        // Apply the sort parameters to the view.
74        if (isset($sort_args['order']) && isset($sort_args['sort'])) {
75          $order_field = $sort_args['order'];
76          $sort_direction = strtoupper($sort_args['sort']);
77
78          // Set the sort on the view's table style plugin.
79          if ($view->display_handler->getPlugin('style') &&
80              method_exists($view->display_handler->getPlugin('style'), 'options')) {
81            $style_plugin = $view->display_handler->getPlugin('style');
82            $style_plugin->active = $order_field;
83            $style_plugin->order = $sort_direction;
84          }
85
86          // Also set it via the request for the table style to pick up.
87          $temp_query = $sort_args;
88          $temp_request = $request->duplicate($temp_query);
89          $view->setRequest($temp_request);
90        }
91
92        // Build the renderable array.
93        $rendered = $view->buildRenderable($display_id);
94      }
95      else {
96        // Fallback to normal embed if view access fails.
97        $rendered = \views_embed_view($view_id, $display_id);
98      }
99    }
100    else {
101      $rendered = \views_embed_view($view_id, $display_id);
102    }
103
104    // Set live preview mode to ensure sort links use current route.
105    if (isset($rendered['view_build']['#view'])) {
106      $view = $rendered['view_build']['#view'];
107      $view->live_preview = TRUE;
108      if (!empty($referrer_path)) {
109        $view->override_path = $referrer_path;
110      }
111    }
112
113    $settings = NULL;
114    $selector = $request->query->get('class');
115
116    $response = new AjaxResponse();
117    $response->addCommand(new ReplaceCommand($selector, $rendered, $settings));
118
119    return $response;
120  }
121
122  /**
123   * Extract view ID and display ID from the class parameter.
124   *
125   * The class parameter contains the format:
126   *  .view-id-{view_id}.view-display-id-{display_id}
127   * This method extracts both the view ID and display ID from this format.
128   *
129   * @param string|null $class_selector
130   *   The class selector string.
131   *
132   * @return array|null
133   *   Array containing [view_id, display_id] if found, null otherwise.
134   */
135  protected function extractViewAndDisplayFromClass(?string $class_selector): ?array {
136    if (empty($class_selector)) {
137      return NULL;
138    }
139
140    // Extract view ID and display ID from the format:
141    // .view-id-{view_id}.view-display-id-{display_id}.
142    if (preg_match('/\.view-id-([^.\s]+)\.view-display-id-([^.\s]+)/', $class_selector, $matches)) {
143      return [$matches[1], $matches[2]];
144    }
145
146    return NULL;
147  }
148
149}