-
Notifications
You must be signed in to change notification settings - Fork 0
/
AbstractDto.php
executable file
·85 lines (74 loc) · 3.71 KB
/
AbstractDto.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<?php
namespace Laravel\Foundation\Abstracts;
use Carbon\Carbon;
use Carbon\CarbonInterface;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Laravel\Foundation\Exceptions\DTOPropertyNotExists;
use ReflectionException;
use ReflectionObject;
use ReflectionProperty;
abstract class AbstractDto
{
public function __construct(array $validatedData)
{
$this->parseData($validatedData);
}
/**Парсит входной массив, по умолчанию кладет значения в свойства текущего объекта (названия ключей массива преобразуются в camelCase)
* @param array $data массив параметров из запроса
* @param bool $throwIfNoProperty если true, то при отсутствии нужного свойства будет сгенерировано исключение
* @return void
* @throws DTOPropertyNotExists
*/
protected function parseData(array $data, bool $throwIfNoProperty = true): void
{
foreach ($data as $param => $value) {
$propertyName = Str::camel($param);
$propertyExists = property_exists($this, $propertyName);
if ($throwIfNoProperty && !$propertyExists) {
throw new DTOPropertyNotExists("Свойство {$propertyName} не найдено в классе " . static::class);
}
if ($propertyExists) {
//если пришел null, то не проверяем тип свойства
if (is_null($value)) {
$this->{$propertyName} = $value;
continue;
}
$reflectionProperty = new ReflectionProperty(static::class, $propertyName);
$propertyClass = $reflectionProperty->getType()->getName();
$this->{$propertyName} = match (true) {
is_subclass_of($propertyClass, \UnitEnum::class) => $value instanceof \UnitEnum
? $value
: $propertyClass::from($value),
is_subclass_of($propertyClass, CarbonInterface::class) => Carbon::parse($value),
is_subclass_of($propertyClass, AbstractDto::class) => new $propertyClass($value),
$propertyClass === Collection::class => collect($value),
default => $value,
};
}
}
}
/**Возвращает массив, где ключами являются названия публичных полей этого объекта в snake_case, а значениями - текущие значения этих полей<br>
* Незаполненные свойства DTO не будут представлены в массиве
* @return array
* @throws ReflectionException
*/
public function toArray(): array
{
$result = [];
$reflectionObject = new ReflectionObject($this);
$publicProperties = $reflectionObject->getProperties(ReflectionProperty::IS_PUBLIC);
foreach ($publicProperties as $publicProperty) {
$reflectionProperty = new ReflectionProperty(static::class, $publicProperty->name);
$propertyClass = $reflectionProperty->getType()->getName();
if ($reflectionProperty->isInitialized($this)) {
$key = Str::snake($publicProperty->name);
$result[$key] = match (true) {
is_subclass_of($propertyClass, AbstractDto::class) => $this->{$publicProperty->name}?->toArray(),
default => $this->{$publicProperty->name}
};
}
}
return $result;
}
}