Test Failed
Push — master ( 306f11...77481f )
by Fran
14:04
created

Dto::toArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
namespace PSFS\base\dto;
4
5
use PSFS\base\Logger;
6
use PSFS\base\Request;
0 ignored issues
show
Bug introduced by
The type PSFS\base\Request was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use PSFS\base\Singleton;
8
use PSFS\base\types\helpers\InjectorHelper;
9
10
/**
11
 * Class Dto
12
 * @package PSFS\base\dto
13
 */
14
class Dto extends Singleton implements \JsonSerializable
15
{
16
    /**
17
     * @var array
18
     */
19
    protected array $__cache = [];
20
21 2
    public function __construct($hydrate = true)
22
    {
23 2
        parent::__construct();
24 2
        if ($hydrate) {
25
            $this->fromArray(Request::getInstance()->getData());
26
        }
27
    }
28
29
    /**
30
     * ToArray wrapper
31
     * @return array
32
     */
33 2
    public function toArray()
34
    {
35 2
        return $this->__toArray();
36
    }
37
38
    /**
39
     * Convert dto to array representation
40
     * @return array
41
     */
42 2
    public function __toArray()
43
    {
44 2
        $dto = [];
45
        try {
46 2
            $reflectionClass = new \ReflectionClass($this);
47 2
            $properties = $reflectionClass->getProperties(\ReflectionProperty::IS_PUBLIC);
48 2
            if (count($properties) > 0) {
49 2
                foreach ($properties as $property) {
50 2
                    $value = $property->getValue($this);
51 2
                    if (is_object($value) && method_exists($value, 'toArray')) {
52 1
                        $dto[$property->getName()] = $value->toArray();
53 2
                    } elseif (is_array($value)) {
54 2
                        foreach ($value as &$arrValue) {
55 2
                            if ($arrValue instanceof Dto) {
56 1
                                $arrValue = $arrValue->toArray();
57
                            }
58
                        }
59 2
                        $dto[$property->getName()] = $value;
60
                    } else {
61 2
                        $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...
62 2
                        $dto[$property->getName()] = $this->checkCastedValue($property->getValue($this), $type ?: 'string');
63
                    }
64
                }
65
            }
66
        } catch (\Exception $e) {
67
            Logger::log(get_class($this) . ': ' . $e->getMessage(), LOG_ERR);
68
        }
69 2
        return $dto;
70
    }
71
72
    /**
73
     * Convert to string representation
74
     * @return string
75
     */
76 1
    public function __toString()
77
    {
78 1
        return get_class($this);
79
    }
80
81
    /**
82
     * @param array $properties
83
     * @param string $key
84
     * @param mixed|null $value
85
     */
86 1
    protected function parseDtoField(array $properties, string $key, $value = null)
87
    {
88 1
        list($type, $isArray) = $this->extractTypes($properties, $key);
89 1
        $reflector = (class_exists($type)) ? new \ReflectionClass($type) : null;
90 1
        if (null !== $reflector && $reflector->isSubclassOf(Dto::class)) {
91 1
            if (is_array($value)) {
92 1
                if (!array_key_exists($type, $this->__cache)) {
93 1
                    $this->__cache[$type] = new $type(false);
94
                }
95 1
                if ($isArray) {
96 1
                    $this->$key = [];
97 1
                    foreach ($value as $data) {
98 1
                        if (is_array($data)) {
99 1
                            $dto = clone $this->__cache[$type];
100 1
                            $dto->fromArray($data);
101 1
                            $this->$key[] = $dto;
102
                        }
103
                    }
104
                } else {
105 1
                    $this->$key = clone $this->__cache[$type];
106 1
                    $this->$key->fromArray($value);
107
                }
108
            }
109
        } else {
110 1
            $this->castValue($key, $value, $type);
111
        }
112
    }
113
114
    /**
115
     * Hydrate object from array
116
     * @param array $object
117
     * @throws \ReflectionException
118
     */
119 1
    public function fromArray(array $object = [])
120
    {
121 1
        if (count($object) > 0) {
122 1
            $reflector = new \ReflectionClass($this);
123 1
            $properties = InjectorHelper::extractProperties($reflector, \ReflectionProperty::IS_PUBLIC, InjectorHelper::VAR_PATTERN);
124 1
            unset($reflector);
125 1
            foreach ($object as $key => $value) {
126 1
                if (property_exists($this, $key) && null !== $value) {
127 1
                    $this->parseDtoField($properties, $key, $value);
128
                }
129
            }
130
        }
131
    }
132
133
    /**
134
     * @return mixed
135
     */
136 1
    public function jsonSerialize(): array|string|null
137
    {
138 1
        return $this->toArray();
139
    }
140
141
    /**
142
     * @param array $properties
143
     * @param string $key
144
     * @return array
145
     */
146 1
    protected function extractTypes(array $properties, string $key): array
147
    {
148 1
        $type = 'string';
149 1
        $isArray = false;
150 1
        if (array_key_exists($key, $properties)) {
151 1
            $type = $properties[$key];
152 1
            if (preg_match('/(\[\]|Array)/i', $type)) {
153 1
                $type = preg_replace('/(\[\]|Array)/i', '', $type);
154 1
                $isArray = true;
155
            }
156
        }
157 1
        return array($type, $isArray);
158
    }
159
160
    /**
161
     * @param string $key
162
     * @param mixed $value
163
     * @param string $type
164
     */
165 1
    protected function castValue(string $key, mixed $value, string $type): void
166
    {
167 1
        $this->$key = $this->checkCastedValue($value, $type);
168
    }
169
170
    /**
171
     * @param mixed $rawValue
172
     * @param string $type
173
     * @return bool|float|int|string|null
174
     */
175 2
    protected function checkCastedValue(mixed $rawValue, string $type)
176
    {
177 2
        if (null !== $rawValue) {
178
            switch ($type) {
179
                default:
180 2
                case 'string':
181 2
                    $value = $rawValue;
182 2
                    break;
183 2
                case 'integer':
184 2
                case 'int':
185 2
                    $value = (integer)$rawValue;
186 2
                    break;
187 2
                case 'float':
188 2
                case 'double':
189 1
                    $value = (float)$rawValue;
190 1
                    break;
191 2
                case 'boolean':
192 1
                case 'bool':
193 2
                    $value = (bool)$rawValue;
194 2
                    break;
195
            }
196
        } else {
197
            $value = $rawValue;
198
        }
199 2
        return $value;
200
    }
201
}
202