BaseParam::getDefault()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
cc 4
eloc 9
c 3
b 0
f 1
nc 3
nop 0
dl 0
loc 17
rs 9.9666
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\Framework\Config\AppDatabaseConfig;
52
use Platine\Framework\Http\RequestData;
53
use Platine\Http\ServerRequestInterface;
54
use Platine\Orm\Entity;
55
use Platine\Stdlib\Helper\Str;
56
use ReflectionClass;
57
use ReflectionNamedType;
58
use ReflectionProperty;
59
60
/**
61
 * @class BaseParam
62
 * @package Platine\Framework\Form\Param
63
 * @template TEntity as Entity
64
 */
65
class BaseParam implements JsonSerializable
66
{
67
    /**
68
     * The list of fields to ignore
69
     * @var array<string>
70
     */
71
    protected array $ignores = ['from'];
72
73
    /**
74
     * Create new instance
75
     * @param array<string, mixed> $data
76
     */
77
    public function __construct(array $data = [])
78
    {
79
        // Load default values
80
        $this->loadDefaultValues();
81
82
        $params = array_merge($this->getDefault(), $data);
83
        $this->load($params);
84
    }
85
86
    /**
87
     * Load the field data
88
     * @param array<string, mixed> $data
89
     * @return void
90
     */
91
    public function load(array $data): void
92
    {
93
        foreach ($data as $name => $value) {
94
            $key = Str::camel($name, true);
95
            $typedValue = $this->getPropertyValue($key, $value);
96
97
            $setterMethod = 'set' . ucfirst($key);
98
            if (method_exists($this, $setterMethod)) {
99
                $this->{$setterMethod}($typedValue);
100
            } elseif (property_exists($this, $key)) {
101
                $this->{$key} = $typedValue;
102
            }
103
        }
104
    }
105
106
    /**
107
     *
108
     * @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...
109
     * @return $this
110
     */
111
    public function fromEntity(Entity $entity): self
112
    {
113
        return $this;
114
    }
115
116
    /**
117
     * Return the fields default values
118
     * @return array<string, mixed>
119
     */
120
    public function getDefault(): array
121
    {
122
        // TODO
123
        /** @var ServerRequestInterface $request */
124
        $request = app(ServerRequestInterface::class);
125
        $param = new RequestData($request);
126
127
        $defaults = [];
128
        $queries = $param->gets();
129
        foreach ($queries as $name => $value) {
130
            $field = Str::camel($name, true);
131
            if (property_exists($this, $field) && in_array($name, $this->ignores) === false) {
132
                $defaults[$name] = $value;
133
            }
134
        }
135
136
        return $defaults;
137
    }
138
139
    /**
140
     * Return the parameters values
141
     * @return array<string, mixed>
142
     */
143
    public function data(): array
144
    {
145
        $values = get_object_vars($this);
146
        unset($values['ignores']);
147
148
        return $values;
149
    }
150
151
    /**
152
     * Convert parameter to JSON array
153
     * @return mixed
154
     */
155
    public function jsonSerialize(): mixed
156
    {
157
        return $this->data();
158
    }
159
160
    /**
161
     * Return the value for the given property
162
     * @param string $name
163
     * @return mixed
164
     */
165
    public function __get(string $name): mixed
166
    {
167
        if (property_exists($this, $name)) {
168
            return $this->{$name};
169
        }
170
171
        //convert to camel
172
        $key = Str::camel($name, true);
173
        if (property_exists($this, $key)) {
174
            return $this->{$key};
175
        }
176
177
        return null;
178
    }
179
180
    /**
181
    * Create instance using database configuration
182
    * @param AppDatabaseConfig $cfg
183
    * @return $this
184
    */
185
    public function fromConfig(AppDatabaseConfig $cfg): self
186
    {
187
        return $this;
188
    }
189
190
    /**
191
     * Return the value after cast
192
     * @param string $attribute
193
     * @param mixed $value
194
     * @return mixed
195
     */
196
    protected function getPropertyValue(string $attribute, mixed $value): mixed
197
    {
198
        $types = $this->getPropertyTypes();
199
        $property = $types[$attribute] ?? null;
200
        if ($property === null) {
201
            return $value;
202
        }
203
204
        $type = $property[0];
205
        $allowNull = $property[1];
206
207
        if (
208
            in_array($type, ['array', 'object']) === false &&
209
            strlen((string) $value) === 0 && $allowNull
210
        ) {
211
            return null;
212
        }
213
214
        if ($type === 'string' && $value !== null) {
215
            $value = trim((string) $value);
216
        }
217
218
        $maps = $this->getPropertiesCastMaps();
219
        $map = $maps[$type] ?? [];
220
        if (count($map) === 0) {
221
            return $value;
222
        }
223
224
        $closure = $map[0] ?? fn($value) => $value;
225
226
        return $closure($value);
227
    }
228
229
    /**
230
     * Return the properties of this class
231
     * @return array<string, array<int, bool|ReflectionProperty|string>>
232
     */
233
    protected function getPropertyTypes(): array
234
    {
235
        $props = [];
236
237
        $reflectionClass = new ReflectionClass($this);
238
        /** @var ReflectionProperty[] $properties */
239
        $properties = $reflectionClass->getProperties(ReflectionProperty::IS_PROTECTED);
240
        foreach ($properties as $property) {
241
            if ($property->getName() === 'ignores') {
242
                continue;
243
            }
244
245
            /** @var ReflectionNamedType|null $type */
246
            $type = $property->getType();
247
            if ($type !== null && $type->isBuiltin()) {
248
                $props[$property->getName()] = [
249
                    $type->getName(),
250
                    $type->allowsNull(),
251
                    $property,
252
                ];
253
            }
254
        }
255
256
        return $props;
257
    }
258
259
    /**
260
     * Return the properties cast maps
261
     * @return array<string, array<int, Closure|mixed>>
262
     */
263
    protected function getPropertiesCastMaps(): array
264
    {
265
        return [
266
            'int' => [fn($value) => intval($value), 0],
267
            'float' => [fn($value) => floatval($value), 0.0],
268
            'double' => [fn($value) => doubleval($value), 0.0],
269
            'bool' => [fn($value) => boolval($value), false],
270
            'string' => [fn($value) => strval($value), ''],
271
            'array' => [fn($value) => (array) $value, []],
272
        ];
273
    }
274
275
    /**
276
     * Load the default value based on data type
277
     * @return void
278
     */
279
    protected function loadDefaultValues(): void
280
    {
281
        $data = [];
282
        $types = $this->getPropertyTypes();
283
        $maps = $this->getPropertiesCastMaps();
284
285
        foreach ($types as $attr => $val) {
286
            /** @var ReflectionProperty $property */
287
            $property = $val[2];
288
            $property->setAccessible(true);
289
            if (isset($maps[$val[0]]) && $property->isInitialized($this) === false) {
290
                $data[$attr] = $maps[$val[0]][1];
291
            }
292
        }
293
294
        $this->load($data);
295
    }
296
}
297