Completed
Push — master ( 7014bb...a38bcf )
by James
15s
created

GetData   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 155
Duplicated Lines 3.23 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 17
c 0
b 0
f 0
lcom 1
cbo 7
dl 5
loc 155
ccs 0
cts 54
cp 0
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B getSettings() 0 42 6
C getIniPart() 5 62 10

How to fix   Duplicated Code   

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:

1
<?php
2
declare(strict_types = 1);
3
4
namespace BrowscapPHP\Parser\Helper;
5
6
use BrowscapPHP\Cache\BrowscapCacheInterface;
7
use BrowscapPHP\Data\PropertyFormatter;
8
use BrowscapPHP\Data\PropertyHolder;
9
use BrowscapPHP\Helper\QuoterInterface;
10
use Psr\Log\LoggerInterface;
11
use Psr\SimpleCache\InvalidArgumentException;
12
13
/**
14
 * extracts the data and the data for theses pattern from the ini content, optimized for PHP 5.5+
15
 */
16
final class GetData implements GetDataInterface
17
{
18
    /**
19
     * The cache instance
20
     *
21
     * @var \BrowscapPHP\Cache\BrowscapCacheInterface
22
     */
23
    private $cache;
24
25
    /**
26
     * a logger instance
27
     *
28
     * @var \Psr\Log\LoggerInterface
29
     */
30
    private $logger;
31
32
    /**
33
     * @var \BrowscapPHP\Helper\Quoter
34
     */
35
    private $quoter;
36
37
    /**
38
     * class contsructor
39
     *
40
     * @param \BrowscapPHP\Cache\BrowscapCacheInterface $cache
41
     * @param \Psr\Log\LoggerInterface                  $logger
42
     * @param \BrowscapPHP\Helper\QuoterInterface       $quoter
43
     */
44
    public function __construct(BrowscapCacheInterface $cache, LoggerInterface $logger, QuoterInterface $quoter)
45
    {
46
        $this->cache = $cache;
47
        $this->logger = $logger;
48
        $this->quoter = $quoter;
0 ignored issues
show
Documentation Bug introduced by
$quoter is of type object<BrowscapPHP\Helper\QuoterInterface>, but the property $quoter was declared to be of type object<BrowscapPHP\Helper\Quoter>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
49
    }
50
51
    /**
52
     * Gets the settings for a given pattern (method calls itself to
53
     * get the data from the parent patterns)
54
     *
55
     * @param  string $pattern
56
     * @param  array  $settings
57
     * @return array
58
     */
59
    public function getSettings(string $pattern, array $settings = []) : array
60
    {
61
        // The pattern has been pre-quoted on generation to speed up the pattern search,
62
        // but for this check we need the unquoted version
63
        $unquotedPattern = $this->quoter->pregUnQuote($pattern);
64
65
        // Try to get settings for the pattern
66
        $addedSettings = $this->getIniPart($unquotedPattern);
67
68
        // set some additional data
69
        if (count($settings) === 0) {
70
            // The optimization with replaced digits get can now result in setting searches, for which we
71
            // won't find a result - so only add the pattern information, is settings have been found.
72
            //
73
            // If not an empty array will be returned and the calling function can easily check if a pattern
74
            // has been found.
75
            if (count($addedSettings) > 0) {
76
                $settings['browser_name_regex'] = '/^' . $pattern . '$/';
77
                $settings['browser_name_pattern'] = $unquotedPattern;
78
            }
79
        }
80
81
        // check if parent pattern set, only keep the first one
82
        $parentPattern = null;
83
84
        if (isset($addedSettings['Parent'])) {
85
            $parentPattern = $addedSettings['Parent'];
86
87
            if (isset($settings['Parent'])) {
88
                unset($addedSettings['Parent']);
89
            }
90
        }
91
92
        // merge settings
93
        $settings += $addedSettings;
94
95
        if (is_string($parentPattern)) {
96
            return $this->getSettings($this->quoter->pregQuote($parentPattern), $settings);
97
        }
98
99
        return $settings;
100
    }
101
102
    /**
103
     * Gets the relevant part (array of settings) of the ini file for a given pattern.
104
     *
105
     * @param  string $pattern
106
     * @return array
107
     */
108
    private function getIniPart(string $pattern) : array
109
    {
110
        $pattern = strtolower($pattern);
111
        $patternhash = Pattern::getHashForParts($pattern);
112
        $subkey = SubKey::getIniPartCacheSubKey($patternhash);
113
114
        try {
115 View Code Duplication
            if (! $this->cache->hasItem('browscap.iniparts.' . $subkey, true)) {
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...
116
                $this->logger->debug('cache key "browscap.iniparts.' . $subkey . '" not found');
117
118
                return [];
119
            }
120
        } catch (InvalidArgumentException $e) {
121
            $this->logger->error(new \InvalidArgumentException('an error occured while checking a inipart in the cache', 0, $e));
122
            return [];
123
        }
124
125
126
        $success = null;
127
        try {
128
            $file = $this->cache->getItem('browscap.iniparts.' . $subkey, true, $success);
129
        } catch (InvalidArgumentException $e) {
130
            $this->logger->error(new \InvalidArgumentException('an error occured while reading a inipart from the cache', 0, $e));
131
132
            return [];
133
        }
134
135
136
        if (! $success) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $success of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
137
            $this->logger->debug('cache key "browscap.iniparts.' . $subkey . '" not found');
138
139
            return [];
140
        }
141
142
        if (! is_array($file) || ! count($file)) {
143
            $this->logger->debug('cache key "browscap.iniparts.' . $subkey . '" was empty');
144
145
            return [];
146
        }
147
148
        $propertyFormatter = new PropertyFormatter(new PropertyHolder());
149
        $return = [];
150
151
        foreach ($file as $buffer) {
152
            list($tmpBuffer, $patterns) = explode("\t", $buffer, 2);
153
154
            if ($tmpBuffer === $patternhash) {
155
                $return = json_decode($patterns, true);
156
157
                foreach (array_keys($return) as $property) {
158
                    $return[$property] = $propertyFormatter->formatPropertyValue(
159
                        $return[$property],
160
                        $property
161
                    );
162
                }
163
164
                break;
165
            }
166
        }
167
168
        return $return;
169
    }
170
}
171