Passed
Push — develop ( 6e46d5...d55787 )
by nguereza
03:20
created

BaseParam::getPropertyValue()   A

Complexity

Conditions 6
Paths 4

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 16
nc 4
nop 2
dl 0
loc 27
rs 9.1111
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Platine Framework
5
 *
6
 * Platine Framework is a lightweight, high-performance, simple and elegant
7
 * PHP Web framework
8
 *
9
 * This content is released under the MIT License (MIT)
10
 *
11
 * Copyright (c) 2020 Platine Framework
12
 *
13
 * Permission is hereby granted, free of charge, to any person obtaining a copy
14
 * of this software and associated documentation files (the "Software"), to deal
15
 * in the Software without restriction, including without limitation the rights
16
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
 * copies of the Software, and to permit persons to whom the Software is
18
 * furnished to do so, subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included in all
21
 * copies or substantial portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
 * SOFTWARE.
30
 */
31
32
/**
33
 *  @file BaseParam.php
34
 *
35
 *  The Form base parameter class
36
 *
37
 *  @package    Platine\Framework\Form\Param
38
 *  @author Platine Developers team
39
 *  @copyright  Copyright (c) 2020
40
 *  @license    http://opensource.org/licenses/MIT  MIT License
41
 *  @link   https://www.platine-php.com
42
 *  @version 1.0.0
43
 *  @filesource
44
 */
45
46
declare(strict_types=1);
47
48
namespace Platine\Framework\Form\Param;
49
50
use JsonSerializable;
51
use Platine\Orm\Entity;
52
use Platine\Stdlib\Helper\Str;
53
use ReflectionClass;
54
use ReflectionNamedType;
55
use ReflectionProperty;
56
57
/**
58
 * @class BaseParam
59
 * @package Platine\Framework\Form\Param
60
 * @template TEntity as Entity
61
 */
62
class BaseParam implements JsonSerializable
63
{
64
    /**
65
     * Create new instance
66
     * @param array<string, mixed> $data
67
     */
68
    public function __construct(array $data = [])
69
    {
70
        // Load default values
71
        $this->loadDefaultValues();
72
        
73
        $params = array_merge($this->getDefault(), $data);
74
        $this->load($params);
75
    }
76
77
    /**
78
     * Load the field data
79
     * @param array<string, mixed> $data
80
     * @return void
81
     */
82
    public function load(array $data): void
83
    {
84
        foreach ($data as $name => $value) {
85
            $key = Str::camel($name, true);
86
            $typedValue = $this->getPropertyValue($key, $value);
87
88
            $setterMethod = 'set' . ucfirst($key);
89
            if (method_exists($this, $setterMethod)) {
90
                $this->{$setterMethod}($typedValue);
91
            } elseif (property_exists($this, $key)) {
92
                $this->{$key} = $typedValue;
93
            }
94
        }
95
    }
96
97
    /**
98
     *
99
     * @param TEntity $entity
0 ignored issues
show
Bug introduced by
The type Platine\Framework\Form\Param\TEntity 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...
100
     * @return $this
101
     */
102
    public function fromEntity(Entity $entity): self
103
    {
104
        return $this;
105
    }
106
107
    /**
108
     * Return the fields default values
109
     * @return array<string, mixed>
110
     */
111
    public function getDefault(): array
112
    {
113
        return [];
114
    }
115
116
    /**
117
     * Return the parameters values
118
     * @return array<string, mixed>
119
     */
120
    public function data(): array
121
    {
122
        return get_object_vars($this);
123
    }
124
125
    /**
126
     * Convert parameter to JSON array
127
     * @return array<string, mixed>
128
     */
129
    public function jsonSerialize()
130
    {
131
        return $this->data();
132
    }
133
134
    /**
135
     * Return the value for the given property
136
     * @param string $name
137
     * @return mixed|null
138
     */
139
    public function __get($name)
140
    {
141
        if (property_exists($this, $name)) {
142
            return $this->{$name};
143
        }
144
145
        //convert to camel
146
        $key = Str::camel($name, true);
147
        if (property_exists($this, $key)) {
148
            return $this->{$key};
149
        }
150
151
        return null;
152
    }
153
154
    /**
155
     * Return the value after cast
156
     * @param string $attribute
157
     * @param mixed $value
158
     * @return mixed
159
     */
160
    protected function getPropertyValue(string $attribute, $value)
161
    {
162
        $types = $this->getPropertyTypes();
163
        $property = $types[$attribute] ?? null;
164
        if ($property === null) {
165
            return $value;
166
        }
167
168
        $type = $property[0];
169
        $allowNull = $property[1];
170
171
        if (
172
            in_array($type, ['array', 'object']) === false &&
173
            strlen((string) $value) === 0 && $allowNull
174
        ) {
175
            return null;
176
        }
177
178
        $maps = $this->getPropertiesCastMaps();
179
        $map = $maps[$type] ?? [];
180
        if (count($map) === 0) {
181
            return $value;
182
        }
183
184
        $closure = $map[0] ?? fn($value) => $value;
185
186
        return $closure($value);
187
    }
188
189
    /**
190
     * Return the properties of this class
191
     * @return array<string, string>
192
     */
193
    protected function getPropertyTypes(): array
194
    {
195
        $props = [];
196
197
        $reflectionClass = new ReflectionClass($this);
198
        /** @var ReflectionProperty[] $properties */
199
        $properties = $reflectionClass->getProperties(ReflectionProperty::IS_PROTECTED);
200
        foreach ($properties as $property) {
201
            /** @var ReflectionNamedType|null $type */
202
            $type = $property->getType();
203
            if ($type !== null && $type->isBuiltin()) {
204
                $props[$property->getName()] = [$type->getName(), $type->allowsNull()];
205
            }
206
        }
207
208
        return $props;
209
    }
210
211
    /**
212
     * Return the properties cast maps
213
     * @return array<string, Closure>
214
     */
215
    protected function getPropertiesCastMaps(): array
216
    {
217
        return [
218
            'int' => [fn($value) => intval($value), 0],
219
            'float' => [fn($value) => floatval($value), 0.0],
220
            'double' => [fn($value) => doubleval($value), 0.0],
221
            'bool' => [fn($value) => boolval($value), false],
222
            'string' => [fn($value) => strval($value), ''],
223
            'array' => [fn($value) => (array) $value, []],
224
        ];
225
    }
226
227
    /**
228
     * Load the default value based on data type
229
     * @return void
230
     */
231
    protected function loadDefaultValues(): void
232
    {
233
        $data = [];
234
        $types = $this->getPropertyTypes();
235
        $maps = $this->getPropertiesCastMaps();
236
237
        foreach ($types as $attr => $val) {
238
            if (isset($maps[$val[0]])) {
239
                $data[$attr] = $maps[$val[0]][1];
240
            }
241
        }
242
243
        $this->load($data);
244
    }
245
}
246