GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#43)
by Martin
06:34
created

UdgerCom   C

Complexity

Total Complexity 41

Size/Duplication

Total Lines 252
Duplicated Lines 9.92 %

Coupling/Cohesion

Components 1
Dependencies 17

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 41
c 1
b 0
f 0
lcom 1
cbo 17
dl 25
loc 252
ccs 81
cts 81
cp 1
rs 6.6123

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getName() 0 4 1
A getComposerPackageName() 0 4 1
A getVersion() 0 4 1
C getResult() 9 70 15
A isBot() 8 8 3
A hydrateBot() 8 8 3
B hydrateBrowser() 0 10 5
A hydrateRenderingEngine() 0 6 3
A hydrateOperatingSystem() 0 6 3
A hydrateDevice() 0 6 3
B parse() 0 29 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like UdgerCom often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use UdgerCom, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace UserAgentParser\Provider\Http;
3
4
use GuzzleHttp\Client;
5
use GuzzleHttp\Psr7\Request;
6
use stdClass;
7
use UserAgentParser\Exception;
8
use UserAgentParser\Model;
9
10
/**
11
 *
12
 * @see https://udger.com/support/documentation/?doc=38
13
 *
14
 */
15
class UdgerCom extends AbstractHttpProvider
16
{
17
    protected $detectionCapabilities = [
18
19
        'browser' => [
20
            'name'    => true,
21
            'version' => true,
22
        ],
23
24
        'renderingEngine' => [
25
            'name'    => true,
26
            'version' => false,
27
        ],
28
29
        'operatingSystem' => [
30
            'name'    => true,
31
            'version' => false,
32
        ],
33
34
        'device' => [
35
            'model'    => false,
36
            'brand'    => false,
37
            'type'     => true,
38
            'isMobile' => false,
39
            'isTouch'  => false,
40
        ],
41
42
        'bot' => [
43
            'isBot' => true,
44
            'name'  => false,
45
            'type'  => false,
46
        ],
47
    ];
48
49
    protected $defaultValues = [
50
        'unknown',
51
    ];
52
53
    private static $uri = 'http://api.udger.com/parse';
54
55
    private $apiKey;
56
57 16
    public function __construct(Client $client, $apiKey)
58
    {
59 16
        parent::__construct($client);
60
61 16
        $this->apiKey = $apiKey;
62 16
    }
63
64 3
    public function getName()
65
    {
66 3
        return 'UdgerCom';
67
    }
68
69 1
    public function getComposerPackageName()
70
    {
71 1
        return;
72
    }
73
74 1
    public function getVersion()
75
    {
76 1
        return;
77
    }
78
79
    /**
80
     *
81
     * @param  string                     $userAgent
82
     * @param  array                      $headers
83
     * @return stdClass
84
     * @throws Exception\RequestException
85
     */
86 12
    protected function getResult($userAgent, array $headers)
0 ignored issues
show
Unused Code introduced by
The parameter $headers is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
87
    {
88
        /*
89
         * an empty UserAgent makes no sense
90
         */
91 12
        if ($userAgent == '') {
92 1
            throw new Exception\NoResultFoundException('No result found for user agent: ' . $userAgent);
93
        }
94
95
        $params = [
96 11
            'accesskey' => $this->apiKey,
97 11
            'uastrig'   => $userAgent,
98 11
        ];
99
100 11
        $body = http_build_query($params, null, '&');
101
102 11
        $request = new Request('POST', self::$uri, [
103 11
            'Content-Type' => 'application/x-www-form-urlencoded',
104 11
        ], $body);
105
106
        try {
107 11
            $response = $this->getResponse($request);
108 11
        } catch (Exception\RequestException $ex) {
109
            /* @var $prevEx \GuzzleHttp\Exception\ClientException */
110 3
            $prevEx = $ex->getPrevious();
111
112 3
            if ($prevEx->hasResponse() === true && $prevEx->getResponse()->getStatusCode() === 400) {
113 2
                $content = $prevEx->getResponse()
114 2
                    ->getBody()
115 2
                    ->getContents();
116 2
                $content = json_decode($content);
117
118 2
                if (isset($content->flag) && $content->flag == 4) {
119 1
                    throw new Exception\InvalidCredentialsException('Your API key "' . $this->apiKey . '" is not valid for ' . $this->getName(), null, $ex);
120
                }
121
122 1 View Code Duplication
                if (isset($content->flag) && $content->flag == 6) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
123 1
                    throw new Exception\LimitationExceededException('Exceeded the maximum number of request with API key "' . $this->apiKey . '" for ' . $this->getName(), null, $ex);
124
                }
125
            }
126
127 1
            throw $ex;
128
        }
129
130
        /*
131
         * no json returned?
132
         */
133 8
        $contentType = $response->getHeader('Content-Type');
134 8 View Code Duplication
        if (! isset($contentType[0]) || $contentType[0] != 'application/json') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
135 1
            throw new Exception\RequestException('Could not get valid "application/json" response from "' . $request->getUri() . '". Response is "' . $response->getBody()->getContents() . '"');
136
        }
