feat: DTO에 DefaultValue, DefaultValueGenerator 추가
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\DTO\Attr;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class DefaultValue
|
||||||
|
{
|
||||||
|
public function __construct(public readonly null|bool|int|float|string|array $defaultValue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefaultValue(): mixed
|
||||||
|
{
|
||||||
|
return $this->defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace sammo\DTO\Attr;
|
||||||
|
|
||||||
|
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||||
|
class DefaultValueGenerator
|
||||||
|
{
|
||||||
|
public function __construct(public readonly string $generator)
|
||||||
|
{
|
||||||
|
if (!is_callable($generator)) {
|
||||||
|
throw new \Exception("$generator is not a callable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefaultValue(): mixed
|
||||||
|
{
|
||||||
|
$generator = $this->generator;
|
||||||
|
return $generator();
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
-5
@@ -11,7 +11,6 @@ abstract class DTO
|
|||||||
public static function fromArray(\ArrayAccess|array $array): static
|
public static function fromArray(\ArrayAccess|array $array): static
|
||||||
{
|
{
|
||||||
$reflection = new \ReflectionClass(static::class);
|
$reflection = new \ReflectionClass(static::class);
|
||||||
$args = [];
|
|
||||||
|
|
||||||
if ($array instanceof \ArrayAccess) {
|
if ($array instanceof \ArrayAccess) {
|
||||||
$keyExists = fn (string|int $key) => $array->offsetExists($key);
|
$keyExists = fn (string|int $key) => $array->offsetExists($key);
|
||||||
@@ -19,6 +18,11 @@ abstract class DTO
|
|||||||
$keyExists = fn (string|int $key) => array_key_exists($key, $array);
|
$keyExists = fn (string|int $key) => array_key_exists($key, $array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$params = Util\Util::getConstructorParams($reflection);
|
||||||
|
|
||||||
|
$args = [];
|
||||||
|
$lazyMap = [];
|
||||||
|
|
||||||
foreach ($reflection->getProperties(
|
foreach ($reflection->getProperties(
|
||||||
\ReflectionProperty::IS_PUBLIC
|
\ReflectionProperty::IS_PUBLIC
|
||||||
) as $property) {
|
) as $property) {
|
||||||
@@ -26,6 +30,19 @@ abstract class DTO
|
|||||||
$name = $property->getName();
|
$name = $property->getName();
|
||||||
$rawName = $name;
|
$rawName = $name;
|
||||||
|
|
||||||
|
$param = $params[$name] ?? null;
|
||||||
|
|
||||||
|
if (key_exists(Attr\DefaultValueGenerator::class, $attrs)){
|
||||||
|
/** @var Attr\DefaultValueGenerator */
|
||||||
|
$defaultValueSetter = $attrs[Attr\DefaultValueGenerator::class]->newInstance();
|
||||||
|
} else if (key_exists(Attr\DefaultValue::class, $attrs)) {
|
||||||
|
/** @var Attr\DefaultValue */
|
||||||
|
$defaultValueSetter = $attrs[Attr\DefaultValue::class]->newInstance();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$defaultValueSetter = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (key_exists(Attr\RawName::class, $attrs)) {
|
if (key_exists(Attr\RawName::class, $attrs)) {
|
||||||
$rawAttr = $attrs[Attr\RawName::class];
|
$rawAttr = $attrs[Attr\RawName::class];
|
||||||
$attr = new Attr\RawName(...$rawAttr->getArguments());
|
$attr = new Attr\RawName(...$rawAttr->getArguments());
|
||||||
@@ -33,13 +50,25 @@ abstract class DTO
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$keyExists($rawName)) {
|
if (!$keyExists($rawName)) {
|
||||||
if ($property->hasDefaultValue()) {
|
if ($param !== null && $param->isOptional()){
|
||||||
$args[$name] = $property->getDefaultValue();
|
$defaultValue = $param->getDefaultValue();
|
||||||
|
}
|
||||||
|
else if ($property->hasDefaultValue()) {
|
||||||
|
$defaultValue = $property->getDefaultValue();
|
||||||
|
} else if($defaultValueSetter !== null){
|
||||||
|
$defaultValue = $defaultValueSetter->getDefaultValue();
|
||||||
} else if ($property->getType()->allowsNull()) {
|
} else if ($property->getType()->allowsNull()) {
|
||||||
$args[$name] = null;
|
$defaultValue = null;
|
||||||
} else {
|
} else {
|
||||||
throw new \Exception("Missing property: {$name}");
|
throw new \Exception("Missing property: {$name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($param !== null){
|
||||||
|
$args[$name] = $defaultValue;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$lazyMap[$name] = $defaultValue;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,10 +89,18 @@ abstract class DTO
|
|||||||
}
|
}
|
||||||
$value = $converter->convertFrom($value);
|
$value = $converter->convertFrom($value);
|
||||||
|
|
||||||
$args[$name] = $value;
|
if($param !== null){
|
||||||
|
$args[$name] = $value;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$lazyMap[$name] = $value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$object = $reflection->newInstanceArgs($args);
|
$object = $reflection->newInstanceArgs($args);
|
||||||
|
foreach($lazyMap as $name => $value){
|
||||||
|
$object->{$name} = $value;
|
||||||
|
}
|
||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,21 @@ class Util{
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string,\ReflectionParameter>
|
||||||
|
*/
|
||||||
|
public static function getConstructorParams(\ReflectionClass $class): array{
|
||||||
|
$constructor = $class->getConstructor();
|
||||||
|
if($constructor === null){
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$result = [];
|
||||||
|
foreach($constructor->getParameters() as $param){
|
||||||
|
$result[$param->getName()] = $param;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<string>
|
* @return array<string>
|
||||||
*/
|
*/
|
||||||
|
|||||||
+57
-8
@@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use sammo\DTO\Attr\Convert;
|
use sammo\DTO\Attr\Convert;
|
||||||
|
use sammo\DTO\Attr\DefaultValue;
|
||||||
|
use sammo\DTO\Attr\DefaultValueGenerator;
|
||||||
use sammo\DTO\DTO;
|
use sammo\DTO\DTO;
|
||||||
use sammo\DTO\Attr\JsonString;
|
use sammo\DTO\Attr\JsonString;
|
||||||
use sammo\DTO\Attr\NullIsUndefined;
|
use sammo\DTO\Attr\NullIsUndefined;
|
||||||
@@ -150,14 +152,13 @@ class TypeRawName extends DTO
|
|||||||
public int $argName,
|
public int $argName,
|
||||||
#[RawName('vID')]
|
#[RawName('vID')]
|
||||||
public int $vID,
|
public int $vID,
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TypeDateTime extends DTO{
|
class TypeDateTime extends DTO
|
||||||
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
#[Convert(DateTimeConverter::class)]
|
#[Convert(DateTimeConverter::class)]
|
||||||
public \DateTimeImmutable $a,
|
public \DateTimeImmutable $a,
|
||||||
@@ -171,6 +172,30 @@ class TypeDateTime extends DTO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function returnDateTime()
|
||||||
|
{
|
||||||
|
return new \DateTimeImmutable('2022-04-01 00:00:00');
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeDefaultValue extends DTO
|
||||||
|
{
|
||||||
|
public bool $g = true;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public ?string $a,
|
||||||
|
#[DefaultValue(false)]
|
||||||
|
public bool $b,
|
||||||
|
public int $c,
|
||||||
|
#[DefaultValue([1,2,3])]
|
||||||
|
public array $e,
|
||||||
|
#[DefaultValueGenerator('returnDateTime')]
|
||||||
|
#[Convert(DateTimeConverter::class)]
|
||||||
|
public \DateTimeInterface $d,
|
||||||
|
public int $f = 111, //contstruct의 뒤에서 default 값이 설정될 경우에만
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class DTOTest extends PHPUnit\Framework\TestCase
|
class DTOTest extends PHPUnit\Framework\TestCase
|
||||||
{
|
{
|
||||||
public function testBasic()
|
public function testBasic()
|
||||||
@@ -321,7 +346,8 @@ class DTOTest extends PHPUnit\Framework\TestCase
|
|||||||
$this->assertEquals($rawType, $testType);
|
$this->assertEquals($rawType, $testType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMap(){
|
public function testMap()
|
||||||
|
{
|
||||||
$rawType = [
|
$rawType = [
|
||||||
'a' => 1,
|
'a' => 1,
|
||||||
'b' => [
|
'b' => [
|
||||||
@@ -336,7 +362,8 @@ class DTOTest extends PHPUnit\Framework\TestCase
|
|||||||
$this->assertEquals($rawType, $testType);
|
$this->assertEquals($rawType, $testType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNestedMap(){
|
public function testNestedMap()
|
||||||
|
{
|
||||||
$rawType = [
|
$rawType = [
|
||||||
'a' => 1,
|
'a' => 1,
|
||||||
'b' => [
|
'b' => [
|
||||||
@@ -357,7 +384,8 @@ class DTOTest extends PHPUnit\Framework\TestCase
|
|||||||
$this->assertEquals($rawType, $testType);
|
$this->assertEquals($rawType, $testType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRawName(){
|
public function testRawName()
|
||||||
|
{
|
||||||
$rawType = [
|
$rawType = [
|
||||||
'arg_name' => 1,
|
'arg_name' => 1,
|
||||||
'vID' => 2,
|
'vID' => 2,
|
||||||
@@ -368,7 +396,8 @@ class DTOTest extends PHPUnit\Framework\TestCase
|
|||||||
$this->assertEquals($rawType, $testType);
|
$this->assertEquals($rawType, $testType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDateTime(){
|
public function testDateTime()
|
||||||
|
{
|
||||||
$rawType = [
|
$rawType = [
|
||||||
'a' => '2022-01-01 10:11:22',
|
'a' => '2022-01-01 10:11:22',
|
||||||
'b' => '2022-02-01T12:34:56.1234+09:00',
|
'b' => '2022-02-01T12:34:56.1234+09:00',
|
||||||
@@ -387,4 +416,24 @@ class DTOTest extends PHPUnit\Framework\TestCase
|
|||||||
|
|
||||||
$this->assertEquals($testValue, $testType);
|
$this->assertEquals($testValue, $testType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testDefaultValue()
|
||||||
|
{
|
||||||
|
$rawType = [
|
||||||
|
'c' => 3,
|
||||||
|
];
|
||||||
|
$testValue = [
|
||||||
|
'g' => true,
|
||||||
|
'a' => null,
|
||||||
|
'b' => false,
|
||||||
|
'c' => 3,
|
||||||
|
'e' => [1, 2, 3],
|
||||||
|
'd' => '2022-04-01 00:00:00',
|
||||||
|
'f' => 111,
|
||||||
|
];
|
||||||
|
$obj = TypeDefaultValue::fromArray($rawType);
|
||||||
|
$testType = $obj->toArray();
|
||||||
|
|
||||||
|
$this->assertEquals($testValue, $testType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user