Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
42 / 42
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
DeviceService
100.00% covered (success)
100.00%
42 / 42
100.00% covered (success)
100.00%
7 / 7
10
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getUniqueUserAgents
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 getDeviceDetector
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 bulkUpdate
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 doDeviceFields
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setDeviceFields
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
3
 hasLibrary
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace Drupal\visitors\Service;
4
5use DeviceDetector\ClientHints;
6use DeviceDetector\DeviceDetector;
7use Drupal\Core\Database\Connection;
8use Drupal\visitors\VisitorsDeviceInterface;
9
10/**
11 * Detects the device type.
12 *
13 * @package Drupal\visitors\Service
14 */
15class DeviceService implements VisitorsDeviceInterface {
16
17  /**
18   * The database connection.
19   *
20   * @var \Drupal\Core\Database\Connection
21   */
22  protected $database;
23
24  /**
25   * DeviceService constructor.
26   *
27   * @param \Drupal\Core\Database\Connection $database
28   *   The database connection.
29   */
30  public function __construct(Connection $database) {
31    $this->database = $database;
32  }
33
34  /**
35   * {@inheritdoc}
36   */
37  public function getUniqueUserAgents(): array {
38    $results = $this->database->select('visitors', 'v')
39      ->fields('v', ['visitors_user_agent'])
40      ->condition('bot', NULL, 'IS NULL')
41      ->distinct()
42      ->orderBy('visitors_user_agent')
43      ->execute()
44      ->fetchAll(\PDO::FETCH_COLUMN, 0);
45
46    return $results;
47  }
48
49  /**
50   * Gets the device detector.
51   *
52   * @param string $user_agent
53   *   The user agent string.
54   * @param array $server
55   *   The server array.
56   *
57   * @return \DeviceDetector\DeviceDetector
58   *   The device detector.
59   */
60  protected function getDeviceDetector(string $user_agent, ?array $server = NULL): DeviceDetector {
61    $client_hints = NULL;
62    if ($server) {
63      $client_hints = ClientHints::factory($server);
64    }
65
66    $dd = new DeviceDetector($user_agent, $client_hints);
67    $dd->parse();
68
69    return $dd;
70  }
71
72  /**
73   * {@inheritdoc}
74   */
75  public function bulkUpdate(string $user_agent): int {
76    $dd = new DeviceDetector($user_agent);
77    $dd->parse();
78    $fields = [];
79
80    $this->setDeviceFields($fields, $dd);
81
82    $count = $this->database->update('visitors')
83      ->fields($fields)
84      ->condition('visitors_user_agent', $user_agent)
85      ->condition('bot', NULL, 'IS NULL')
86      ->execute();
87
88    return $count;
89  }
90
91  /**
92   * {@inheritdoc}
93   */
94  public function doDeviceFields(array &$fields, string $user_agent, ?array $server = NULL): void {
95    $dd = $this->getDeviceDetector($user_agent, $server);
96    $this->setDeviceFields($fields, $dd);
97
98  }
99
100  /**
101   * Assigns the device fields to the fields array.
102   *
103   * @param array $fields
104   *   The fields array.
105   * @param \DeviceDetector\DeviceDetector $dd
106   *   The DeviceDetector object.
107   */
108  protected function setDeviceFields(&$fields, DeviceDetector $dd): void {
109    $fields['config_browser_engine'] = $dd->getClient('engine');
110    $fields['config_browser_name'] = $dd->getClient('short_name');
111    $fields['config_browser_version'] = $dd->getClient('version');
112    $fields['config_client_type'] = $dd->getClient('type');
113    $fields['config_device_brand'] = $dd->getBrandName();
114    $fields['config_device_model'] = $dd->getModel();
115    $fields['config_device_type'] = $dd->getDeviceName();
116    $fields['config_os'] = $dd->getOs('short_name');
117    $fields['config_os_version'] = $dd->getOs('version');
118    $fields['bot'] = (int) $dd->isBot();
119
120    $nullable = [
121      'config_browser_engine',
122      'config_browser_name',
123      'config_browser_version',
124      'config_client_type',
125      'config_os',
126      'config_os_version',
127    ];
128    foreach ($nullable as $field) {
129      $value = strtolower($fields[$field]);
130      if ($value == 'unk') {
131        $fields[$field] = NULL;
132      }
133    }
134  }
135
136  /**
137   * {@inheritdoc}
138   */
139  public function hasLibrary($class_name = 'DeviceDetector\ClientHints'): bool {
140    return class_exists($class_name);
141  }
142
143}