Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
96.48% |
849 / 880 |
|
90.91% |
10 / 11 |
CRAP | n/a |
0 / 0 |
|
visitors_help | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
2 | |||
visitors_cron | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
visitors_page_attachments | |
0.00% |
0 / 31 |
|
0.00% |
0 / 1 |
90 | |||
visitors_form_user_form_alter | |
100.00% |
29 / 29 |
|
100.00% |
1 / 1 |
5 | |||
visitors_user_profile_form_submit | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
visitors_node_links_alter | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
4 | |||
visitors_entity_delete | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
visitors_ranking | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
3 | |||
visitors_views_data | |
100.00% |
721 / 721 |
|
100.00% |
1 / 1 |
7 | |||
visitors_token_info | |
100.00% |
21 / 21 |
|
100.00% |
1 / 1 |
2 | |||
visitors_tokens | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
12 |
1 | <?php |
2 | |
3 | /** |
4 | * @file |
5 | * Logs visitors for your site. |
6 | */ |
7 | |
8 | use Drupal\Core\Access\AccessResult; |
9 | use Drupal\Core\Entity\ContentEntityInterface; |
10 | use Drupal\Core\Entity\EntityInterface; |
11 | use Drupal\Core\Form\FormStateInterface; |
12 | use Drupal\Core\Render\BubbleableMetadata; |
13 | use Drupal\Core\Utility\Error; |
14 | use Drupal\node\NodeInterface; |
15 | use Drupal\visitors\VisitorsVisibilityInterface; |
16 | |
17 | /** |
18 | * Implements hook_help(). |
19 | */ |
20 | function visitors_help($route_name, $route_match) { |
21 | switch ($route_name) { |
22 | case 'help.page.visitors': |
23 | $help = '<p><a href="https://git.drupalcode.org/project/visitors/-/commits/8.x-2.x"><img alt="coverage report" src="https://git.drupalcode.org/project/visitors/badges/8.x-2.x/coverage.svg" /></a> '; |
24 | $help .= '<a href="https://git.drupalcode.org/project/visitors/-/commits/8.x-2.x"><img alt="pipeline status" src="https://git.drupalcode.org/project/visitors/badges/8.x-2.x/pipeline.svg" /></a> '; |
25 | $help .= '<a href="https://www.drupal.org/project/visitors">Homepage</a> '; |
26 | $help .= '<a href="https://www.drupal.org/project/issues/visitors?version=any_8.x-">Issues</a></p>'; |
27 | $help .= '<p>' |
28 | . t('The Visitors module logs all visitors to your site and provides various statistics about them.') |
29 | . '</p>'; |
30 | |
31 | return [ |
32 | '#title' => t('Visitors'), |
33 | 'description' => [ |
34 | '#markup' => $help, |
35 | ], |
36 | ]; |
37 | |
38 | } |
39 | } |
40 | |
41 | /** |
42 | * Implements hook_cron(). |
43 | */ |
44 | function visitors_cron(): void { |
45 | \Drupal::service('visitors.cron')->execute(); |
46 | } |
47 | |
48 | /** |
49 | * Implements hook_page_attachments(). |
50 | */ |
51 | function visitors_page_attachments(array &$page) { |
52 | $required_permissions = ['access visitors', 'access toolbar']; |
53 | $current_user = \Drupal::currentUser(); |
54 | $access = AccessResult::allowedIfHasPermissions($current_user, $required_permissions); |
55 | if ($access->isAllowed()) { |
56 | $page['#attached']['library'][] = 'visitors/menu'; |
57 | } |
58 | $page['#cache']['tags'][] = 'user:' . $current_user->id(); |
59 | $page['#cache']['tags'][] = 'config:visitors.config'; |
60 | $page['#cache']['contexts'][] = 'user'; |
61 | |
62 | try { |
63 | /** @var \Drupal\visitors\VisitorsVisibilityInterface $visibility_service */ |
64 | $visibility_service = \Drupal::service('visitors.visibility'); |
65 | if (!$visibility_service->isVisible()) { |
66 | return NULL; |
67 | } |
68 | |
69 | $route = \Drupal::routeMatch()->getRouteName(); |
70 | $base_path = \Drupal::request()->getBasePath(); |
71 | $module_path = \Drupal::service('module_handler')->getModule('visitors')->getPath(); |
72 | |
73 | $page['#attached']['drupalSettings']['visitors']['module'] = "$base_path/$module_path"; |
74 | $page['#attached']['drupalSettings']['visitors']['route'] = $route; |
75 | $page['#attached']['drupalSettings']['visitors']['server'] = gethostname(); |
76 | $page['#attached']['library'][] = 'visitors/visitors'; |
77 | |
78 | $route_array = explode('.', $route); |
79 | if (count($route_array) == 3 && $route_array[0] == 'entity' && $route_array[2] == 'canonical') { |
80 | $entity_type = $route_array[1]; |
81 | $settings = \Drupal::config('visitors.config'); |
82 | $entity_types = $settings->get('counter.entity_types') ?? []; |
83 | $is_disabled_or_not_has_entity_types = !$settings->get('counter.enabled') || !in_array($entity_type, $entity_types); |
84 | if ($is_disabled_or_not_has_entity_types) { |
85 | return NULL; |
86 | } |
87 | $entity_id = \Drupal::routeMatch()->getParameter($entity_type)->id(); |
88 | $page['#attached']['drupalSettings']['visitors']['counter'] = "$entity_type:$entity_id"; |
89 | } |
90 | |
91 | } |
92 | catch (\Exception $e) { |
93 | $logger = \Drupal::logger('visitors'); |
94 | Error::logException($logger, $e); |
95 | } |
96 | |
97 | } |
98 | |
99 | /** |
100 | * Implements hook_form_FORM_ID_alter(). |
101 | * |
102 | * Allow users to decide if tracking code will be added to pages or not. |
103 | */ |
104 | function visitors_form_user_form_alter(&$form, FormStateInterface $form_state) { |
105 | |
106 | $config = \Drupal::config('visitors.config'); |
107 | $visibility_users = $config->get('visibility.user_account_mode'); |
108 | |
109 | if ($visibility_users == VisitorsVisibilityInterface::USER_NO_PERSONALIZATION) { |
110 | return; |
111 | } |
112 | |
113 | /** @var \Drupal\user\AccountForm $user_form */ |
114 | $user_form = $form_state->getFormObject(); |
115 | /** @var \Drupal\user\UserInterface $account */ |
116 | $account = $user_form->getEntity(); |
117 | |
118 | if (!$account->hasPermission('opt-out of visitors tracking')) { |
119 | return; |
120 | } |
121 | |
122 | $account_data_visitors = \Drupal::service('user.data')->get('visitors', $account->id()); |
123 | |
124 | $form['visitors'] = [ |
125 | '#type' => 'details', |
126 | '#title' => t('Visitors settings'), |
127 | '#weight' => 3, |
128 | '#open' => TRUE, |
129 | ]; |
130 | $description = ''; |
131 | switch ($visibility_users) { |
132 | case VisitorsVisibilityInterface::USER_OPT_OUT: |
133 | $description = t('Users are tracked by default, but you are able to opt out.'); |
134 | break; |
135 | |
136 | case VisitorsVisibilityInterface::USER_OPT_IN: |
137 | $description = t('Users are <em>not</em> tracked by default, but you are able to opt in.'); |
138 | break; |
139 | } |
140 | |
141 | $default_value = $account_data_visitors['user_account_users'] ?? $visibility_users; |
142 | $form['visitors']['user_account_users'] = [ |
143 | '#type' => 'checkbox', |
144 | '#title' => t('Enable user tracking'), |
145 | '#description' => $description, |
146 | '#default_value' => $default_value, |
147 | ]; |
148 | |
149 | // Custom submit handler. |
150 | $form['actions']['submit']['#submit'][] = 'visitors_user_profile_form_submit'; |
151 | |
152 | } |
153 | |
154 | /** |
155 | * Submit callback for user profile form to save the Visitor setting. |
156 | */ |
157 | function visitors_user_profile_form_submit($form, FormStateInterface $form_state) { |
158 | if (!$form_state->hasValue('user_account_users')) { |
159 | return; |
160 | } |
161 | /** @var \Drupal\user\AccountForm $user_form */ |
162 | $user_form = $form_state->getFormObject(); |
163 | /** @var \Drupal\user\UserInterface $account */ |
164 | $account = $user_form->getEntity(); |
165 | |
166 | $value = (int) $form_state->getValue('user_account_users'); |
167 | \Drupal::service('user.data') |
168 | ->set('visitors', $account->id(), 'user_account_users', $value); |
169 | } |
170 | |
171 | /** |
172 | * Implements hook_node_links_alter(). |
173 | */ |
174 | function visitors_node_links_alter(array &$links, NodeInterface $entity, array &$context) { |
175 | if ($context['view_mode'] == 'rss') { |
176 | return NULL; |
177 | } |
178 | $links['#cache']['contexts'][] = 'user.permissions'; |
179 | if (!\Drupal::currentUser()->hasPermission('view visitors counter')) { |
180 | return NULL; |
181 | } |
182 | $settings = \Drupal::config('visitors.config'); |
183 | |
184 | $statistics = \Drupal::service('visitors.counter')->fetchView('node', $entity->id()); |
185 | if ($statistics) { |
186 | $statistics_links['visitors_counter']['title'] = \Drupal::translation() |
187 | ->formatPlural($statistics->getTotalCount(), '1 view', '@count views'); |
188 | $links['visitors'] = [ |
189 | '#theme' => 'links__node__visitors', |
190 | '#links' => $statistics_links, |
191 | '#attributes' => ['class' => ['links', 'inline']], |
192 | ]; |
193 | } |
194 | $links['#cache']['max-age'] = $settings->get('counter.display_max_age'); |
195 | |
196 | } |
197 | |
198 | /** |
199 | * Implements hook_entity_delete(). |
200 | */ |
201 | function visitors_entity_delete(EntityInterface $entity) { |
202 | |
203 | $entity_id = $entity->id(); |
204 | if (!is_int($entity_id)) { |
205 | return; |
206 | } |
207 | $entity_type = $entity->getEntityTypeId(); |
208 | |
209 | \Drupal::service('visitors.counter') |
210 | ->deleteViews($entity_type, $entity_id); |
211 | } |
212 | |
213 | /** |
214 | * Implements hook_ranking(). |
215 | */ |
216 | function visitors_ranking() { |
217 | $settings = \Drupal::config('visitors.config'); |
218 | $is_enabled_and_has_node_entity_type = $settings->get('counter.enabled') |
219 | && in_array('node', $settings->get('counter.entity_types')); |
220 | if ($is_enabled_and_has_node_entity_type) { |
221 | return [ |
222 | 'views' => [ |
223 | 'title' => t('Number of views'), |
224 | 'join' => [ |
225 | 'type' => 'LEFT', |
226 | 'table' => 'visitors_counter', |
227 | 'alias' => 'visitors_counter', |
228 | 'on' => "visitors_counter.entity_id = i.sid AND visitors_counter.entity_type = 'node'", |
229 | ], |
230 | // Inverse law that maps the highest view count on the site to 1 and 0 |
231 | // to 0. Note that the ROUND here is necessary for PostgreSQL and SQLite |
232 | // in order to ensure that the :statistics_scale argument is treated as |
233 | // a numeric type, because the PostgreSQL PDO driver sometimes puts |
234 | // values in as strings instead of numbers in complex expressions like |
235 | // this. |
236 | 'score' => '2.0 - 2.0 / (1.0 + visitors_counter.total * (ROUND(:statistics_scale, 4)))', |
237 | 'arguments' => [':statistics_scale' => \Drupal::state()->get('visitors.node_counter_scale', 0)], |
238 | ], |
239 | ]; |
240 | } |
241 | } |
242 | |
243 | /** |
244 | * Implements hook_views_data(). |
245 | */ |
246 | function visitors_views_data() { |
247 | $data = []; |
248 | $data['visitors_counter']['table']['group'] = t('Visitor counters'); |
249 | $data['visitors_counter']['table']['base'] = [ |
250 | 'title' => t('Visitor Counters'), |
251 | 'help' => t('Visitors data from visitors DB table.'), |
252 | ]; |
253 | $settings = \Drupal::config('visitors.config'); |
254 | $supported_entity_types = $settings->get('counter.entity_types') ?? []; |
255 | foreach (\Drupal::entityTypeManager()->getDefinitions() as $entity_type_id => $entity_type) { |
256 | $base_table = $entity_type->getBaseTable(); |
257 | if (!in_array($entity_type_id, $supported_entity_types) || !$entity_type->entityClassImplements(ContentEntityInterface::class) || !$base_table) { |
258 | continue; |
259 | } |
260 | |
261 | $base_table = $entity_type->getDataTable() ?: $base_table; |
262 | $args = ['@entity_type' => $entity_type_id]; |
263 | |
264 | // Multilingual properties are stored in data table. |
265 | if (!($table = $entity_type->getDataTable())) { |
266 | $table = $base_table; |
267 | } |
268 | $data[$base_table]['visitors_counter'] = [ |
269 | 'title' => t('Visitors @entity_type counter', $args), |
270 | 'help' => t('Relate all visitor counts on the @entity_type.', $args), |
271 | 'relationship' => [ |
272 | 'group' => t('Visitor Counters'), |
273 | 'label' => t('Visitor counters'), |
274 | 'base' => 'visitors_counter', |
275 | 'base field' => 'entity_id', |
276 | 'relationship field' => $entity_type->getKey('id'), |
277 | 'id' => 'standard', |
278 | 'extra' => [ |
279 | [ |
280 | 'field' => 'entity_type', |
281 | 'value' => $entity_type_id, |
282 | ], |
283 | ], |
284 | ], |
285 | ]; |
286 | |
287 | $data['visitors_counter']['table']['join'][$table] = [ |
288 | 'type' => 'LEFT', |
289 | 'left_field' => $entity_type->getKey('id'), |
290 | 'field' => 'entity_id', |
291 | 'extra' => [ |
292 | [ |
293 | 'field' => 'entity_type', |
294 | 'value' => $entity_type_id, |
295 | ], |
296 | ], |
297 | ]; |
298 | |
299 | } |
300 | |
301 | $data['visitors_counter']['total'] = [ |
302 | 'title' => t('Total views'), |
303 | 'help' => t('The total number of times the node has been viewed.'), |
304 | 'field' => [ |
305 | 'id' => 'visitors_numeric', |
306 | 'click sortable' => TRUE, |
307 | ], |
308 | 'filter' => [ |
309 | 'id' => 'numeric', |
310 | ], |
311 | 'argument' => [ |
312 | 'id' => 'numeric', |
313 | ], |
314 | 'sort' => [ |
315 | 'id' => 'standard', |
316 | ], |
317 | ]; |
318 | $data['visitors_counter']['today'] = [ |
319 | 'title' => t('Views today'), |
320 | 'help' => t('The total number of times the node has been viewed today.'), |
321 | 'field' => [ |
322 | 'id' => 'visitors_numeric', |
323 | 'click sortable' => TRUE, |
324 | ], |
325 | 'filter' => [ |
326 | 'id' => 'numeric', |
327 | ], |
328 | 'argument' => [ |
329 | 'id' => 'numeric', |
330 | ], |
331 | 'sort' => [ |
332 | 'id' => 'standard', |
333 | ], |
334 | ]; |
335 | $data['visitors_counter']['timestamp'] = [ |
336 | 'title' => t('Most recent visit'), |
337 | 'help' => t('The most recent time the node has been viewed.'), |
338 | 'field' => [ |
339 | 'id' => 'visitors_counter_timestamp', |
340 | 'click sortable' => TRUE, |
341 | ], |
342 | 'filter' => [ |
343 | 'id' => 'date', |
344 | ], |
345 | 'argument' => [ |
346 | 'id' => 'date', |
347 | ], |
348 | 'sort' => [ |
349 | 'id' => 'standard', |
350 | ], |
351 | ]; |
352 | |
353 | $data['visitors']['table']['group'] = t('Visitors'); |
354 | $data['visitors']['table']['base'] = [ |
355 | 'title' => t('Visitors'), |
356 | 'help' => t('Visitors data from visitors DB table.'), |
357 | ]; |
358 | |
359 | $data['visitors']['visitors_id'] = [ |
360 | 'title' => t('Visitors ID'), |
361 | 'help' => t('Visitors entry ID.'), |
362 | 'field' => [ |
363 | 'id' => 'numeric', |
364 | ], |
365 | 'sort' => [ |
366 | 'id' => 'standard', |
367 | ], |
368 | 'filter' => [ |
369 | 'id' => 'numeric', |
370 | ], |
371 | 'argument' => [ |
372 | 'id' => 'numeric', |
373 | ], |
374 | ]; |
375 | $data['visitors']['visitor_id'] = [ |
376 | 'title' => t('Unique visitor'), |
377 | 'help' => t('A unique ID for the visitor.'), |
378 | 'field' => [ |
379 | 'id' => 'standard', |
380 | ], |
381 | 'filter' => [ |
382 | 'id' => 'string', |
383 | ], |
384 | 'sort' => [ |
385 | 'id' => 'standard', |
386 | ], |
387 | 'argument' => [ |
388 | 'id' => 'string', |
389 | ], |
390 | ]; |
391 | $data['visitors']['visitors_uid'] = [ |
392 | 'title' => t('Visitors UID'), |
393 | 'help' => t('The user ID of the visitors entry.'), |
394 | 'field' => [ |
395 | 'id' => 'standard', |
396 | ], |
397 | 'relationship' => [ |
398 | 'title' => t('User'), |
399 | 'help' => t('The user entity from the visitor entry.'), |
400 | 'base' => 'users_field_data', |
401 | 'base field' => 'uid', |
402 | 'id' => 'standard', |
403 | ], |
404 | 'filter' => [ |
405 | 'id' => 'numeric', |
406 | ], |
407 | 'argument' => [ |
408 | 'id' => 'numeric', |
409 | ], |
410 | ]; |
411 | $data['visitors']['visitors_date_time'] = [ |
412 | 'title' => t('Visitors Date Time'), |
413 | 'help' => t('The timestamp from the visitors entry.'), |
414 | 'field' => [ |
415 | 'id' => 'date', |
416 | 'click sortable' => TRUE, |
417 | ], |
418 | 'filter' => [ |
419 | 'id' => 'visitors_date', |
420 | ], |
421 | ]; |
422 | $data['visitors']['visitors_hour'] = [ |
423 | 'title' => t('Hour'), |
424 | 'help' => t('The hour (server) of the visit.'), |
425 | 'field' => [ |
426 | 'id' => 'visitors_hour', |
427 | 'field' => 'visitors_date_time', |
428 | ], |
429 | 'sort' => [ |
430 | 'id' => 'visitors_timestamp', |
431 | 'field' => 'visitors_date_time', |
432 | ], |
433 | ]; |
434 | $data['visitors']['visitors_month'] = [ |
435 | 'title' => t('Month'), |
436 | 'help' => t('The month of the visit.'), |
437 | 'field' => [ |
438 | 'id' => 'visitors_month', |
439 | 'field' => 'visitors_date_time', |
440 | ], |
441 | 'sort' => [ |
442 | 'id' => 'visitors_timestamp', |
443 | 'field' => 'visitors_date_time', |
444 | ], |
445 | ]; |
446 | $data['visitors']['visitors_day_of_week'] = [ |
447 | 'title' => t('Day of Week'), |
448 | 'help' => t('The day of week of the visit.'), |
449 | 'field' => [ |
450 | 'id' => 'visitors_day_of_week', |
451 | 'field' => 'visitors_date_time', |
452 | ], |
453 | 'sort' => [ |
454 | 'id' => 'visitors_timestamp', |
455 | 'field' => 'visitors_date_time', |
456 | ], |
457 | ]; |
458 | $data['visitors']['visitors_day_of_month'] = [ |
459 | 'title' => t('Day of Month'), |
460 | 'help' => t('The day of month of the visit.'), |
461 | 'field' => [ |
462 | 'id' => 'visitors_day_of_month', |
463 | 'field' => 'visitors_date_time', |
464 | ], |
465 | 'sort' => [ |
466 | 'id' => 'visitors_timestamp', |
467 | 'field' => 'visitors_date_time', |
468 | ], |
469 | ]; |
470 | $data['visitors']['visitors_day'] = [ |
471 | 'title' => t('Day'), |
472 | 'help' => t('The day of the visit.'), |
473 | 'field' => [ |
474 | 'id' => 'visitors_day', |
475 | 'field' => 'visitors_date_time', |
476 | ], |
477 | 'sort' => [ |
478 | 'id' => 'visitors_timestamp', |
479 | 'field' => 'visitors_date_time', |
480 | ], |
481 | ]; |
482 | $data['visitors']['visitors_week'] = [ |
483 | 'title' => t('Week'), |
484 | 'help' => t('The week of the visit.'), |
485 | 'field' => [ |
486 | 'id' => 'visitors_week', |
487 | 'field' => 'visitors_date_time', |
488 | ], |
489 | 'sort' => [ |
490 | 'id' => 'visitors_timestamp', |
491 | 'field' => 'visitors_date_time', |
492 | ], |
493 | ]; |
494 | $data['visitors']['visitor_localtime'] = [ |
495 | 'title' => t('Visitor Hour'), |
496 | 'help' => t('The hour (client) of the visit.'), |
497 | 'field' => [ |
498 | 'id' => 'visitors_local_hour', |
499 | 'field' => 'visitor_localtime', |
500 | ], |
501 | 'sort' => [ |
502 | 'id' => 'visitors_timestamp', |
503 | 'field' => 'visitors_date_time', |
504 | ], |
505 | ]; |
506 | $data['visitors']['visitors_ip'] = [ |
507 | 'title' => t('Visitors IP'), |
508 | 'help' => t('The IP of the visitors entry.'), |
509 | 'field' => [ |
510 | 'id' => 'standard', |
511 | ], |
512 | 'filter' => [ |
513 | 'id' => 'string', |
514 | ], |
515 | 'argument' => [ |
516 | 'id' => 'string', |
517 | ], |
518 | ]; |
519 | $data['visitors']['server'] = [ |
520 | 'title' => t('Server'), |
521 | 'help' => t('The server that generated the response.'), |
522 | 'field' => [ |
523 | 'id' => 'standard', |
524 | ], |
525 | 'filter' => [ |
526 | 'id' => 'string', |
527 | ], |
528 | 'argument' => [ |
529 | 'id' => 'string', |
530 | ], |
531 | ]; |
532 | $data['visitors']['visitors_url'] = [ |
533 | 'title' => t('Visitors URL'), |
534 | 'help' => t('The URL of the visitors entry.'), |
535 | 'field' => [ |
536 | 'id' => 'standard', |
537 | ], |
538 | 'filter' => [ |
539 | 'id' => 'string', |
540 | ], |
541 | ]; |
542 | $data['visitors']['visitors_referer'] = [ |
543 | 'title' => t('Visitors referer'), |
544 | 'help' => t('The referer of the visitors entry.'), |
545 | 'field' => [ |
546 | 'id' => 'standard', |
547 | ], |
548 | 'filter' => [ |
549 | 'id' => 'string', |
550 | ], |
551 | ]; |
552 | $data['visitors']['visitors_path'] = [ |
553 | 'title' => t('Visitors path'), |
554 | 'help' => t('The path of the visitors entry.'), |
555 | 'field' => [ |
556 | 'id' => 'standard', |
557 | ], |
558 | 'filter' => [ |
559 | 'id' => 'string', |
560 | ], |
561 | 'argument' => [ |
562 | 'id' => 'string', |
563 | ], |
564 | ]; |
565 | $data['visitors']['route'] = [ |
566 | 'title' => t('Route'), |
567 | 'help' => t('The route of the visitors entry.'), |
568 | 'field' => [ |
569 | 'id' => 'standard', |
570 | ], |
571 | 'filter' => [ |
572 | 'id' => 'string', |
573 | ], |
574 | 'argument' => [ |
575 | 'id' => 'string', |
576 | ], |
577 | ]; |
578 | $data['visitors']['visitors_title'] = [ |
579 | 'title' => t('Visitors title'), |
580 | 'help' => t('The title of the visitors entry.'), |
581 | 'field' => [ |
582 | 'id' => 'standard', |
583 | ], |
584 | 'filter' => [ |
585 | 'id' => 'string', |
586 | ], |
587 | ]; |
588 | $data['visitors']['visitors_user_agent'] = [ |
589 | 'title' => t('Visitors user agent'), |
590 | 'help' => t('The user agent of the visitors entry.'), |
591 | 'field' => [ |
592 | 'id' => 'standard', |
593 | ], |
594 | 'filter' => [ |
595 | 'id' => 'string', |
596 | ], |
597 | ]; |
598 | $data['visitors']['config_resolution'] = [ |
599 | 'title' => t('Resolution'), |
600 | 'help' => t("The visitor's screen resolution."), |
601 | 'field' => [ |
602 | 'id' => 'standard', |
603 | ], |
604 | 'filter' => [ |
605 | 'id' => 'string', |
606 | ], |
607 | 'argument' => [ |
608 | 'id' => 'string', |
609 | ], |
610 | ]; |
611 | $data['visitors']['config_pdf'] = [ |
612 | 'title' => t('PDF Plugin'), |
613 | 'help' => t("The visitor's browser supports PDFs."), |
614 | 'field' => [ |
615 | 'id' => 'visitors_pdf', |
616 | ], |
617 | 'filter' => [ |
618 | 'id' => 'boolean', |
619 | ], |
620 | ]; |
621 | $data['visitors']['config_flash'] = [ |
622 | 'title' => t('Flash Plugin'), |
623 | 'help' => t("The visitor's browser supports Flash."), |
624 | 'field' => [ |
625 | 'id' => 'visitors_flash', |
626 | ], |
627 | 'filter' => [ |
628 | 'id' => 'boolean', |
629 | ], |
630 | ]; |
631 | $data['visitors']['config_java'] = [ |
632 | 'title' => t('Java Plugin'), |
633 | 'help' => t("The visitor's browser supports Java."), |
634 | 'field' => [ |
635 | 'id' => 'visitors_java', |
636 | ], |
637 | 'filter' => [ |
638 | 'id' => 'boolean', |
639 | ], |
640 | ]; |
641 | $data['visitors']['config_quicktime'] = [ |
642 | 'title' => t('Quicktime Plugin'), |
643 | 'help' => t("The visitor's browser supports Quicktime."), |
644 | 'field' => [ |
645 | 'id' => 'visitors_quicktime', |
646 | ], |
647 | 'filter' => [ |
648 | 'id' => 'boolean', |
649 | ], |
650 | ]; |
651 | $data['visitors']['config_realplayer'] = [ |
652 | 'title' => t('Realplayer Plugin'), |
653 | 'help' => t("The visitor's browser supports Realplayer."), |
654 | 'field' => [ |
655 | 'id' => 'visitors_realplayer', |
656 | ], |
657 | 'filter' => [ |
658 | 'id' => 'boolean', |
659 | ], |
660 | ]; |
661 | $data['visitors']['config_windowsmedia'] = [ |
662 | 'title' => t('Windows Media Plugin'), |
663 | 'help' => t("The visitor's browser supports Windows Media."), |
664 | 'field' => [ |
665 | 'id' => 'visitors_windowsmedia', |
666 | ], |
667 | 'filter' => [ |
668 | 'id' => 'boolean', |
669 | ], |
670 | ]; |
671 | $data['visitors']['config_silverlight'] = [ |
672 | 'title' => t('Silverlight Plugin'), |
673 | 'help' => t("The visitor's browser supports Silverlight."), |
674 | 'field' => [ |
675 | 'id' => 'visitors_silverlight', |
676 | ], |
677 | 'filter' => [ |
678 | 'id' => 'boolean', |
679 | ], |
680 | ]; |
681 | $data['visitors']['config_cookie'] = [ |
682 | 'title' => t('Cookie Plugin'), |
683 | 'help' => t("The visitor's browser supports cookies."), |
684 | 'field' => [ |
685 | 'id' => 'visitors_cookie', |
686 | ], |
687 | 'filter' => [ |
688 | 'id' => 'boolean', |
689 | ], |
690 | ]; |
691 | $data['visitors']['config_browser_engine'] = [ |
692 | 'title' => t('Browser Engine'), |
693 | 'help' => t('The engine used by the browser.'), |
694 | 'field' => [ |
695 | 'id' => 'standard', |
696 | ], |
697 | 'filter' => [ |
698 | 'id' => 'string', |
699 | ], |
700 | 'argument' => [ |
701 | 'id' => 'string', |
702 | ], |
703 | ]; |
704 | $data['visitors']['config_browser_name'] = [ |
705 | 'title' => t('Browser Name'), |
706 | 'help' => t('The name of the browser.'), |
707 | 'field' => [ |
708 | 'id' => 'visitors_browser', |
709 | ], |
710 | 'filter' => [ |
711 | 'id' => 'string', |
712 | ], |
713 | 'argument' => [ |
714 | 'id' => 'string', |
715 | ], |
716 | ]; |
717 | $data['visitors']['config_browser_version'] = [ |
718 | 'title' => t('Browser Version'), |
719 | 'help' => t('The version of the browser.'), |
720 | 'field' => [ |
721 | 'id' => 'standard', |
722 | ], |
723 | 'filter' => [ |
724 | 'id' => 'string', |
725 | ], |
726 | 'argument' => [ |
727 | 'id' => 'string', |
728 | ], |
729 | ]; |
730 | $data['visitors']['config_client_type'] = [ |
731 | 'title' => t('Client type'), |
732 | 'help' => t('The type of the client.'), |
733 | 'field' => [ |
734 | 'id' => 'standard', |
735 | ], |
736 | 'filter' => [ |
737 | 'id' => 'string', |
738 | ], |
739 | 'argument' => [ |
740 | 'id' => 'string', |
741 | ], |
742 | ]; |
743 | $data['visitors']['config_device_brand'] = [ |
744 | 'title' => t('Device brand'), |
745 | 'help' => t('The brand of the device.'), |
746 | 'field' => [ |
747 | 'id' => 'visitors_brand', |
748 | ], |
749 | 'filter' => [ |
750 | 'id' => 'string', |
751 | ], |
752 | 'argument' => [ |
753 | 'id' => 'string', |
754 | ], |
755 | ]; |
756 | $data['visitors']['config_device_model'] = [ |
757 | 'title' => t('Device model'), |
758 | 'help' => t('The model of the device.'), |
759 | 'field' => [ |
760 | 'id' => 'standard', |
761 | ], |
762 | 'filter' => [ |
763 | 'id' => 'string', |
764 | ], |
765 | 'argument' => [ |
766 | 'id' => 'string', |
767 | ], |
768 | ]; |
769 | $data['visitors']['config_device_type'] = [ |
770 | 'title' => t('Device type'), |
771 | 'help' => t('The type of device.'), |
772 | 'field' => [ |
773 | 'id' => 'visitors_device', |
774 | ], |
775 | 'filter' => [ |
776 | 'id' => 'string', |
777 | ], |
778 | 'argument' => [ |
779 | 'id' => 'string', |
780 | ], |
781 | ]; |
782 | $data['visitors']['config_os'] = [ |
783 | 'title' => t('Operating System'), |
784 | 'help' => t('The operating system.'), |
785 | 'field' => [ |
786 | 'id' => 'visitors_operating_system', |
787 | ], |
788 | 'filter' => [ |
789 | 'id' => 'string', |
790 | ], |
791 | 'argument' => [ |
792 | 'id' => 'string', |
793 | ], |
794 | ]; |
795 | $data['visitors']['config_os_version'] = [ |
796 | 'title' => t('OS version'), |
797 | 'help' => t('The version of the Operating System.'), |
798 | 'field' => [ |
799 | 'id' => 'standard', |
800 | ], |
801 | 'filter' => [ |
802 | 'id' => 'string', |
803 | ], |
804 | 'argument' => [ |
805 | 'id' => 'string', |
806 | ], |
807 | ]; |
808 | $data['visitors']['bot'] = [ |
809 | 'title' => t('Bot'), |
810 | 'help' => t("The visit is from a bot."), |
811 | 'field' => [ |
812 | 'id' => 'boolean', |
813 | ], |
814 | 'filter' => [ |
815 | 'id' => 'boolean', |
816 | ], |
817 | 'argument' => [ |
818 | 'id' => 'numeric', |
819 | ], |
820 | ]; |
821 | $data['visitors']['language'] = [ |
822 | 'title' => t('Language'), |
823 | 'help' => t('The browser language.'), |
824 | 'field' => [ |
825 | 'id' => 'visitors_language', |
826 | ], |
827 | 'filter' => [ |
828 | 'id' => 'string', |
829 | ], |
830 | 'argument' => [ |
831 | 'id' => 'string', |
832 | ], |
833 | ]; |
834 | $data['visitors']['location_continent'] = [ |
835 | 'title' => t('Continent'), |
836 | 'help' => t('The location continent.'), |
837 | 'field' => [ |
838 | 'id' => 'visitors_continent', |
839 | ], |
840 | 'filter' => [ |
841 | 'id' => 'string', |
842 | ], |
843 | 'argument' => [ |
844 | 'id' => 'string', |
845 | ], |
846 | ]; |
847 | $data['visitors']['location_country'] = [ |
848 | 'title' => t('Country'), |
849 | 'help' => t('The location country.'), |
850 | 'field' => [ |
851 | 'id' => 'visitors_country', |
852 | ], |
853 | 'filter' => [ |
854 | 'id' => 'string', |
855 | ], |
856 | 'argument' => [ |
857 | 'id' => 'string', |
858 | ], |
859 | ]; |
860 | |
861 | $data['visitors']['pf_network'] = [ |
862 | 'title' => t('Network'), |
863 | 'help' => t('Network performance.'), |
864 | 'field' => [ |
865 | 'id' => 'numeric', |
866 | ], |
867 | 'sort' => [ |
868 | 'id' => 'standard', |
869 | ], |
870 | 'filter' => [ |
871 | 'id' => 'numeric', |
872 | ], |
873 | 'argument' => [ |
874 | 'id' => 'numeric', |
875 | ], |
876 | ]; |
877 | $data['visitors']['pf_server'] = [ |
878 | 'title' => t('Server'), |
879 | 'help' => t('Server performance.'), |
880 | 'field' => [ |
881 | 'id' => 'numeric', |
882 | ], |
883 | 'sort' => [ |
884 | 'id' => 'standard', |
885 | ], |
886 | 'filter' => [ |
887 | 'id' => 'numeric', |
888 | ], |
889 | 'argument' => [ |
890 | 'id' => 'numeric', |
891 | ], |
892 | ]; |
893 | $data['visitors']['pf_transfer'] = [ |
894 | 'title' => t('Transfer'), |
895 | 'help' => t('Transfer performance.'), |
896 | 'field' => [ |
897 | 'id' => 'numeric', |
898 | ], |
899 | 'sort' => [ |
900 | 'id' => 'standard', |
901 | ], |
902 | 'filter' => [ |
903 | 'id' => 'numeric', |
904 | ], |
905 | 'argument' => [ |
906 | 'id' => 'numeric', |
907 | ], |
908 | ]; |
909 | $data['visitors']['pf_dom_processing'] = [ |
910 | 'title' => t('DOM Processing'), |
911 | 'help' => t('DOM Processing performance.'), |
912 | 'field' => [ |
913 | 'id' => 'numeric', |
914 | ], |
915 | 'sort' => [ |
916 | 'id' => 'standard', |
917 | ], |
918 | 'filter' => [ |
919 | 'id' => 'numeric', |
920 | ], |
921 | 'argument' => [ |
922 | 'id' => 'numeric', |
923 | ], |
924 | ]; |
925 | $data['visitors']['pf_dom_complete'] = [ |
926 | 'title' => t('DOM Complete'), |
927 | 'help' => t('DOM Complete performance.'), |
928 | 'field' => [ |
929 | 'id' => 'numeric', |
930 | ], |
931 | 'sort' => [ |
932 | 'id' => 'standard', |
933 | ], |
934 | 'filter' => [ |
935 | 'id' => 'numeric', |
936 | ], |
937 | 'argument' => [ |
938 | 'id' => 'numeric', |
939 | ], |
940 | ]; |
941 | $data['visitors']['pf_on_load'] = [ |
942 | 'title' => t('On Load'), |
943 | 'help' => t('On Load performance.'), |
944 | 'field' => [ |
945 | 'id' => 'numeric', |
946 | ], |
947 | 'sort' => [ |
948 | 'id' => 'standard', |
949 | ], |
950 | 'filter' => [ |
951 | 'id' => 'numeric', |
952 | ], |
953 | 'argument' => [ |
954 | 'id' => 'numeric', |
955 | ], |
956 | ]; |
957 | $data['visitors']['pf_total'] = [ |
958 | 'title' => t('Total'), |
959 | 'help' => t('Total performance.'), |
960 | 'field' => [ |
961 | 'id' => 'numeric', |
962 | ], |
963 | 'sort' => [ |
964 | 'id' => 'standard', |
965 | ], |
966 | 'filter' => [ |
967 | 'id' => 'numeric', |
968 | ], |
969 | 'argument' => [ |
970 | 'id' => 'numeric', |
971 | ], |
972 | ]; |
973 | |
974 | $data['visitors']['visitors_display_link'] = [ |
975 | 'title' => t('Link to Visitors display'), |
976 | 'help' => t('Displays a link to a non-path-based display of this view while keeping the filter criteria, sort criteria, pager settings and contextual filters.'), |
977 | 'area' => [ |
978 | 'id' => 'visitors_display_link', |
979 | ], |
980 | ]; |
981 | |
982 | return $data; |
983 | } |
984 | |
985 | /** |
986 | * Implements hook_token_info(). |
987 | */ |
988 | function visitors_token_info() { |
989 | $entity['total-count'] = [ |
990 | 'name' => t("Number of views"), |
991 | 'description' => t("The number of visitors who have read the node."), |
992 | ]; |
993 | $entity['day-count'] = [ |
994 | 'name' => t("Views today"), |
995 | 'description' => t("The number of visitors who have read the node today."), |
996 | ]; |
997 | $entity['last-view'] = [ |
998 | 'name' => t("Last view"), |
999 | 'description' => t("The date on which a visitor last read the node."), |
1000 | 'type' => 'date', |
1001 | ]; |
1002 | |
1003 | $token = [ |
1004 | 'tokens' => [], |
1005 | ]; |
1006 | $entity_types = \Drupal::config('visitors.config') |
1007 | ->get('counter.entity_types') ?? []; |
1008 | foreach ($entity_types as $entity_type) { |
1009 | $token['tokens'][$entity_type] = $entity; |
1010 | } |
1011 | |
1012 | return $token; |
1013 | } |
1014 | |
1015 | /** |
1016 | * Implements hook_tokens(). |
1017 | */ |
1018 | function visitors_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) { |
1019 | $token_service = \Drupal::token(); |
1020 | $entity_types = \Drupal::config('visitors.config') |
1021 | ->get('counter.entity_types') ?? []; |
1022 | $replacements = []; |
1023 | |
1024 | if (!in_array($type, $entity_types) || empty($data[$type])) { |
1025 | return $replacements; |
1026 | } |
1027 | $entity = $data[$type]; |
1028 | |
1029 | /** @var \Drupal\visitors\VisitorsCounterInterface $counter_storage */ |
1030 | $counter_storage = \Drupal::service('visitors.counter'); |
1031 | |
1032 | $entity_id = $entity->id(); |
1033 | $entity_view = $counter_storage->fetchView($type, $entity_id); |
1034 | foreach ($tokens as $name => $original) { |
1035 | if ($name == 'total-count') { |
1036 | $replacements[$original] = $entity_view ? $entity_view->getTotalCount() : 0; |
1037 | } |
1038 | elseif ($name == 'day-count') { |
1039 | $replacements[$original] = $entity_view ? $entity_view->getDayCount() : 0; |
1040 | } |
1041 | elseif ($name == 'last-view') { |
1042 | $replacements[$original] = $entity_view ? \Drupal::service('date.formatter')->format($entity_view->getTimestamp()) : t('never'); |
1043 | } |
1044 | } |
1045 | |
1046 | if ($created_tokens = $token_service->findWithPrefix($tokens, 'last-view')) { |
1047 | $replacements += $token_service->generate('date', $created_tokens, ['date' => $entity_view ? $entity_view->getTimestamp() : 0], $options, $bubbleable_metadata); |
1048 | } |
1049 | |
1050 | return $replacements; |
1051 | } |