Passed
Pull Request — master (#58)
by Serhii
01:33
created

Detector::initDetector()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 6
rs 10
1
<?php
2
/**
3
 * @author Serhii Nekhaienko <[email protected]>
4
 * @license GPL
5
 * @copyright Serhii Nekhaienko &copy 2018
6
 * @version 4.0.0
7
 * @project endorphin-studio/browser-detector
8
 */
9
10
namespace EndorphinStudio\Detector;
11
12
use EndorphinStudio\Detector\Data\Result;
13
use EndorphinStudio\Detector\Exception\StorageException;
14
use EndorphinStudio\Detector\Storage\StorageInterface;
15
use EndorphinStudio\Detector\Storage\YamlStorage;
16
use RuntimeException;
17
use Symfony\Component\HttpFoundation\Request;
18
19
/**
20
 * Class Detector
21
 * Detect OS, Device, Browser, Robot
22
 * @package EndorphinStudio\Detector
23
 */
24
class Detector
25
{
26
    private const DATA_PACKAGE = 'endorphin-studio/browser-detector-data-yaml';
27
28
    /**
29
     * @var array Array of options
30
     */
31
    protected $options = [
32
        'dataProvider' => YamlStorage::class,
33
        'dataDirectory' => 'auto',
34
        'cacheDirectory' => 'auto',
35
        'format' => 'yaml'
36
    ];
37
38
    private $version = '6.0.3';
39
40
    /**
41
     * @var StorageInterface
42
     */
43
    private $dataProvider;
44
45
    /**
46
     * @var Result Result object
47
     */
48
    private $resultObject;
49
50
    /**
51
     * @var string $ua User Agent
52
     */
53
    private $ua;
54
55
    /**
56
     * @var array
57
     */
58
    private $detectors;
59
60
    /**
61
     * Detector constructor.
62
     * Options:
63
     * 'dataProvider' => '\\EndorphinStudio\\Detector\\Storage\\YamlStorage',
64
     * 'dataDirectory' => 'auto',
65
     * 'cacheDirectory' => 'auto',
66
     * 'format' => 'yaml'
67
     * @param array $options Array of options
68
     * @throws StorageException
69
     * @SuppressWarnings(PHPMD.StaticAccess)
70
     */
71
    public function __construct(array $options = [])
72
    {
73
        $this->options = array_merge_recursive($options, $this->options);
74
75
        $this->init();
76
        $this->detectors = [];
77
        Tools::setWindowsConfig($this->dataProvider->getConfig()['windows']);
78
        foreach (['os', 'device', 'browser'] as $detectionType) {
79
            $this->initDetector($detectionType);
80
        }
81
    }
82
83
    /**
84
     * Initialisation method
85
     * @throws StorageException
86
     * @throws RuntimeException
87
     */
88
    protected function init(): void
89
    {
90
        $this->setDataProvider($this->createDataProvider());
91
        $this->dataProvider->setDataDirectory($this->findDataDirectory());
92
        $this->callMethod($this->dataProvider, 'setCacheDirectory', $this->findCacheDirectory());
93
        $this->callMethod($this->dataProvider, 'setCacheEnabled', true);
94
    }
95
96
    private function createDataProvider()
97
    {
98
        if (class_exists($this->options['dataProvider'])) {
99
            return new $this->options['dataProvider']();
100
        }
101
        throw new RuntimeException('Data Provider class isn\'t exist');
102
    }
103
104
    /**
105
     * @return string
106
     * @throws StorageException
107
     */
108
    private function findDataDirectory(): string
109
    {
110
        $dataDirectory = $this->options['dataDirectory'];
111
        if ($this->options['dataDirectory'] === 'auto') {
112
            $dataDirectory = sprintf('%s/data', $this->getPackagePath(self::DATA_PACKAGE));
113
        }
114
        if (is_dir($dataDirectory)) {
115
            return $dataDirectory;
116
        }
117
        throw new StorageException(sprintf(StorageException::DIRECTORY_NOT_FOUND, $dataDirectory));
118
    }
119
120
    private function getPackagePath(string $package): string
121
    {
122
        /**
123
         * If running from vendor directory
124
         */
125
        if (strpos(dirname(__FILE__, 3), 'endorphin-studio') !== false) {
126
            $vendorDir = dirname(__FILE__, 4);
127
        } else {
128
            $vendorDir = dirname(__FILE__, 2) . '/vendor';
129
        }
130
        return sprintf('%s/%s', $vendorDir, $package);
131
    }
132
133
    protected function callMethod($object, string $methodName, ...$arguments): void
134
    {
135
        if (method_exists($object, $methodName)) {
136
            $object->$methodName($arguments);
137
        }
138
    }
139
140
    /**
141
     * @return string
142
     * @throws StorageException
143
     */
144
    private function findCacheDirectory(): string
145
    {
146
        $cacheDirectory = $this->options['cacheDirectory'];
147
        if ($this->options['cacheDirectory'] === 'auto') {
148
            $cacheDirectory = sprintf('%s/var/cache', dirname(__FILE__, 2));
149
        }
150
        if (is_dir($cacheDirectory)) {
151
            return $cacheDirectory;
152
        }
153
        throw new StorageException(sprintf(StorageException::DIRECTORY_NOT_FOUND, $cacheDirectory));
154
    }
155
156
    private function initDetector(string $type): void
157
    {
158
        $className = sprintf('\\EndorphinStudio\\Detector\\Detection\\%s', ucfirst(sprintf('%sDetector', $type)));
159
        if (class_exists($className)) {
160
            $this->detectors[$type] = new $className();
161
            $this->detectors[$type]->init($this);
162
        }
163
    }
164
165
    public function getVersion(): string
166
    {
167
        return $this->version;
168
    }
169
170
    /**
171
     * Get storage provider
172
     * @return StorageInterface
173
     */
174
    public function getDataProvider(): StorageInterface
175
    {
176
        return $this->dataProvider;
177
    }
178
179
    /**
180
     * Set data provider
181
     * @param StorageInterface $dataProvider
182
     */
183
    public function setDataProvider(StorageInterface $dataProvider): void
184
    {
185
        $this->dataProvider = $dataProvider;
186
    }
187
188
    /**
189
     * Get result object
190
     * @return Result Result object
191
     */
192
    public function getResultObject(): Result
193
    {
194
        return $this->resultObject;
195
    }
196
197
    /**
198
     * @return string
199
     */
200
    public function getUserAgent(): string
201
    {
202
        return $this->ua;
203
    }
204
205
    /**
206
     * Analyse User Agent String
207
     * @param string $ua
208
     * @return Result
209
     * @SuppressWarnings(PHPMD.StaticAccess)
210
     */
211
    public function analyse(string $ua = 'ua'): Result
212
    {
213
        $request = Request::createFromGlobals();
214
        $this->ua = $ua === 'ua' ? $request->server->get('HTTP_USER_AGENT') : $ua;
215
        $this->resultObject = new Result($this->ua, $this);
216
        foreach ($this->detectors as $detectionType => $detector) {
217
            $detector->detect();
218
        }
219
        return $this->resultObject;
220
    }
221
222
    /**
223
     * Get list of patterns from config
224
     * @param $list
225
     * @param $type
226
     * @return array
227
     */
228
    public function getPatternList($list, $type): array
229
    {
230
        return array_key_exists($type, $list) ? $list[$type] : [];
231
    }
232
}
233