Attribute   B
last analyzed

Complexity

Total Complexity 47

Size/Duplication

Total Lines 265
Duplicated Lines 36.98 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 47
lcom 1
cbo 2
dl 98
loc 265
ccs 120
cts 120
cp 1
rs 8.439
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A getName() 0 4 1
A getType() 0 4 1
B setType() 0 17 10
A getValue() 0 4 1
A getIsStandard() 0 4 1
A setIsStandard() 0 4 1
D clean() 55 82 15
A cleanAttributeBoolean() 9 12 2
C cleanAttributeInteger() 14 32 8
A cleanAttributeString() 10 12 2
A cleanAttributeUri() 10 15 2
A __toString() 0 10 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 Attribute 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 Attribute, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Groundskeeper\Tokens;
4
5
use Groundskeeper\Configuration;
6
use Psr\Log\LoggerInterface;
7
8
class Attribute
9
{
10
    const BOOL = 'ci_boo'; // boolean
11
    const CI_ENUM = 'ci_enu'; // case-insensitive enumeration
12
    const CI_SSENUM = 'ci_sse'; // case-insensitive space-separated enumeration
13
    const INT = 'ci_int'; // integer
14
    const JS = 'cs_jsc'; // javascript
15
    const CI_STRING = 'ci_str'; // case-insensitive string
16
    const CS_STRING = 'cs_str'; // case-sensitive string
17
    const URI = 'cs_uri'; // uri
18
    const UNKNOWN = 'cs_unk'; // unknown
19
20
    /** @var string */
21
    private $name;
22
23
    /** @var string */
24
    private $type;
25
26
    /** @var null|mixed */
27
    private $value;
28
29
    /** @var bool */
30
    private $isStandard;
31
32
    /**
33
     * Constructor
34
     */
35 117
    public function __construct(string $name, $value = null)
36
    {
37 117
        $this->name = $name;
38 117
        $this->type = self::UNKNOWN;
39 117
        $this->value = $value;
40 117
        $this->isStandard = false;
41 117
    }
42
43
    /**
44
     * Getter for 'name'.
45
     */
46 94
    public function getName() : string
47
    {
48 94
        return $this->name;
49
    }
50
51
    /**
52
     * Getter for 'type'.
53
     */
54 2
    public function getType() : string
55
    {
56 2
        return $this->type;
57
    }
58
59
    /**
60
     * Chainable setter for 'type'.
61
     */
62 106
    public function setType(string $type)
63
    {
64 106
        $typeEnum = mb_substr($type, 0, 6);
65 106
        if ($typeEnum !== self::BOOL &&
66 106
            $typeEnum !== self::CI_ENUM &&
67 106
            $typeEnum !== self::CI_SSENUM &&
68 106
            $typeEnum !== self::INT &&
69 106
            $typeEnum !== self::JS &&
70 106
            $typeEnum !== self::CI_STRING &&
71 106
            $typeEnum !== self::CS_STRING &&
72 106
            $typeEnum !== self::URI &&
73 106
            $typeEnum !== self::UNKNOWN) {
74 1
            throw new \InvalidArgumentException('Invalid attribute type: ' . $typeEnum);
75
        }
76
77 106
        $this->type = $type;
78 106
    }
79
80
    /**
81
     * Getter for 'value'.
82
     */
83 19
    public function getValue()
84
    {
85 19
        return $this->value;
86
    }
87
88
    /**
89
     * Getter for 'isStandard'.
90
     */
91 2
    public function getIsStandard() : bool
92
    {
93 2
        return $this->isStandard;
94
    }
95
96
    /**
97
     * Chainable setter for 'isStandard'.
98
     */
99 106
    public function setIsStandard(bool $isStandard)
100
    {
101 106
        $this->isStandard = $isStandard;
102 106
    }
103
104 105
    public function clean(Configuration $configuration, Element $element, LoggerInterface $logger)
105
    {
106 105
        if ($configuration->get('clean-strategy') === Configuration::CLEAN_STRATEGY_NONE) {
107 1
            return true;
108
        }
109
110
        // Remove non-standard attributes.
111 104 View Code Duplication
        if ($configuration->get(
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...
112 104
                'clean-strategy'
113 104
            ) !== Configuration::CLEAN_STRATEGY_LENIENT && $this->isStandard === false) {
114 10
            $logger->debug('Removing non-standard attribute "' . $this->name . '" from ' . $element);
115
116 10
            return false;
117
        }
118
119
        // Validate attribute value.
120 103
        list($caseSensitivity, $attributeType) = explode('_', $this->type);
121
122
        // Standard is case-insensitive attribute values should be lower case.
123 103
        if ($caseSensitivity === 'ci' && $this->value !== true) {
124 32
            $newValue = strtolower($this->value);
125 32 View Code Duplication
            if ($newValue !== $this->value) {
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...
126 4
                $logger->debug(
127 4
                    'Within ' . $element . ', the value for the attribute "' . $this->name . '" is case-insensitive.  The value has been converted to lower case.'
128
                );
129 4
                $this->value = $newValue;
130
            }
131
        }
132
133
        // Validate value types.
134
        switch ($attributeType) {
135 103 View Code Duplication
        case 'boo': // boolean
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...
136 7
            $cleanResult = $this->cleanAttributeBoolean(
137 7
                $configuration,
138 7
                $element,
139 7
                $logger
140
            );
141 7
            if ($configuration->get('clean-strategy') !== Configuration::CLEAN_STRATEGY_LENIENT) {
142 6
                return $cleanResult;
143
            }
144
145 5
            break;
146
147 98 View Code Duplication
        case 'int': // integer
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...
148 13
            $cleanResult = $this->cleanAttributeInteger(
149 13
                $configuration,
150 13
                $element,
151 13
                $logger
152
            );
153 13
            if ($configuration->get('clean-strategy') !== Configuration::CLEAN_STRATEGY_LENIENT) {
154 13
                return $cleanResult;
155
            }
156
157 9
            break;
158
159 90 View Code Duplication
        case 'str': // string
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...
160 68
            $cleanResult = $this->cleanAttributeString(
161 68
                $configuration,
162 68
                $element,
163 68
                $logger
164
            );
165 68
            if ($configuration->get('clean-strategy') !== Configuration::CLEAN_STRATEGY_LENIENT) {
166 66
                return $cleanResult;
167
            }
168
169 55
            break;
170
171 45 View Code Duplication
        case 'uri': // URI
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...
172 36
            $cleanResult = $this->cleanAttributeUri(
173 36
                $configuration,
174 36
                $element,
175 36
                $logger
176
            );
177 36
            if ($configuration->get('clean-strategy') !== Configuration::CLEAN_STRATEGY_LENIENT) {
178 31
                return $cleanResult;
179
            }
180
181 34
            break;
182
        }
183
184 82
        return true;
185
    }
186
187 7 View Code Duplication
    private function cleanAttributeBoolean(Configuration $configuration, Element $element, LoggerInterface $logger)
0 ignored issues
show
Unused Code introduced by
The parameter $configuration 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...
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...
188
    {
189 7
        if ($this->value !== true) {
190 3
            $logger->debug(
191 3
                'Within ' . $element . ', the attribute "' . $this->name .
192 3
                '" is a boolean attribute.  The value has been removed.'
193
            );
194 3
            $this->value = true;
195
        }
196
197 7
        return true;
198
    }
199
200 13
    private function cleanAttributeInteger(Configuration $configuration, Element $element, LoggerInterface $logger)
201
    {
202 13
        if ($this->value === true || $this->value == '') {
203 2 View Code Duplication
            if ($configuration->get('clean-strategy') !== Configuration::CLEAN_STRATEGY_LENIENT) {
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...
204 2
                $logger->debug(
205 2
                    'Within ' . $element . ', the value for the attribute "' . $this->name . '" is required to be an positive, non-zero integer.  The value is invalid, therefore the attribute has been removed.'
206
                );
207
            }
208
209 2
            return false;
210
        }
211
212 12
        if (!is_int($this->value)) {
213 12
            $originalValue = (string) $this->value;
214 12
            $this->value = (int) $this->value;
215 12 View Code Duplication
            if ($originalValue !== ((string) $this->value)) {
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...
216 3
                $logger->debug(
217 3
                    'Within ' . $element . ', the value for the attribute "' . $this->name . '" is required to be an positive, non-zero integer.  The value has been converted to an integer.'
218
                );
219
            }
220
        }
221
222 12 View Code Duplication
        if ($this->value <= 0 && $configuration->get('clean-strategy') !== Configuration::CLEAN_STRATEGY_LENIENT) {
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...
223 3
            $logger->debug(
224 3
                'Within ' . $element . ', the value for the attribute "' . $this->value . '" is required to be an positive, non-zero integer.  The value is invalid, therefore the attribute has been removed.'
225
            );
226
227 3
            return false;
228
        }
229
230 10
        return true;
231
    }
232
233 68 View Code Duplication
    private function cleanAttributeString(Configuration $configuration, Element $element, LoggerInterface $logger)
0 ignored issues
show
Unused Code introduced by
The parameter $configuration 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...
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...
234
    {
235 68
        if ($this->value === true) {
236 1
            $logger->debug(
237 1
                'Within ' . $element . ', the attribute "' . $this->name . '" requires a string value.  The value is missing, therefore the attribute value is set to the attribute name.'
238
            );
239
240 1
            $this->value = $this->name;
241
        }
242
243 68
        return true;
244
    }
245
246 36 View Code Duplication
    private function cleanAttributeUri(Configuration $configuration, Element $element, LoggerInterface $logger)
0 ignored issues
show
Unused Code introduced by
The parameter $configuration 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...
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...
247
    {
248
        // Check for empty attribute.
249 36
        if ($this->value === true) {
250 1
            $logger->debug(
251 1
                'Within ' . $element . ', the attribute "' . $this->name . '" requires a URI.  The value is invalid, therefore the attribute has been removed.'
252
            );
253
254 1
            return false;
255
        }
256
257
        /// @todo
258
259 35
        return true;
260
    }
261
262 95
    public function __toString()
263
    {
264 95
        $output = $this->name;
265 95
        if ($this->value === true) {
266 6
            return $output;
267
        }
268
269
        /// @todo Escape double quotes in value.
270 94
        return $output . '="' . $this->value . '"';
271
    }
272
}
273