include missing
This commit is contained in:
parent
88b5850c32
commit
d3e12785bb
20 changed files with 584 additions and 4 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
parameters:
|
parameters:
|
||||||
paths:
|
paths:
|
||||||
- app
|
- src
|
||||||
- tests
|
- tests
|
||||||
level: 10
|
level: 5
|
||||||
|
|
|
||||||
13
src/Attributes/FromInput.php
Normal file
13
src/Attributes/FromInput.php
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Icefox\DTO\Attributes;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_PARAMETER)]
|
||||||
|
class FromInput
|
||||||
|
{
|
||||||
|
public function __construct(public readonly string $name) {}
|
||||||
|
}
|
||||||
16
src/Attributes/FromMapper.php
Normal file
16
src/Attributes/FromMapper.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Icefox\DTO\Attributes;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_PARAMETER)]
|
||||||
|
class FromMapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param class-string $class
|
||||||
|
*/
|
||||||
|
public function __construct(public readonly string $class) {}
|
||||||
|
}
|
||||||
13
src/Attributes/FromRouteParameter.php
Normal file
13
src/Attributes/FromRouteParameter.php
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Icefox\DTO\Attributes;
|
||||||
|
|
||||||
|
use Attribute;
|
||||||
|
|
||||||
|
#[Attribute(Attribute::TARGET_PARAMETER)]
|
||||||
|
class FromRouteParameter
|
||||||
|
{
|
||||||
|
public function __construct(public readonly string $name) {}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ use Icefox\DTO\Attributes\FromInput;
|
||||||
use Icefox\DTO\Attributes\FromMapper;
|
use Icefox\DTO\Attributes\FromMapper;
|
||||||
use Icefox\DTO\Attributes\FromRouteParameter;
|
use Icefox\DTO\Attributes\FromRouteParameter;
|
||||||
use Icefox\DTO\Support\RuleFactory;
|
use Icefox\DTO\Support\RuleFactory;
|
||||||
|
use Icefox\DTO\Support\ValueFactory;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
@ -39,7 +40,7 @@ trait DataObject
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<int,mixed> $input
|
* @param array<string,mixed> $input
|
||||||
*/
|
*/
|
||||||
public static function fromArray(array $input): static
|
public static function fromArray(array $input): static
|
||||||
{
|
{
|
||||||
|
|
@ -86,7 +87,7 @@ trait DataObject
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$mappedInput[$parameterName] = RuleFactory::resolveValue(
|
$mappedInput[$parameterName] = ValueFactory::resolveValue(
|
||||||
$validator->getValue($parameterName),
|
$validator->getValue($parameterName),
|
||||||
$parameter->tag instanceof Param ? $parameter->tag->getType() : null,
|
$parameter->tag instanceof Param ? $parameter->tag->getType() : null,
|
||||||
$parameter->reflection,
|
$parameter->reflection,
|
||||||
|
|
|
||||||
40
src/Factories/CollectionFactory.php
Normal file
40
src/Factories/CollectionFactory.php
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icefox\DTO\Factories;
|
||||||
|
|
||||||
|
use Icefox\DTO\Support\RuleFactory;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use ReflectionParameter;
|
||||||
|
use phpDocumentor\Reflection\PseudoTypes\Generic;
|
||||||
|
use phpDocumentor\Reflection\Type;
|
||||||
|
|
||||||
|
class CollectionFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array<string,string|Rule[]>
|
||||||
|
*/
|
||||||
|
public static function rules(ReflectionParameter $parameter, ?Type $type): array
|
||||||
|
{
|
||||||
|
if (is_null($type)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$type instanceof Generic) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$subtypes = $type->getTypes();
|
||||||
|
|
||||||
|
if (count($subtypes) == 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$subtype = count($subtypes) == 1 ? $subtypes[0] : $subtypes[1];
|
||||||
|
|
||||||
|
return array_merge(
|
||||||
|
['' => ['array']],
|
||||||
|
RuleFactory::getRulesFromDocBlock($subtype, '.*'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
191
src/Support/RuleFactory.php
Normal file
191
src/Support/RuleFactory.php
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Icefox\DTO\Support;
|
||||||
|
|
||||||
|
use Icefox\DTO\Attributes\FromMapper;
|
||||||
|
use Icefox\DTO\ParameterMeta;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use ReflectionClass;
|
||||||
|
use ReflectionNamedType;
|
||||||
|
use ReflectionParameter;
|
||||||
|
use ReflectionUnionType;
|
||||||
|
use BackedEnum;
|
||||||
|
use phpDocumentor\Reflection\DocBlockFactory;
|
||||||
|
use phpDocumentor\Reflection\DocBlock\Tag;
|
||||||
|
use phpDocumentor\Reflection\DocBlock\Tags\Param;
|
||||||
|
use phpDocumentor\Reflection\Type;
|
||||||
|
use phpDocumentor\Reflection\Types\AbstractList;
|
||||||
|
use phpDocumentor\Reflection\Types\Boolean;
|
||||||
|
use phpDocumentor\Reflection\Types\ContextFactory;
|
||||||
|
use phpDocumentor\Reflection\Types\Float_;
|
||||||
|
use phpDocumentor\Reflection\Types\Integer;
|
||||||
|
use phpDocumentor\Reflection\Types\Nullable;
|
||||||
|
use phpDocumentor\Reflection\Types\Object_;
|
||||||
|
|
||||||
|
class RuleFactory
|
||||||
|
{
|
||||||
|
protected static array $cache = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, array<string|Rule>>
|
||||||
|
*/
|
||||||
|
public static function getRulesFromDocBlock(
|
||||||
|
Type $type,
|
||||||
|
string $prefix,
|
||||||
|
): array {
|
||||||
|
$rules = [];
|
||||||
|
if ($type instanceof Nullable) {
|
||||||
|
$rules[$prefix] = ['nullable'];
|
||||||
|
$rules = array_merge($rules, self::getRulesFromDocBlock($type->getActualType(), $prefix));
|
||||||
|
} else {
|
||||||
|
$rules[$prefix] = ['required'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type instanceof AbstractList) {
|
||||||
|
$rules[$prefix][] = 'array';
|
||||||
|
|
||||||
|
$valueType = $type->getValueType();
|
||||||
|
$rules = array_merge($rules, self::getRulesFromDocBlock($valueType, $prefix . '.*'));
|
||||||
|
}
|
||||||
|
if ($type instanceof Boolean) {
|
||||||
|
$rules[$prefix][] = 'boolean';
|
||||||
|
} elseif ($type instanceof Float_ || $type instanceof Integer) {
|
||||||
|
$rules[$prefix][] = 'numeric';
|
||||||
|
} elseif ($type instanceof Object_) {
|
||||||
|
$paramsSub = self::getParametersMeta($type->getFqsen()->__toString());
|
||||||
|
$rules = array_merge(
|
||||||
|
$rules,
|
||||||
|
self::buildRules($paramsSub, $prefix . '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param class-string $class
|
||||||
|
* @return array<ParameterMeta>
|
||||||
|
*/
|
||||||
|
public static function getParametersMeta(string $class): array
|
||||||
|
{
|
||||||
|
if (array_key_exists($class, self::$cache)) {
|
||||||
|
return self::$cache[$class];
|
||||||
|
}
|
||||||
|
|
||||||
|
$reflection = new ReflectionClass($class);
|
||||||
|
$constructor = $reflection->getConstructor();
|
||||||
|
try {
|
||||||
|
$docblockParams = (DocBlockFactory::createInstance())->create(
|
||||||
|
$constructor->getDocComment(),
|
||||||
|
(new ContextFactory())->createFromReflector($constructor),
|
||||||
|
)->getTagsByName('param');
|
||||||
|
} catch (\Exception) {
|
||||||
|
$docblockParams = [];
|
||||||
|
}
|
||||||
|
self::$cache[$class] = array_map(
|
||||||
|
fn(ReflectionParameter $p) => new ParameterMeta(
|
||||||
|
$p,
|
||||||
|
array_find(
|
||||||
|
$docblockParams,
|
||||||
|
fn(Tag $tag) => $tag instanceof Param ? $tag->getVariableName() == $p->getName() : false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
$constructor->getParameters(),
|
||||||
|
);
|
||||||
|
return self::$cache[$class];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<ParameterMeta> $parameters
|
||||||
|
* @return array<string,array<int,string|Rule>>
|
||||||
|
*/
|
||||||
|
public static function buildRules(array $parameters, string $prefix): array
|
||||||
|
{
|
||||||
|
$rules = [];
|
||||||
|
foreach ($parameters as $parameter) {
|
||||||
|
foreach (self::buildParameterRule($parameter, $prefix) as $key => $newRules) {
|
||||||
|
$rules[$key] = $newRules;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, array<int, string|Rule>>
|
||||||
|
*/
|
||||||
|
public static function buildParameterRule(ParameterMeta $parameter, string $prefix): array
|
||||||
|
{
|
||||||
|
$type = $parameter->reflection->getType();
|
||||||
|
|
||||||
|
$root = $prefix . $parameter->reflection->getName();
|
||||||
|
if (empty($type)) {
|
||||||
|
return [$root => $parameter->reflection->isOptional() ? ['sometimes'] : ['required']];
|
||||||
|
}
|
||||||
|
|
||||||
|
$rules = [$root => []];
|
||||||
|
if ($parameter->reflection->isOptional()) {
|
||||||
|
$rules[$root][] = 'sometimes';
|
||||||
|
} elseif ($type->allowsNull()) {
|
||||||
|
$rules[$root][] = 'nullable';
|
||||||
|
} else {
|
||||||
|
$rules[$root][] = 'required';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type instanceof ReflectionUnionType) {
|
||||||
|
//TODO: handle ReflectionUnionType
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type instanceof ReflectionNamedType && $name = $type->getName()) {
|
||||||
|
if ($globalRules = config('dto.rules.' . $name)) {
|
||||||
|
foreach ($globalRules($parameter->reflection, $parameter->tag->getType()) as $scopedPrefix => $values) {
|
||||||
|
$realPrefix = $root . $scopedPrefix;
|
||||||
|
$rules[$realPrefix] = array_values(array_unique(array_merge($rules[$realPrefix] ?? [], $values)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($name === 'string') {
|
||||||
|
} elseif ($name === 'bool') {
|
||||||
|
$rules[$root][] = 'boolean';
|
||||||
|
} elseif ($name === 'int' || $name === 'float') {
|
||||||
|
$rules[$root][] = 'numeric';
|
||||||
|
} elseif ($name === 'array') {
|
||||||
|
$rules[$root][] = 'array';
|
||||||
|
} elseif (enum_exists($name)) {
|
||||||
|
$ref = new ReflectionClass($name);
|
||||||
|
if ($ref->isSubclassOf(BackedEnum::class)) {
|
||||||
|
$rules[$root][] = Rule::enum($name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$paramsSub = self::getParametersMeta($type->getName());
|
||||||
|
$rules = array_merge(
|
||||||
|
$rules,
|
||||||
|
self::buildRules($paramsSub, $root . '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($parameter->reflection->getAttributes(FromMapper::class) as $attr) {
|
||||||
|
$mapperClass = $attr->newInstance()->class;
|
||||||
|
if (method_exists($mapperClass, 'rules')) {
|
||||||
|
$subRules = App::call("$mapperClass@rules");
|
||||||
|
foreach ($subRules as $key => &$value) {
|
||||||
|
$path = empty($key) ? $root : ($root . '.' . $key);
|
||||||
|
$rules[$path] = array_values(array_unique(array_merge($rules[$path] ?? [], $value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($parameter->tag instanceof Param) {
|
||||||
|
$docblockRules = self::getRulesFromDocBlock(
|
||||||
|
$parameter->tag->getType(),
|
||||||
|
$prefix . $parameter->reflection->getName(),
|
||||||
|
);
|
||||||
|
foreach ($docblockRules as $key => &$values) {
|
||||||
|
$rules[$key] = array_values(array_unique(array_merge($rules[$key] ?? [], $values)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
}
|
||||||
101
src/Support/ValueFactory.php
Normal file
101
src/Support/ValueFactory.php
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Icefox\DTO\Support;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use ReflectionNamedType;
|
||||||
|
use ReflectionParameter;
|
||||||
|
use phpDocumentor\Reflection\PseudoTypes\Generic;
|
||||||
|
use phpDocumentor\Reflection\Type;
|
||||||
|
use phpDocumentor\Reflection\Types\AbstractList;
|
||||||
|
use phpDocumentor\Reflection\Types\Boolean;
|
||||||
|
use phpDocumentor\Reflection\Types\Float_;
|
||||||
|
use phpDocumentor\Reflection\Types\Integer;
|
||||||
|
use phpDocumentor\Reflection\Types\Nullable;
|
||||||
|
use phpDocumentor\Reflection\Types\Object_;
|
||||||
|
|
||||||
|
class ValueFactory
|
||||||
|
{
|
||||||
|
public static function constructObject(string $className, mixed $rawValue): object
|
||||||
|
{
|
||||||
|
if ($mapper = config('dto.mappers.' . $className, null)) {
|
||||||
|
return $mapper($rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($rawValue)) {
|
||||||
|
return App::makeWith($className, $rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new $className($rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function resolveTypedValue(mixed $rawValue, Type $type): mixed
|
||||||
|
{
|
||||||
|
if ($type instanceof Nullable) {
|
||||||
|
$type = $type->getActualType();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type instanceof Generic) {
|
||||||
|
$types = $type->getTypes();
|
||||||
|
$innerType = count($types) === 2 ? $types[1] : $types[0];
|
||||||
|
$result = [];
|
||||||
|
foreach ($rawValue as $key => $value) {
|
||||||
|
$result[$key] = self::resolveTypedValue($value, $innerType);
|
||||||
|
}
|
||||||
|
return new ($type->getFqsen()->__toString())($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type instanceof AbstractList) {
|
||||||
|
$innerType = $type->getValueType();
|
||||||
|
$result = [];
|
||||||
|
foreach ($rawValue as $key => $value) {
|
||||||
|
$result[$key] = self::resolveTypedValue($value, $innerType);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type instanceof Boolean) {
|
||||||
|
return boolval($rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type instanceof Float_) {
|
||||||
|
return floatval($rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type instanceof Integer) {
|
||||||
|
return intval($rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type instanceof Object_) {
|
||||||
|
return self::constructObject($type->getFqsen()->__toString(), $rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rawValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function resolveValue(mixed $rawValue, ?Type $type, ReflectionParameter $reflection): mixed
|
||||||
|
{
|
||||||
|
if ($reflection->allowsNull() && is_null($rawValue)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($type)) {
|
||||||
|
$reflectedType = $reflection->getType();
|
||||||
|
if ($reflectedType instanceof ReflectionNamedType && $name = $reflectedType->getName()) {
|
||||||
|
return match ($name) {
|
||||||
|
'string' => $rawValue,
|
||||||
|
'bool' => boolval($rawValue),
|
||||||
|
'int' => intval($rawValue),
|
||||||
|
'float' => floatval($rawValue),
|
||||||
|
'array' => $rawValue,
|
||||||
|
default => self::constructObject($name, $rawValue),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return $rawValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::resolveTypedValue($rawValue, $type);
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/config/dto.php
Normal file
14
src/config/dto.php
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Icefox\DTO\Factories\CollectionFactory;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'rules' => [
|
||||||
|
Collection::class => CollectionFactory::rules(...),
|
||||||
|
],
|
||||||
|
'default' => [
|
||||||
|
'factories' => [
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
16
tests/Classes/ArrayDataObject.php
Normal file
16
tests/Classes/ArrayDataObject.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Classes;
|
||||||
|
|
||||||
|
use Icefox\DTO\DataObject;
|
||||||
|
|
||||||
|
readonly class ArrayDataObject
|
||||||
|
{
|
||||||
|
use DataObject;
|
||||||
|
/**
|
||||||
|
* @param array<int,int> $values
|
||||||
|
*/
|
||||||
|
public function __construct(public array $values) {}
|
||||||
|
}
|
||||||
22
tests/Classes/CarbonPeriodMapper.php
Normal file
22
tests/Classes/CarbonPeriodMapper.php
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Classes;
|
||||||
|
|
||||||
|
use Carbon\CarbonPeriodImmutable;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
|
class CarbonPeriodMapper
|
||||||
|
{
|
||||||
|
public function map(mixed $value): CarbonPeriodImmutable
|
||||||
|
{
|
||||||
|
return new CarbonPeriodImmutable(Carbon::parse($value['start']), Carbon::parse($value['end']));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'start' => ['required', 'date'],
|
||||||
|
'end' => ['required', 'date'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
17
tests/Classes/CollectionDataObject.php
Normal file
17
tests/Classes/CollectionDataObject.php
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Classes;
|
||||||
|
|
||||||
|
use Icefox\DTO\DataObject;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
readonly class CollectionDataObject
|
||||||
|
{
|
||||||
|
use DataObject;
|
||||||
|
/**
|
||||||
|
* @param Collection<OptionalNullableData> $values
|
||||||
|
*/
|
||||||
|
public function __construct(public Collection $values) {}
|
||||||
|
}
|
||||||
19
tests/Classes/FromInputObject.php
Normal file
19
tests/Classes/FromInputObject.php
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Classes;
|
||||||
|
|
||||||
|
use Icefox\DTO\Attributes\FromInput;
|
||||||
|
use Icefox\DTO\DataObject;
|
||||||
|
|
||||||
|
readonly class FromInputObject
|
||||||
|
{
|
||||||
|
use DataObject;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
#[FromInput('other_name')]
|
||||||
|
public string $text,
|
||||||
|
public int $standard,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
17
tests/Classes/ObjectWithoutMapper.php
Normal file
17
tests/Classes/ObjectWithoutMapper.php
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Classes;
|
||||||
|
|
||||||
|
use Icefox\DTO\DataObject;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
|
readonly class ObjectWithoutMapper
|
||||||
|
{
|
||||||
|
use DataObject;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public Carbon $date,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
19
tests/Classes/OptionalData.php
Normal file
19
tests/Classes/OptionalData.php
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Classes;
|
||||||
|
|
||||||
|
use Icefox\DTO\DataObject;
|
||||||
|
|
||||||
|
readonly class OptionalData
|
||||||
|
{
|
||||||
|
use DataObject;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public string $string = 'xyz',
|
||||||
|
public float $float = 0.777,
|
||||||
|
public int $int = 3,
|
||||||
|
public bool $bool = false,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
19
tests/Classes/OptionalNullableData.php
Normal file
19
tests/Classes/OptionalNullableData.php
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Classes;
|
||||||
|
|
||||||
|
use Icefox\DTO\DataObject;
|
||||||
|
|
||||||
|
readonly class OptionalNullableData
|
||||||
|
{
|
||||||
|
use DataObject;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public string $string,
|
||||||
|
public ?int $int,
|
||||||
|
public float $float = 0.999,
|
||||||
|
public bool $bool = false,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
19
tests/Classes/PrimitiveData.php
Normal file
19
tests/Classes/PrimitiveData.php
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Classes;
|
||||||
|
|
||||||
|
use Icefox\DTO\DataObject;
|
||||||
|
|
||||||
|
readonly class PrimitiveData
|
||||||
|
{
|
||||||
|
use DataObject;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public string $string,
|
||||||
|
public int $int,
|
||||||
|
public float $float,
|
||||||
|
public bool $bool,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
17
tests/Classes/RecursiveDataObject.php
Normal file
17
tests/Classes/RecursiveDataObject.php
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Classes;
|
||||||
|
|
||||||
|
use Icefox\DTO\DataObject;
|
||||||
|
|
||||||
|
readonly class RecursiveDataObject
|
||||||
|
{
|
||||||
|
use DataObject;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public string $string,
|
||||||
|
public PrimitiveData $extra,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
19
tests/Classes/WithMapperObject.php
Normal file
19
tests/Classes/WithMapperObject.php
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Classes;
|
||||||
|
|
||||||
|
use Carbon\CarbonPeriodImmutable;
|
||||||
|
use Icefox\DTO\Attributes\FromMapper;
|
||||||
|
use Icefox\DTO\DataObject;
|
||||||
|
|
||||||
|
readonly class WithMapperObject
|
||||||
|
{
|
||||||
|
use DataObject;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
#[FromMapper(CarbonPeriodMapper::class)]
|
||||||
|
public CarbonPeriodImmutable $period,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
7
workbench/bootstrap/app.php
Normal file
7
workbench/bootstrap/app.php
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Application;
|
||||||
|
|
||||||
|
use function Orchestra\Testbench\default_skeleton_path;
|
||||||
|
|
||||||
|
return Application::configure(basePath: $APP_BASE_PATH ?? default_skeleton_path())->create();
|
||||||
Loading…
Add table
Add a link
Reference in a new issue