137
138 7
        $content = json_decode($response->getBody()->getContents());
139
140
        /*
141
         * No result found?
142
         */
143 7
        if (isset($content->flag) && $content->flag == 3) {
144 1
            throw new Exception\NoResultFoundException('No result found for user agent: ' . $userAgent);
145
        }
146
147
        /*
148
         * Missing data?
149
         */
150 6 View Code Duplication
        if (! $content instanceof stdClass || ! isset($content->info)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
151 1
            throw new Exception\RequestException('Could not get valid response from "' . $request->getUri() . '". Response is "' . $response->getBody()->getContents() . '"');
152
        }
153
154 5
        return $content;
155
    }
156
157
    /**
158
     *
159
     * @param  stdClass $resultRaw
160
     * @return boolean
161
     */
162 5 View Code Duplication
    private function isBot(stdClass $resultRaw)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
163
    {
164 5
        if (isset($resultRaw->type) && $resultRaw->type === 'Robot') {
165 1
            return true;
166
        }
167
168 4
        return false;
169
    }
170
171
    /**
172
     *
173
     * @param Model\Bot $bot
174
     * @param stdClass  $resultRaw
175
     */
176 1 View Code Duplication
    private function hydrateBot(Model\Bot $bot, stdClass $resultRaw)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
177
    {
178 1
        $bot->setIsBot(true);
179
180 1
        if (isset($resultRaw->ua_family) && $this->isRealResult($resultRaw->ua_family) === true) {
181 1
            $bot->setName($resultRaw->ua_family);
182
        }
183 1
    }
184
185
    /**
186
     *
187
     * @param Model\Browser $browser
188
     * @param stdClass      $resultRaw
189
     */
190 4
    private function hydrateBrowser(Model\Browser $browser, stdClass $resultRaw)
191
    {
192 4
        if (isset($resultRaw->ua_family) && $this->isRealResult($resultRaw->ua_family) === true) {
193 1
            $browser->setName($resultRaw->ua_family);
194
        }
195
196 4
        if (isset($resultRaw->ua_ver) && $this->isRealResult($resultRaw->ua_ver) === true) {
197 1
            $browser->getVersion()->setComplete($resultRaw->ua_ver);
198
        }
199 4
    }
200
201
    /**
202
     *
203
     * @param Model\RenderingEngine $engine
204
     * @param stdClass              $resultRaw
205
     */
206 4
    private function hydrateRenderingEngine(Model\RenderingEngine $engine, stdClass $resultRaw)
207
    {
208 4
        if (isset($resultRaw->ua_engine) && $this->isRealResult($resultRaw->ua_engine) === true) {
209 1
            $engine->setName($resultRaw->ua_engine);
210
        }
211 4
    }
212
213
    /**
214
     *
215
     * @param Model\OperatingSystem $os
216
     * @param stdClass              $resultRaw
217
     */
218 4
    private function hydrateOperatingSystem(Model\OperatingSystem $os, stdClass $resultRaw)
219
    {
220 4
        if (isset($resultRaw->os_family) && $this->isRealResult($resultRaw->os_family) === true) {
221 1
            $os->setName($resultRaw->os_family);
222
        }
223 4
    }
224
225
    /**
226
     *
227
     * @param Model\UserAgent $device
228
     * @param stdClass        $resultRaw
229
     */
230 4
    private function hydrateDevice(Model\Device $device, stdClass $resultRaw)
231
    {
232 4
        if (isset($resultRaw->device_name) && $this->isRealResult($resultRaw->device_name) === true) {
233 1
            $device->setType($resultRaw->device_name);
234
        }
235 4
    }
236
237 12
    public function parse($userAgent, array $headers = [])
238
    {
239 12
        $resultRaw = $this->getResult($userAgent, $headers);
240
241
        /*
242
         * Hydrate the model
243
         */
244 5
        $result = new Model\UserAgent();
245 5
        $result->setProviderResultRaw($resultRaw);
246
247
        /*
248
         * Bot detection
249
         */
250 5
        if ($this->isBot($resultRaw->info) === true) {
251 1
            $this->hydrateBot($result->getBot(), $resultRaw->info);
252
253 1
            return $result;
254
        }
255
256
        /*
257
         * hydrate the result
258
         */
259 4
        $this->hydrateBrowser($result->getBrowser(), $resultRaw->info);
260 4
        $this->hydrateRenderingEngine($result->getRenderingEngine(), $resultRaw->info);
261 4
        $this->hydrateOperatingSystem($result->getOperatingSystem(), $resultRaw->info);
262 4
        $this->hydrateDevice($result->getDevice(), $resultRaw->info);
263
264 4
        return $result;
265
    }
266
}
267