Passed
Push — master ( 472f53...0ee5cf )
by Fran
02:53
created

Dto   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 181
Duplicated Lines 0 %

Test Coverage

Coverage 97.7%

Importance

Changes 6
Bugs 0 Features 0
Metric Value
eloc 80
dl 0
loc 181
ccs 85
cts 87
cp 0.977
rs 9.0399
c 6
b 0
f 0
wmc 42

10 Methods

Rating   Name   Duplication   Size   Complexity  
A toArray() 0 3 1
A __construct() 0 5 2
B checkCastedValue() 0 20 8
B __toArray() 0 29 9
A castValue() 0 3 1
B parseDtoField() 0 24 11
A fromArray() 0 9 5
A extractTypes() 0 12 3
A jsonSerialize() 0 3 1
A __toString() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Dto 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.

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 Dto, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace PSFS\base\dto;
3
4
use PSFS\base\Logger;
5
use PSFS\base\Request;
6
use PSFS\base\Singleton;
7
use PSFS\base\types\helpers\InjectorHelper;
8
9
/**
10
 * Class Dto
11
 * @package PSFS\base\dto
12
 */
13
class Dto extends Singleton implements \JsonSerializable
14
{
15
    /**
16
     * @var array
17
     */
18
    protected $__cache = [];
19 4
    public function __construct($hydrate = true)
20
    {
21 4
        parent::__construct();
22 4
        if($hydrate) {
23 2
            $this->fromArray(Request::getInstance()->getData());
24
        }
25 4
    }
26
27
    /**
28
     * ToArray wrapper
29
     * @return array
30
     */
31 4
    public function toArray()
32
    {
33 4
        return $this->__toArray();
34
    }
35
36
    /**
37
     * Convert dto to array representation
38
     * @return array
39
     */
40 4
    public function __toArray()
41
    {
42 4
        $dto = array();
43
        try {
44 4
            $reflectionClass = new \ReflectionClass($this);
45 4
            $properties = $reflectionClass->getProperties(\ReflectionProperty::IS_PUBLIC);
46 4
            if (count($properties) > 0) {
47
                /** @var \ReflectionProperty $property */
48 4
                foreach ($properties as $property) {
49 4
                    $value = $property->getValue($this);
50 4
                    if(is_object($value) && method_exists($value, 'toArray')) {
51 1
                        $dto[$property->getName()] = $value->toArray();
52 4
                    } elseif(is_array($value)) {
53 4
                        foreach($value as &$arrValue) {
54 2
                            if($arrValue instanceof Dto) {
55 2
                                $arrValue = $arrValue->toArray();
56
                            }
57
                        }
58 4
                        $dto[$property->getName()] = $value;
59
                    } else {
60 4
                        $type = InjectorHelper::extractVarType($property->getDocComment());
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $type is correct as PSFS\base\types\helpers\...perty->getDocComment()) targeting PSFS\base\types\helpers\...elper::extractVarType() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
61 4
                        $dto[$property->getName()] = $this->checkCastedValue($property->getValue($this), $type);
62
                    }
63
                }
64
            }
65
        } catch (\Exception $e) {
66
            Logger::log(get_class($this) . ': ' . $e->getMessage(), LOG_ERR);
67
        }
68 4
        return $dto;
69
    }
70
71
    /**
72
     * Convert to string representation
73
     * @return string
74
     */
75 1
    public function __toString()
76
    {
77 1
        return get_class($this);
78
    }
79
80
    /**
81
     * @param array $properties
82
     * @param $key
83
     * @param mixed $value
84
     * @throws \ReflectionException
85
     */
86 2
    protected function parseDtoField(array $properties, $key, $value = null) {
87 2
        list($type, $isArray) = $this->extractTypes($properties, $key);
88 2
        $reflector = (class_exists($type)) ? new \ReflectionClass($type) : null;
89 2
        if(null !== $reflector && $reflector->isSubclassOf(Dto::class)) {
90 1
            if(null !== $value && is_array($value)) {
91 1
                if(!array_key_exists($type, $this->__cache)) {
92 1
                    $this->__cache[$type] = new $type(false);
93
                }
94 1
                if($isArray) {
95 1
                    $this->$key = [];
96 1
                    foreach($value as $data) {
97 1
                        if(null !== $data && is_array($data)) {
98 1
                            $dto = clone $this->__cache[$type];
99 1
                            $dto->fromArray($data);
100 1
                            array_push($this->$key, $dto);
101
                        }
102
                    }
103
                } else {
104 1
                    $this->$key = clone $this->__cache[$type];
105 1
                    $this->$key->fromArray($value);
106
                }
107
            }
108
        } else {
109 2
            $this->castValue($key, $value, $type);
110
        }
111 2
    }
112
113
    /**
114
     * Hydrate object from array
115
     * @param array $object
116
     * @throws \ReflectionException
117
     */
118 3
    public function fromArray(array $object = array())
119
    {
120 3
        if (count($object) > 0) {
121 2
            $reflector = new \ReflectionClass($this);
122 2
            $properties = InjectorHelper::extractProperties($reflector, \ReflectionProperty::IS_PUBLIC, InjectorHelper::VAR_PATTERN);
123 2
            unset($reflector);
124 2
            foreach ($object as $key => $value) {
125 2
                if (property_exists($this, $key) && null !== $value) {
126 2
                    $this->parseDtoField($properties, $key, $value);
127
                }
128
            }
129
        }
130 3
    }
131
132
    /**
133
     * @return array|mixed
134
     */
135 1
    public function jsonSerialize()
136
    {
137 1
        return $this->toArray();
138
    }
139
140
    /**
141
     * @param array $properties
142
     * @param $key
143
     * @return array
144
     */
145 2
    protected function extractTypes(array $properties, $key)
146
    {
147 2
        $type = 'string';
148 2
        $isArray = false;
149 2
        if (array_key_exists($key, $properties)) {
150 2
            $type = $properties[$key];
151 2
            if (preg_match('/(\[\]|Array)/i', $type)) {
152 1
                $type = preg_replace('/(\[\]|Array)/i', '', $type);
153 1
                $isArray = true;
154
            }
155
        }
156 2
        return array($type, $isArray);
157
    }
158
159
    /**
160
     * @param string $key
161
     * @param mixed $value
162
     * @param string $type
163
     */
164 2
    protected function castValue($key, $value, $type)
165
    {
166 2
        $this->$key = $this->checkCastedValue($value, $type);
167 2
    }
168
169
    /**
170
     * @param mixed $rawValue
171
     * @param string $type
172
     * @return mixed
173
     */
174 4
    protected function checkCastedValue($rawValue, $type) {
175 4
        switch ($type) {
176
            default:
177 4
            case 'string':
178 4
                $value = $rawValue;
179 4
                break;
180 4
            case 'integer':
181 4
            case 'int':
182 4
                $value = (integer)$rawValue;
183 4
                break;
184 4
            case 'float':
185 4
            case 'double':
186 1
                $value = (float)$rawValue;
187 1
                break;
188 4
            case 'boolean':
189 3
            case 'bool':
190 4
                $value = (bool)$rawValue;
191 4
                break;
192
        }
193 4
        return $value;
194
    }
195
}
196