Browscap   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 189
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 20
c 2
b 0
f 1
lcom 1
cbo 8
dl 0
loc 189
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getParser() 0 8 2
A setParser() 0 6 1
A getFormatter() 0 8 2
A setFormatter() 0 6 1
A getAutoUpdateProbability() 0 4 1
A setAutoUpdateProbability() 0 6 1
A getBrowser() 0 14 2
A autoUpdate() 0 9 3
B update() 0 33 6
A __invoke() 0 5 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Crossjoin\Browscap;
5
6
use Crossjoin\Browscap\Exception\ParserConfigurationException;
7
use Crossjoin\Browscap\Exception\ParserRuntimeException;
8
use Crossjoin\Browscap\Formatter\FormatterInterface;
9
use Crossjoin\Browscap\Formatter\PhpGetBrowser;
10
use Crossjoin\Browscap\Parser\ParserInterface;
11
use Crossjoin\Browscap\Parser\Sqlite\Parser;
12
13
/**
14
 * Class Browscap
15
 *
16
 * @package Crossjoin\Browscap
17
 * @author Christoph Ziegenberg <[email protected]>
18
 * @link https://github.com/crossjoin/browscap
19
 */
20
class Browscap
21
{
22
    const VERSION = '3.0.0';
23
24
    /**
25
     * @var ParserInterface
26
     */
27
    protected $parser;
28
29
    /**
30
     * @var FormatterInterface
31
     */
32
    protected $formatter;
33
34
    /**
35
     * Update probability percentage, so a value of 1 would check for updates in
36
     * 1% of the requests. A value of 0 disables automatic updates (default).
37
     *
38
     * @var int
39
     */
40
    protected $autoUpdateProbability = 0;
41
42
    /**
43
     * @return ParserInterface
44
     * @throws ParserConfigurationException
45
     */
46
    public function getParser() : ParserInterface
47
    {
48
        if ($this->parser === null) {
49
            $this->setParser(new Parser());
50
        }
51
52
        return $this->parser;
53
    }
54
55
    /**
56
     * @param ParserInterface $parser
57
     *
58
     * @return Browscap
59
     */
60
    public function setParser(ParserInterface $parser) : Browscap
61
    {
62
        $this->parser = $parser;
63
64
        return $this;
65
    }
66
67
    /**
68
     * @return FormatterInterface
69
     */
70
    public function getFormatter() : FormatterInterface
71
    {
72
        if ($this->formatter === null) {
73
            $this->setFormatter(new PhpGetBrowser());
74
        }
75
76
        return $this->formatter;
77
    }
78
79
    /**
80
     * @param FormatterInterface $formatter
81
     *
82
     * @return Browscap
83
     */
84
    public function setFormatter(FormatterInterface $formatter) : Browscap
85
    {
86
        $this->formatter = $formatter;
87
88
        return $this;
89
    }
90
91
    /**
92
     * @return int
93
     */
94
    public function getAutoUpdateProbability() : int
95
    {
96
        return $this->autoUpdateProbability;
97
    }
98
99
    /**
100
     * @param int $autoUpdateProbability
101
     *
102
     * @return Browscap
103
     */
104
    public function setAutoUpdateProbability(int $autoUpdateProbability) : Browscap
105
    {
106
        $this->autoUpdateProbability = $autoUpdateProbability;
107
108
        return $this;
109
    }
110
111
    /**
112
     * @param string|null $userAgent
113
     *
114
     * @return mixed
115
     * @throws ParserConfigurationException
116
     * @throws ParserRuntimeException
117
     */
118
    public function getBrowser(string $userAgent = null)
119
    {
120
        // Check if an automatic update is required
121
        $this->autoUpdate();
122
123
        // If no user agent is set, try to get it from the HTTP headers
124
        if ($userAgent === null) {
125
            $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
126
        }
127
128
        // Get rwa Browscap data and return a formatted version, using the set Formatter
129
        $browscapData = $this->getParser()->getReader()->getBrowser($userAgent);
130
        return $this->getFormatter()->format($browscapData);
131
    }
132
133
    /**
134
     * @return Browscap
135
     * @throws ParserConfigurationException
136
     * @throws ParserRuntimeException
137
     */
138
    protected function autoUpdate() : Browscap
139
    {
140
        $updateProbability = $this->getAutoUpdateProbability();
141
        if ($updateProbability >= random_int(1, 100) || $this->getParser()->getReader()->isUpdateRequired()) {
142
            $this->update();
143
        }
144
145
        return $this;
146
    }
147
148
    /**
149
     * Updates Browscap data. Returns a boolean indicating if an update has been done or
150
     * not (because not required). If the option 'forceUpdate' is used, the update is always
151
     * done, no matter if required or not.
152
     *
153
     * @param bool $forceUpdate
154
     *
155
     * @return bool
156
     * @throws ParserConfigurationException
157
     * @throws ParserRuntimeException
158
     */
159
    public function update(bool $forceUpdate = false) : bool
160
    {
161
        $parser = $this->getParser();
162
163
        // Check if an update is required, either because it's forced, or the source is newer
164
        $updateRequired = $forceUpdate;
165
        if ($updateRequired === false) {
166
            $reader = $parser->getReader();
167
            $source = $parser->getSource();
168
            $updateRequired = (
169
                $reader->isUpdateRequired() ||
170
                $reader->getType() !== $source->getType() ||
171
                $reader->getVersion() < $source->getVersion()
172
            );
173
        }
174
175
        // Generate ne parser data, if an update is required
176
        if ($updateRequired === true) {
177
            $parser->getWriter()->generate();
178
179
            // Re-initiate the reader and check if the update is still required,
180
            // if so, there's something wrong with the generation of the data.
181
            $reader = $parser->getReader(true);
182
            if ($reader->isUpdateRequired() === true) {
183
                throw new ParserRuntimeException(
184
                    'There is something wrong with the parser. The data have been re-generated without errors, ' .
185
                    'but the reader still requires an update of the data...'
186
                );
187
            }
188
        }
189
190
        return $updateRequired;
191
    }
192
193
    /**
194
     * Use the class instance as a function that exactly behaves like PHP get_browser().
195
     *
196
     * @param string $userAgent
197
     * @param bool $returnArray
198
     *
199
     * @return mixed
200
     * @throws ParserConfigurationException
201
     * @throws ParserRuntimeException
202
     */
203
    public function __invoke(string $userAgent, bool $returnArray = false)
204
    {
205
        $this->setFormatter(new PhpGetBrowser($returnArray));
206
        return $this->getBrowser($userAgent);
207
    }
208
}
209