Completed
Push — master ( 44676f...b7bc18 )
by Jens
13:18
created

Attribute   C

Complexity

Total Complexity 71

Size/Duplication

Total Lines 486
Duplicated Lines 6.58 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 85.19%

Importance

Changes 0
Metric Value
wmc 71
lcom 1
cbo 4
dl 32
loc 486
ccs 161
cts 189
cp 0.8519
rs 5.5904
c 0
b 0
f 0

43 Methods

Rating   Name   Duplication   Size   Complexity  
A fieldDefinitions() 0 7 1
B fieldDefinition() 0 18 5
A getApiType() 0 15 3
A setAttributeDefinition() 0 6 1
A initialize() 0 9 2
A setApiType() 0 14 4
A getValueAsBool() 0 6 1
A getValueAsNumber() 0 6 1
A getValueAsString() 0 6 1
A getValueAsLocalizedString() 0 6 1
A getValueAsLocalizedEnum() 0 6 1
A getValueAsEnum() 0 6 1
A getValueAsMoney() 0 6 1
A getValueAsDate() 0 6 1
A getValueAsTime() 0 6 1
A getValueAsDateTime() 0 6 1
A getValueAsNested() 0 6 1
A getValueAsReference() 0 6 1
A getValueAsBoolSet() 0 6 1
A getValueAsNumberSet() 0 6 1
A getValueAsStringSet() 0 6 1
A getValueAsLocalizedStringSet() 0 6 1
A getValueAsLocalizedEnumSet() 0 6 1
A getValueAsEnumSet() 0 6 1
A getValueAsMoneySet() 0 6 1
A getValueAsDateSet() 0 6 1
A getValueAsTimeSet() 0 6 1
A getValueAsDateTimeSet() 0 6 1
A getValueAsNestedSet() 0 6 1
A getValueAsReferenceSet() 0 6 1
B guessApiType() 0 24 3
A hasKeys() 0 8 2
A guessUnknown() 0 4 2
A guessTextLike() 0 4 2
A guessBool() 0 4 2
A guessNumber() 0 4 2
A guessEnum() 8 8 3
A guessLocalizedEnum() 8 8 3
A guessMoney() 8 8 2
A guessReference() 8 8 2
A guessLocalizedText() 0 8 3
A guessSet() 0 8 2
A guessNested() 0 11 3

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
 * @author @jayS-de <[email protected]>
4
 * @created: 04.02.15, 17:46
5
 */
6
7
namespace Commercetools\Core\Model\Common;
8
9
use Commercetools\Core\Model\ProductType\AttributeDefinition;
10
use Commercetools\Core\Model\ProductType\AttributeType;
11
use Commercetools\Core\Model\ProductType\SetType;
12
13
/**
14
 * @package Commercetools\Core\Model\Common
15
 * @link https://dev.commercetools.com/http-api-projects-products.html#attribute
16
 * @method string getName()
17
 * @method Attribute setName(string $name = null)
18
 * @method mixed getValue()
19
 * @method Attribute setValue($value = null)
20
 */
