Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
87 / 87
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
ReportService
100.00% covered (success)
100.00%
87 / 87
100.00% covered (success)
100.00%
5 / 5
13
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 referer
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
3
 setReferrersCondition
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
4
 hitDetails
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
1 / 1
4
 addDateFilter
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace Drupal\visitors\Service;
4
5use Drupal\Core\Config\ConfigFactoryInterface;
6use Drupal\Core\Database\Connection;
7use Drupal\Core\Datetime\DateFormatterInterface;
8use Drupal\Core\Entity\EntityTypeManagerInterface;
9use Drupal\Core\Extension\ModuleHandlerInterface;
10use Drupal\Core\Render\RendererInterface;
11use Drupal\Core\StringTranslation\StringTranslationTrait;
12use Drupal\visitors\VisitorsReportInterface;
13use Symfony\Component\HttpFoundation\RequestStack;
14use Drupal\visitors\VisitorsDateRangeInterface;
15
16/**
17 * Report data.
18 *
19 * @package visitors
20 */
21class ReportService implements VisitorsReportInterface {
22  use StringTranslationTrait;
23
24  /**
25   * The database service.
26   *
27   * @var \Drupal\Core\Database\Connection
28   */
29  protected $database;
30
31  /**
32   * Items per page.
33   *
34   * @var int
35   */
36  protected $itemsPerPage;
37
38  /**
39   * The page number.
40   *
41   * @var int
42   */
43  protected $page;
44
45  /**
46   * The first day of week.
47   *
48   * @var int
49   */
50  protected $firstDay;
51
52  /**
53   * The renderer service.
54   *
55   * @var \Drupal\Core\Render\RendererInterface
56   */
57  protected $renderer;
58
59  /**
60   * The date service.
61   *
62   * @var \Drupal\Core\Datetime\DateFormatterInterface
63   */
64  protected $date;
65
66  /**
67   * The entity type manager service.
68   *
69   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
70   */
71  protected $entityTypeManager;
72
73  /**
74   * The module handler service.
75   *
76   * @var \Drupal\Core\Extension\ModuleHandlerInterface
77   */
78  protected $moduleHandler;
79
80  /**
81   * The date range service.
82   *
83   * @var \Drupal\visitors\VisitorsDateRangeInterface
84   */
85  protected $dateRange;
86
87  /**
88   * Database Service Object.
89   *
90   * @param \Drupal\Core\Database\Connection $database
91   *   The database service.
92   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
93   *   The config factory service.
94   * @param \Symfony\Component\HttpFoundation\RequestStack $stack
95   *   The request stack service.
96   * @param \Drupal\Core\Render\RendererInterface $renderer
97   *   The renderer service.
98   * @param \Drupal\Core\Datetime\DateFormatterInterface $date
99   *   The date service.
100   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
101   *   The entity type manager service.
102   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
103   *   The module handler service.
104   * @param \Drupal\visitors\VisitorsDateRangeInterface $date_range
105   *   The date range service.
106   */
107  public function __construct(
108    Connection $database,
109    ConfigFactoryInterface $config_factory,
110    RequestStack $stack,
111    RendererInterface $renderer,
112    DateFormatterInterface $date,
113    EntityTypeManagerInterface $entity_type_manager,
114    ModuleHandlerInterface $module_handler,
115    VisitorsDateRangeInterface $date_range,
116  ) {
117
118    $this->database = $database;
119    $this->firstDay = $config_factory->get('system.date')->get('first_day') ?? 0;
120    $this->itemsPerPage = $config_factory->get('visitors.config')->get('items_per_page') ?? 10;
121    $this->page = $stack->getCurrentRequest()->query->get('page') ?? 0;
122    $this->renderer = $renderer;
123    $this->date = $date;
124    $this->entityTypeManager = $entity_type_manager;
125    $this->moduleHandler = $module_handler;
126    $this->dateRange = $date_range;
127  }
128
129  /**
130   * {@inheritdoc}
131   */
132  public function referer(array $header) {
133    /** @var \Drupal\Core\Database\Query\SelectInterface $query */
134    $query = $this->database->select('visitors', 'v')
135      ->extend('Drupal\Core\Database\Query\PagerSelectExtender')
136      ->extend('Drupal\Core\Database\Query\TableSortExtender');
137    $query->condition('bot', 1, '<>');
138    $query->addExpression('COUNT(*)', 'count');
139    $query->fields('v', ['visitors_referer']);
140    $this->addDateFilter($query);
141    $query = $this->setReferrersCondition($query);
142    $query->condition('visitors_referer', '', '<>');
143    $query->groupBy('visitors_referer');
144    $query->orderByHeader($header);
145    $query->limit($this->itemsPerPage);
146
147    $count_query = $this->database->select('visitors', 'v');
148    $count_query->condition('bot', 1, '<>');
149    $count_query->condition('visitors_referer', '', '<>');
150    $count_query->addExpression('COUNT(DISTINCT visitors_referer)');
151    $this->addDateFilter($count_query);
152    $count_query = $this->setReferrersCondition($count_query);
153    $query->setCountQuery($count_query);
154    $results = $query->execute();
155
156    $rows = [];
157    $i = $this->page * $this->itemsPerPage;
158    foreach ($results as $data) {
159
160      $rows[] = [
161        empty($data->visitors_referer) ? $this->t('No Referer') : $data->visitors_referer,
162        $data->count,
163      ];
164    }
165    return $rows;
166  }
167
168  /**
169   * Build sql query from referer type value.
170   */
171  protected function setReferrersCondition($query) {
172    switch ($_SESSION['referer_type']) {
173      case VisitorsReportInterface::REFERER_TYPE_INTERNAL_PAGES:
174        $query->condition(
175          'visitors_referer',
176          sprintf('%%%s%%', $_SERVER['HTTP_HOST']),
177          'LIKE'
178        );
179        $query->condition('visitors_referer', '', '<>');
180        break;
181
182      case VisitorsReportInterface::REFERER_TYPE_EXTERNAL_PAGES:
183        $query->condition(
184          'visitors_referer',
185          sprintf('%%%s%%', $_SERVER['HTTP_HOST']),
186          'NOT LIKE'
187        );
188        break;
189
190      default:
191        break;
192    }
193
194    return $query;
195  }
196
197  /**
198   * {@inheritdoc}
199   */
200  public function hitDetails($hit_id) {
201    $query = $this->database->select('visitors', 'v');
202
203    $query->fields('v');
204    $query->condition('v.visitors_id', (int) $hit_id);
205    /** @var object|false $hit_details */
206    $hit_details = $query->execute()->fetch();
207
208    $rows = [];
209
210    if ($hit_details) {
211      $url     = urldecode($hit_details->visitors_url);
212      $referer = $hit_details->visitors_referer;
213      $date    = $this->date->format($hit_details->visitors_date_time, 'large');
214      $ip      = $hit_details->visitors_ip;
215
216      $array = [
217        $this->t('URL')->render()        => $url,
218        $this->t('Title')->render()      => ($hit_details->visitors_title ?? ''),
219        $this->t('Referer')->render()    => $referer,
220        $this->t('Date')->render()       => $date,
221        $this->t('Visitor')->render()    => $hit_details->visitor_id,
222        $this->t('IP')->render()         => $ip,
223        $this->t('User Agent')->render() => ($hit_details->visitors_user_agent ?? ''),
224        $this->t('Country')->render()    => ($hit_details->location_country ?? ''),
225      ];
226
227      if ($this->moduleHandler->moduleExists('visitors_geoip')) {
228        $geoip_data_array = [
229          $this->t('Region')->render()          => ($hit_details->location_region ?? ''),
230          $this->t('City')->render()            => ($hit_details->location_city ?? ''),
231          $this->t('Latitude')->render()        => ($hit_details->location_latitude ?? ''),
232          $this->t('Longitude')->render()       => ($hit_details->location_longitude ?? ''),
233        ];
234        $array = array_merge($array, $geoip_data_array);
235      }
236
237      foreach ($array as $key => $value) {
238        $rows[] = [['data' => $key, 'header' => TRUE], $value];
239      }
240    }
241
242    return $rows;
243  }
244
245  /**
246   * Add date filter to the query.
247   *
248   * @param \Drupal\Core\Database\Query\SelectInterface $query
249   *   The query object.
250   */
251  protected function addDateFilter(&$query) {
252
253    $from = $this->dateRange->getStartTimestamp();
254    $to   = $this->dateRange->getEndTimestamp();
255
256    $query->condition('visitors_date_time', [$from, $to], 'BETWEEN');
257  }
258
259}