Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
130 / 130 |
|
100.00% |
5 / 5 |
CRAP | |
100.00% |
1 / 1 |
VisitorsDisplayLink | |
100.00% |
130 / 130 |
|
100.00% |
5 / 5 |
24 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
create | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
buildOptionsForm | |
100.00% |
41 / 41 |
|
100.00% |
1 / 1 |
4 | |||
validate | |
100.00% |
41 / 41 |
|
100.00% |
1 / 1 |
10 | |||
render | |
100.00% |
40 / 40 |
|
100.00% |
1 / 1 |
8 |
1 | <?php |
2 | |
3 | namespace Drupal\visitors\Plugin\views\area; |
4 | |
5 | use Drupal\Core\Config\ImmutableConfig; |
6 | use Drupal\Core\EventSubscriber\AjaxResponseSubscriber; |
7 | use Drupal\Core\EventSubscriber\MainContentViewSubscriber; |
8 | use Drupal\Core\Form\FormBuilderInterface; |
9 | use Drupal\Core\Form\FormStateInterface; |
10 | use Drupal\Core\Url; |
11 | use Drupal\views\Plugin\views\area\DisplayLink; |
12 | use Symfony\Component\DependencyInjection\ContainerInterface; |
13 | |
14 | /** |
15 | * Views area display_link handler. |
16 | * |
17 | * @ingroup views_area_handlers |
18 | * |
19 | * @ViewsArea("visitors_display_link") |
20 | */ |
21 | final class VisitorsDisplayLink extends DisplayLink { |
22 | |
23 | /** |
24 | * The view settings. |
25 | * |
26 | * @var \Drupal\Core\Config\ImmutableConfig |
27 | */ |
28 | protected $viewSettings; |
29 | |
30 | /** |
31 | * Constructs a new VisitorsDisplayLink object. |
32 | * |
33 | * @param array $configuration |
34 | * The plugin configuration. |
35 | * @param string $plugin_id |
36 | * The plugin ID. |
37 | * @param mixed $plugin_definition |
38 | * The plugin definition. |
39 | * @param \Drupal\Core\Config\ImmutableConfig $view_settings |
40 | * The view settings. |
41 | */ |
42 | public function __construct(array $configuration, $plugin_id, $plugin_definition, ImmutableConfig $view_settings) { |
43 | parent::__construct($configuration, $plugin_id, $plugin_definition); |
44 | $this->viewSettings = $view_settings; |
45 | } |
46 | |
47 | /** |
48 | * {@inheritdoc} |
49 | */ |
50 | public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { |
51 | return new self( |
52 | $configuration, |
53 | $plugin_id, |
54 | $plugin_definition, |
55 | $container->get('config.factory')->get('views.settings') |
56 | ); |
57 | } |
58 | |
59 | /** |
60 | * {@inheritdoc} |
61 | */ |
62 | public function buildOptionsForm(&$form, FormStateInterface $form_state) { |
63 | parent::buildOptionsForm($form, $form_state); |
64 | |
65 | $allowed_displays = []; |
66 | $displays = $this->view->storage->get('display'); |
67 | foreach ($displays as $display_id => $display) { |
68 | if ($this->isPathBasedDisplay($display_id)) { |
69 | unset($displays[$display_id]); |
70 | continue; |
71 | } |
72 | $allowed_displays[$display_id] = $display['display_title']; |
73 | } |
74 | |
75 | $form['description'] = [ |
76 | [ |
77 | '#markup' => $this->t('To make sure the results are the same when switching to the other display, it is recommended to make sure the display:'), |
78 | ], |
79 | [ |
80 | '#theme' => 'item_list', |
81 | '#items' => [ |
82 | $this->t('Has a path.'), |
83 | $this->t('Has the same filter criteria.'), |
84 | $this->t('Has the same sort criteria.'), |
85 | $this->t('Has the same pager settings.'), |
86 | $this->t('Has the same contextual filters.'), |
87 | ], |
88 | ], |
89 | ]; |
90 | |
91 | if (!$allowed_displays) { |
92 | $form['empty_message'] = [ |
93 | '#markup' => '<p><em>' . $this->t('There are only path-based displays available.') . '</em></p>', |
94 | ]; |
95 | } |
96 | else { |
97 | $form['display_id'] = [ |
98 | '#title' => $this->t('Display'), |
99 | '#type' => 'select', |
100 | '#options' => $allowed_displays, |
101 | '#default_value' => $this->options['display_id'], |
102 | '#required' => TRUE, |
103 | ]; |
104 | $form['label'] = [ |
105 | '#title' => $this->t('Label'), |
106 | '#description' => $this->t('The text of the link.'), |
107 | '#type' => 'textfield', |
108 | '#default_value' => $this->options['label'], |
109 | '#required' => TRUE, |
110 | ]; |
111 | } |
112 | } |
113 | |
114 | /** |
115 | * {@inheritdoc} |
116 | */ |
117 | public function validate() { |
118 | $errors = []; |
119 | |
120 | // Do not add errors for the default display if it is not displayed in the |
121 | // UI. |
122 | if ($this->displayHandler->isDefaultDisplay() && !$this->viewSettings->get('ui.show.default_display')) { |
123 | return $errors; |
124 | } |
125 | |
126 | // Ajax errors can cause the plugin to be added without any settings. |
127 | $linked_display_id = !empty($this->options['display_id']) ? $this->options['display_id'] : NULL; |
128 | if (!$linked_display_id) { |
129 | $errors[] = $this->t('%current_display: The link in the %area area has no configured display.', [ |
130 | '%current_display' => $this->displayHandler->display['display_title'], |
131 | '%area' => $this->areaType, |
132 | ]); |
133 | return $errors; |
134 | } |
135 | |
136 | // Check if the linked display hasn't been removed. |
137 | if (!$this->view->displayHandlers->get($linked_display_id)) { |
138 | $errors[] = $this->t('%current_display: The link in the %area area points to the %linked_display display which no longer exists.', [ |
139 | '%current_display' => $this->displayHandler->display['display_title'], |
140 | '%area' => $this->areaType, |
141 | '%linked_display' => $this->options['display_id'], |
142 | ]); |
143 | return $errors; |
144 | } |
145 | |
146 | // Check if the linked display is a path-based display. |
147 | if ($this->isPathBasedDisplay($linked_display_id)) { |
148 | $errors[] = $this->t('%current_display: The link in the %area area points to the %linked_display display which does not have a path.', [ |
149 | '%current_display' => $this->displayHandler->display['display_title'], |
150 | '%area' => $this->areaType, |
151 | '%linked_display' => $this->view->displayHandlers->get($linked_display_id)->display['display_title'], |
152 | ]); |
153 | return $errors; |
154 | } |
155 | |
156 | // Check if options of the linked display are equal to the options of the |
157 | // current display. We "only" show a warning here, because even though we |
158 | // recommend keeping the display options equal, we do not want to enforce |
159 | // this. |
160 | $unequal_options = [ |
161 | 'filters' => $this->t('Filter criteria'), |
162 | 'pager' => $this->t('Pager'), |
163 | 'arguments' => $this->t('Contextual filters'), |
164 | ]; |
165 | foreach (array_keys($unequal_options) as $option) { |
166 | if ($this->hasEqualOptions($linked_display_id, $option)) { |
167 | unset($unequal_options[$option]); |
168 | } |
169 | } |
170 | |
171 | if ($unequal_options) { |
172 | $warning = $this->t('%current_display: The link in the %area area points to the %linked_display display which uses different settings than the %current_display display for: %unequal_options. To make sure users see the exact same result when clicking the link, please check that the settings are the same.', [ |
173 | '%current_display' => $this->displayHandler->display['display_title'], |
174 | '%area' => $this->areaType, |
175 | '%linked_display' => $this->view->displayHandlers->get($linked_display_id)->display['display_title'], |
176 | '%unequal_options' => implode(', ', $unequal_options), |
177 | ]); |
178 | $this->messenger()->addWarning($warning); |
179 | } |
180 | return $errors; |
181 | } |
182 | |
183 | /** |
184 | * {@inheritdoc} |
185 | */ |
186 | public function render($empty = FALSE) { |
187 | |
188 | if (($empty && empty($this->options['empty'])) || empty($this->options['display_id'])) { |
189 | return []; |
190 | } |
191 | |
192 | if ($this->isPathBasedDisplay($this->options['display_id'])) { |
193 | return []; |
194 | } |
195 | |
196 | // Get query parameters from the exposed input and pager. |
197 | $query = $this->view->getExposedInput(); |
198 | if ($current_page = $this->view->getCurrentPage()) { |
199 | $query['page'] = $current_page; |
200 | } |
201 | |
202 | // @todo Remove this parsing once these are removed from the request in |
203 | // https://www.drupal.org/node/2504709. |
204 | foreach ([ |
205 | 'view_name', |
206 | 'view_display_id', |
207 | 'view_args', |
208 | 'view_path', |
209 | 'view_dom_id', |
210 | 'pager_element', |
211 | 'view_base_path', |
212 | AjaxResponseSubscriber::AJAX_REQUEST_PARAMETER, |
213 | FormBuilderInterface::AJAX_FORM_REQUEST, |
214 | MainContentViewSubscriber::WRAPPER_FORMAT, |
215 | ] as $key) { |
216 | unset($query[$key]); |
217 | } |
218 | |
219 | // Set default classes. |
220 | $classes = [ |
221 | 'views-display-link', |
222 | 'views-display-link-' . $this->options['display_id'], |
223 | ]; |
224 | if ($this->options['display_id'] === $this->view->current_display) { |
225 | $classes[] = 'is-active'; |
226 | } |
227 | $classes[] = 'use-ajax'; |
228 | $storage_id = $this->view->storage->id(); |
229 | $path = 'internal:/visitors/_report/' . $storage_id . '/' . $this->options['display_id']; |
230 | $query_class = '.view-id-' . $storage_id . '.view-display-id-' . $this->view->current_display; |
231 | |
232 | return [ |
233 | '#type' => 'link', |
234 | '#title' => $this->options['label'], |
235 | '#url' => Url::fromUri($path, [ |
236 | 'query' => ['class' => $query_class], |
237 | ]), |
238 | '#options' => [ |
239 | 'attributes' => ['class' => $classes], |
240 | ], |
241 | ]; |
242 | } |
243 | |
244 | } |