21
class Attribute extends JsonObject
22
{
23
    // identifiers for the Api Product Attribute Types:
24
    const T_UNKNOWN = 'unknown';  // zero, should evaluate to false
25
26
    const PROP_VALUE = "value";
27
    const PROP_KEY = "key";
28
    const PROP_NAME = "name";
29
    const PROP_CURRENCY_CODE = "currencyCode";
30
    const PROP_CENT_AMOUNT = "centAmount";
31
    const PROP_TYPE_ID = "typeId";
32
    const PROP_ID = "id";
33
    const PROP_LABEL = "label";
34
35
    const API_BOOL = 'boolean';
36
    const API_NUMBER = 'number';
37
    const API_TEXT = 'text';
38
    const API_LTEXT = 'ltext';
39
    const API_LENUM = 'lenum';
40
    const API_ENUM = 'enum';
41
    const API_MONEY = 'money';
42
    const API_DATE = 'date';
43
    const API_TIME = 'time';
44
    const API_DATETIME = 'datetime';
45
    const API_SET = 'set';
46
    const API_NESTED = 'nested';
47
    const API_REFERENCE = 'reference';
48
49
    protected static $types = [];
50
51 48
    public function fieldDefinitions()
52
    {
53
        return [
54 48
            static::PROP_NAME => [static::TYPE => 'string'],
55 48
            static::PROP_VALUE => [],
56
        ];
57
    }
58
59 48
    public function fieldDefinition($field)
60
    {
61 48
        if ($field == static::PROP_VALUE) {
62 47
            if (isset(static::$types[$this->getName()])) {
63 40
                $fieldDefinition = static::$types[$this->getName()];
64 40
                if (!$fieldDefinition instanceof AttributeDefinition) {
65
                    return null;
66
                }
67 40
                $fieldType = $fieldDefinition->getType();
68 40
                if (!$fieldType instanceof AttributeType) {
69
                    return null;
70
                }
71 40
                return $fieldType->fieldTypeDefinition();
72
            }
73 8
            return null;
74
        }
75 48
        return parent::fieldDefinition($field);
76
    }
77
78
    /**
79
     * @param $attributeName
80
     * @param $value
81
     * @return mixed
82
     */
83 40
    protected function getApiType($attributeName, $value)
84
    {
85 40
        if (isset(static::$types[$attributeName])) {
86 25
            return static::$types[$attributeName];
87
        }
88
89 15
        $apiType = $this->guessApiType($value);
90 15
        $elementType = null;
91 15
        if ($apiType == static::API_SET) {
92 2
            $elementType = $this->guessApiType(current($value));
93
        }
94 15
        $this->setApiType($attributeName, $apiType, $elementType);
95
96 15
        return static::$types[$attributeName];
97
    }
98
99
    /**
100
     * @param AttributeDefinition $definition
101
     * @return $this
102
     */
103 40
    public function setAttributeDefinition(AttributeDefinition $definition)
104
    {
105 40
        static::$types[$definition->getName()] = $definition;
106
107 40
        return $this;
108
    }
109
110
    /**
111
     * @param string $field
112
     */
113 41
    protected function initialize($field)
114
    {
115 41
        if ($field == static::PROP_VALUE) {
116 40
            $name = $this->getRaw(static::PROP_NAME);
117 40
            $value = $this->getRaw(static::PROP_VALUE);
118 40
            $this->getApiType($name, $value);
119
        }
120 41
        parent::initialize($field);
121 41
    }
122
123 36
    private function setApiType($attributeName, $valueType, $elementType = null)
124
    {
125 36
        if (!isset(static::$types[$attributeName])) {
126 36
            $attributeType = AttributeType::fromArray(['name' => $valueType]);
127 36
            if ($attributeType instanceof SetType && $elementType != null) {
128 13
                $attributeType->setElementType(AttributeType::fromArray(['name' => $elementType]));
129
            }
130
131 36
            $definition = AttributeDefinition::of($this->getContextCallback());
132 36
            $definition->setName($attributeName);
133 36
            $definition->setType($attributeType);
134 36
            $this->setAttributeDefinition($definition);
135
        }
136 36
    }
137
138
    /**
139
     * @return bool
140
     */
141 1
    public function getValueAsBool()
142
    {
143 1
        $attributeName = $this->getName();
144 1
        $this->setApiType($attributeName, static::API_BOOL);
145 1
        return $this->getValue();
146
    }
147
148
    /**
149
     * @return int|float
150
     */
151 2
    public function getValueAsNumber()
152
    {
153 2
        $attributeName = $this->getName();
154 2
        $this->setApiType($attributeName, static::API_NUMBER);
155 2
        return $this->getValue();
156
    }
157
158
    /**
159
     * @return string
160
     */
161 1
    public function getValueAsString()
162
    {
163 1
        $attributeName = $this->getName();
164 1
        $this->setApiType($attributeName, static::API_TEXT);
165 1
        return $this->getValue();
166
    }
167
168
    /**
169
     * @return LocalizedString
170
     */
171 1
    public function getValueAsLocalizedString()
172
    {
173 1
        $attributeName = $this->getName();
174 1
        $this->setApiType($attributeName, static::API_LTEXT);
175 1
        return $this->getValue();
176
    }
177
178
    /**
179
     * @return LocalizedEnum
180
     */
181 1
    public function getValueAsLocalizedEnum()
182
    {
183 1
        $attributeName = $this->getName();
184 1
        $this->setApiType($attributeName, static::API_LENUM);
185 1
        return $this->getValue();
186
    }
187
188
    /**
189
     * @return Enum
190
     */
191 1
    public function getValueAsEnum()
192
    {
193 1
        $attributeName = $this->getName();
194 1
        $this->setApiType($attributeName, static::API_ENUM);
195 1
        return $this->getValue();
196
    }
197
198
    /**
199
     * @return Money
200
     */
201 1
    public function getValueAsMoney()
202
    {
203 1
        $attributeName = $this->getName();
204 1
        $this->setApiType($attributeName, static::API_MONEY);
205 1
        return $this->getValue();
206
    }
207
208
    /**
209
     * @return DateDecorator
210
     */
211
    public function getValueAsDate()
212
    {
213
        $attributeName = $this->getName();
214
        $this->setApiType($attributeName, static::API_DATE);
215
        return $this->getValue();
216
    }
217
218
    /**
219
     * @return TimeDecorator
220
     */
221
    public function getValueAsTime()
222
    {
223
        $attributeName = $this->getName();
224
        $this->setApiType($attributeName, static::API_TIME);
225
        return $this->getValue();
226
    }
227
228
    /**
229
     * @return DateTimeDecorator
230
     */
231
    public function getValueAsDateTime()
232
    {
233
        $attributeName = $this->getName();
234
        $this->setApiType($attributeName, static::API_DATETIME);
235
        return $this->getValue();
236
    }
237
238
    /**
239
     * @return AttributeCollection
240
     */
241 1
    public function getValueAsNested()
242
    {
243 1
        $attributeName = $this->getName();
244 1
        $this->setApiType($attributeName, static::API_NESTED);
245 1
        return $this->getValue();
246
    }
247
248
    /**
249
     * @return Reference
250
     */
251 1
    public function getValueAsReference()
252
    {
253 1
        $attributeName = $this->getName();
254 1
        $this->setApiType($attributeName, static::API_REFERENCE);
255 1
        return $this->getValue();
256
    }
257
258
    /**
259
     * @return Set
260
     */
261 1
    public function getValueAsBoolSet()
262
    {
263 1
        $attributeName = $this->getName();
264 1
        $this->setApiType($attributeName, static::API_SET, static::API_BOOL);
265 1
        return $this->getValue();
266
    }
267
268
    /**
269
     * @return Set
270
     */
271 2
    public function getValueAsNumberSet()
272
    {
273 2
        $attributeName = $this->getName();
274 2
        $this->setApiType($attributeName, static::API_SET, static::API_NUMBER);
275 2
        return $this->getValue();
276
    }
277
278
    /**
279
     * @return Set
280
     */
281 1
    public function getValueAsStringSet()
282
    {
283 1
        $attributeName = $this->getName();
284 1
        $this->setApiType($attributeName, static::API_SET, static::API_TEXT);
285 1
        return $this->getValue();
286
    }
287
288
    /**
289
     * @return Set
290
     */
291 1
    public function getValueAsLocalizedStringSet()
292
    {
293 1
        $attributeName = $this->getName();
294 1
        $this->setApiType($attributeName, static::API_SET, static::API_LTEXT);
295 1
        return $this->getValue();
296
    }
297
298
    /**
299
     * @return Set
300
     */
301 1
    public function getValueAsLocalizedEnumSet()
302
    {
303 1
        $attributeName = $this->getName();
304 1
        $this->setApiType($attributeName, static::API_SET, static::API_LENUM);
305 1
        return $this->getValue();
306
    }
307
308
    /**
309
     * @return Set
310
     */
311 2
    public function getValueAsEnumSet()
312
    {
313 2
        $attributeName = $this->getName();
314 2
        $this->setApiType($attributeName, static::API_SET, static::API_ENUM);
315 2
        return $this->getValue();
316
    }
317
318
    /**
319
     * @return Set
320
     */
321 1
    public function getValueAsMoneySet()
322
    {
323 1
        $attributeName = $this->getName();
324 1
        $this->setApiType($attributeName, static::API_SET, static::API_MONEY);
325 1
        return $this->getValue();
326
    }
327
328
    /**
329
     * @return Set
330
     */
331
    public function getValueAsDateSet()
332
    {
333
        $attributeName = $this->getName();
334
        $this->setApiType($attributeName, static::API_SET, static::API_DATE);
335
        return $this->getValue();
336
    }
337
338
    /**
339
     * @return Set
340
     */
341
    public function getValueAsTimeSet()
342
    {
343
        $attributeName = $this->getName();
344
        $this->setApiType($attributeName, static::API_SET, static::API_TIME);
345
        return $this->getValue();
346
    }
347
348
    /**
349
     * @return Set
350
     */
351
    public function getValueAsDateTimeSet()
352
    {
353
        $attributeName = $this->getName();
354
        $this->setApiType($attributeName, static::API_SET, static::API_DATETIME);
355
        return $this->getValue();
356
    }
357
358
    /**
359
     * @return Set
360
     */
361 1
    public function getValueAsNestedSet()
362
    {
363 1
        $attributeName = $this->getName();
364 1
        $this->setApiType($attributeName, static::API_SET, static::API_NESTED);
365 1
        return $this->getValue();
366
    }
367
368
    /**
369
     * @return Set
370
     */
371 1
    public function getValueAsReferenceSet()
372
    {
373 1
        $attributeName = $this->getName();
374 1
        $this->setApiType($attributeName, static::API_SET, static::API_REFERENCE);
375 1
        return $this->getValue();
376
    }
377
378
    /**
379
     * @param $value
380
     * @return string
381
     */
382 15
    protected function guessApiType($value)
383
    {
384
        $map = [
385 15
            'guessUnknown',
386
            'guessBool',
387
            'guessTextLike',
388
            'guessNumber',
389
            'guessEnum',
390
            'guessLocalizedEnum',
391
            'guessMoney',
392
            'guessReference',
393
            'guessLocalizedText',
394
            'guessNested',
395
            'guessSet',
396
        ];
397
398 15
        foreach ($map as $function) {
399 15
            if ($type = $this->$function($value)) {
400 15
                return $type;
401
            }
402
        }
403
404
        return static::T_UNKNOWN;
405
    }
406
407
    /**
408
     * @param $value
409
     * @param string[] $keys
410
     * @return bool
411
     */
412 9
    protected function hasKeys($value, $keys)
413
    {
414 9
        if (!is_array($value)) {
415 1
            return false;
416
        }
417 9
        $intersect = array_intersect_key(array_flip($keys), $value);
418 9
        return (count($intersect) == count($keys));
419
    }
420
421 15
    protected function guessUnknown($value)
422
    {
423 15
        return (!isset($value) ? static::T_UNKNOWN : null);
424
    }
425
426 13
    protected function guessTextLike($value)
427
    {
428 13
        return is_string($value) ? static::API_TEXT : null;
429
    }
430
431 14
    protected function guessBool($value)
432
    {
433 14
        return is_bool($value) ? static::API_BOOL : null;
434
    }
435
436 11
    protected function guessNumber($value)
437
    {
438 11
        return is_numeric($value) ? static::API_NUMBER : null;
439
    }
440
441 9 View Code Duplication
    protected function guessEnum($value)
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...
442
    {
443 9
        if ($this->hasKeys($value, [static::PROP_KEY, static::PROP_LABEL]) && is_string($value[static::PROP_LABEL])) {
444 2
            return static::API_ENUM;
445
        }
446
447 8
        return null;
448
    }
449
450 8 View Code Duplication
    protected function guessLocalizedEnum($value)
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...
451
    {
452 8
        if ($this->hasKeys($value, [static::PROP_KEY, static::PROP_LABEL]) && is_array($value[static::PROP_LABEL])) {
453 1
            return static::API_LENUM;
454
        }
455
456 7
        return null;
457
    }
458
459 7 View Code Duplication
    protected function guessMoney($value)
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...
460
    {
461 7
        if ($this->hasKeys($value, [static::PROP_CENT_AMOUNT, static::PROP_CURRENCY_CODE])) {
462 1
            return static::API_MONEY;
463
        }
464
465 6
        return null;
466
    }
467
468 6 View Code Duplication
    protected function guessReference($value)
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...
469
    {
470 6
        if ($this->hasKeys($value, [static::PROP_TYPE_ID, static::PROP_ID])) {
471 2
            return static::API_REFERENCE;
472
        }
473
474 4
        return null;
475
    }
476
477 4
    protected function guessLocalizedText($value)
478
    {
479 4
        if (is_array($value) && !is_numeric(key($value))) {
480 1
            return static::API_LTEXT;
481
        }
482
483 3
        return null;
484
    }
485
486 2
    protected function guessSet($value)
487
    {
488 2
        if (is_array($value)) {
489 2
            return static::API_SET;
490
        }
491
492
        return null;
493
    }
494
495 3
    protected function guessNested($value)
496
    {
497 3
        if (is_array($value)) {
498 3
            $first = reset($value);
499 3
            if ($this->hasKeys($first, [static::PROP_NAME, static::PROP_VALUE])) {
500 1
                return static::API_NESTED;
501
            }
502
        }
503
504 2
        return null;
505
    }
506
}
507