Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
64 / 64
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
PageAttachmentsService
100.00% covered (success)
100.00%
64 / 64
100.00% covered (success)
100.00%
6 / 6
16
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 pageAttachments
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 attachMetaData
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 attachToolbar
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 attachEntityCounter
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
6
 processEvent
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\visitors\Service;
6
7use Drupal\Core\Access\AccessResult;
8use Drupal\Core\Config\ConfigFactoryInterface;
9use Drupal\Core\Extension\ModuleHandlerInterface;
10use Drupal\Core\Routing\RouteMatchInterface;
11use Drupal\Core\Session\AccountInterface;
12use Drupal\Core\Utility\Error;
13use Drupal\visitors\VisitorsEventPluginManager;
14use Drupal\visitors\VisitorsPageAttachmentsInterface;
15use Drupal\visitors\VisitorsVisibilityInterface;
16use Psr\Log\LoggerInterface;
17use Symfony\Component\HttpFoundation\RequestStack;
18
19/**
20 * Visitors Page Attachments Service.
21 */
22class PageAttachmentsService implements VisitorsPageAttachmentsInterface {
23
24  /**
25   * The config factory.
26   *
27   * @var \Drupal\Core\Config\ConfigFactoryInterface
28   */
29  protected $configFactory;
30
31  /**
32   * The current user service.
33   *
34   * @var \Drupal\Core\Session\AccountInterface
35   */
36  protected $currentUser;
37
38  /**
39   * The module handler service.
40   *
41   * @var \Drupal\Core\Extension\ModuleHandlerInterface
42   */
43  protected $moduleHandler;
44
45  /**
46   * The route match service.
47   *
48   * @var \Drupal\Core\Routing\ResettableStackedRouteMatchInterface
49   */
50  protected $routeMatch;
51
52  /**
53   * The request stack service.
54   *
55   * @var \Symfony\Component\HttpFoundation\RequestStack
56   */
57  protected $requestStack;
58
59  /**
60   * The visitors visibility service.
61   *
62   * @var \Drupal\visitors\VisitorsVisibilityInterface
63   */
64  protected $visibilityService;
65
66  /**
67   * The logger service.
68   *
69   * @var \Psr\Log\LoggerInterface
70   */
71  protected $logger;
72
73  /**
74   * The visitors event plugin manager.
75   *
76   * @var \Drupal\visitors\VisitorsEventPluginManager
77   */
78  protected $eventPluginManager;
79
80  /**
81   * Constructs a new Page Attachments Service.
82   *
83   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
84   *   The config factory.
85   * @param \Drupal\Core\Session\AccountInterface $current_user
86   *   The current user service.
87   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
88   *   The module handler service.
89   * @param \Drupal\Core\Routing\ResettableStackedRouteMatchInterface $route_match
90   *   The route match service.
91   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
92   *   The request stack service.
93   * @param \Drupal\visitors\VisitorsVisibilityInterface $visibility_service
94   *   The visitors visibility service.
95   * @param \Psr\Log\LoggerInterface $logger
96   *   The logger service.
97   * @param \Drupal\visitors\VisitorsEventPluginManager $event_plugin_manager
98   *   The visitors event plugin manager.
99   */
100  public function __construct(
101    ConfigFactoryInterface $config_factory,
102    AccountInterface $current_user,
103    ModuleHandlerInterface $module_handler,
104    RouteMatchInterface $route_match,
105    RequestStack $request_stack,
106    VisitorsVisibilityInterface $visibility_service,
107    LoggerInterface $logger,
108    VisitorsEventPluginManager $event_plugin_manager,
109  ) {
110    $this->configFactory = $config_factory;
111    $this->currentUser = $current_user;
112    $this->moduleHandler = $module_handler;
113    $this->routeMatch = $route_match;
114    $this->requestStack = $request_stack;
115    $this->visibilityService = $visibility_service;
116    $this->logger = $logger;
117    $this->eventPluginManager = $event_plugin_manager;
118  }
119
120  /**
121   * {@inheritdoc}
122   */
123  public function pageAttachments(array &$page) {
124    $page['#cache']['tags'][] = 'user:' . $this->currentUser->id();
125    $page['#cache']['contexts'][] = 'user';
126    $page['#cache']['tags'][] = 'config:visitors.settings';
127
128    $this->attachToolbar($page);
129
130    try {
131      if ($this->visibilityService->isVisible()) {
132        $this->attachMetaData($page);
133        $this->attachEntityCounter($page);
134        $this->processEvent($page);
135      }
136    }
137    catch (\Exception $e) {
138      Error::logException($this->logger, $e);
139    }
140  }
141
142  /**
143   * Attach meta data to the page.
144   *
145   * @param array $page
146   *   The page attachments array.
147   */
148  protected function attachMetaData(array &$page): void {
149    $route = $this->routeMatch->getRouteName();
150    $request = $this->requestStack->getCurrentRequest();
151    $base_path = $request->getBasePath();
152    $module_path = $this->moduleHandler->getModule('visitors')->getPath();
153
154    $visitors = &$page['#attached']['drupalSettings']['visitors'];
155
156    $visitors['module'] = "$base_path/$module_path";
157    $visitors['route'] = $route;
158    $visitors['server'] = gethostname();
159    $page['#attached']['library'][] = 'visitors/visitors';
160
161  }
162
163  /**
164   * Visitors toolbar integration.
165   *
166   * @param array $page
167   *   The page attachments array.
168   */
169  protected function attachToolbar(array &$page): void {
170    $required_permissions = ['access visitors', 'access toolbar'];
171
172    $access = AccessResult::allowedIfHasPermissions($this->currentUser, $required_permissions);
173    if ($access->isAllowed()) {
174      $page['#attached']['library'][] = 'visitors/toolbar';
175    }
176  }
177
178  /**
179   * Attach entity counter to the page.
180   *
181   * @param array $page
182   *   The page attachments array.
183   */
184  protected function attachEntityCounter(array &$page): void {
185    $route = $this->routeMatch->getRouteName();
186    $route_array = explode('.', $route);
187    if (count($route_array) == 3 && $route_array[0] == 'entity' && $route_array[2] == 'canonical') {
188      $entity_type = $route_array[1];
189
190      $settings = $this->configFactory->get('visitors.settings');
191      $entity_types = $settings->get('counter.entity_types') ?? [];
192      if (!$settings->get('counter.enabled') || !in_array($entity_type, $entity_types)) {
193        return;
194      }
195
196      $entity_id = $this->routeMatch->getParameter($entity_type)->id();
197      $page['#attached']['drupalSettings']['visitors']['counter'] = "$entity_type:$entity_id";
198    }
199  }
200
201  /**
202   * Process visitor events.
203   *
204   * @param array $page
205   *   The page attachments array.
206   */
207  protected function processEvent(array &$page): void {
208    $route = $this->routeMatch->getRouteName();
209    $request = $this->requestStack->getCurrentRequest();
210
211    $path = $request->getPathInfo();
212    // $referrer_url = $request->headers->get('referer');
213    $context = [
214      'url' => $request->getUri(),
215      'path' => $path,
216      'route' => $route,
217      'uid' => $this->currentUser->id(),
218    ];
219
220    // Get all plugins sorted by weight.
221    $definitions = $this->eventPluginManager->getDefinitions();
222
223    uasort($definitions, function ($a, $b) {
224      return ($a['weight'] ?? 0) <=> ($b['weight'] ?? 0);
225    });
226
227    // Process each plugin until one returns an array.
228    foreach ($definitions as $plugin_id => $definition) {
229      $plugin = $this->eventPluginManager->createInstance($plugin_id);
230      $result = $plugin->process($context);
231
232      if ($result !== NULL) {
233        $page['#attached']['drupalSettings']['visitors']['event'] = [
234          'plugin' => $plugin->getPluginId(),
235          'event' => $result['event'],
236          'variables' => $result['variables'],
237        ];
238        return;
239      }
240    }
241  }
242
243}