Initial Commit

This commit is contained in:
icefox 2026-02-18 19:06:59 -03:00
commit 88b5850c32
No known key found for this signature in database
12 changed files with 11441 additions and 0 deletions

111
src/DataObject.php Normal file
View file

@ -0,0 +1,111 @@
<?php
declare(strict_types=1);
namespace Icefox\DTO;
use Icefox\DTO\Attributes\FromInput;
use Icefox\DTO\Attributes\FromMapper;
use Icefox\DTO\Attributes\FromRouteParameter;
use Icefox\DTO\Support\RuleFactory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
use Illuminate\Validation\Validator;
use ReflectionClass;
use phpDocumentor\Reflection\DocBlock\Tags\Param;
trait DataObject
{
public static function fromRequest(Request $request): mixed
{
$reflection = new ReflectionClass(static::class);
$constructor = $reflection->getConstructor();
$input = [];
foreach ($constructor->getParameters() as $parameter) {
$parameterName = $parameter->getName();
foreach ($parameter->getAttributes(FromRouteParameter::class) as $attr) {
$name = $attr->newInstance()->name;
if ($value = $request->input($name, null)) {
$input[$parameterName] = $value;
continue 2;
}
}
}
return static::fromArray($input);
}
/**
* @param array<int,mixed> $input
*/
public static function fromArray(array $input): static
{
$parameters = RuleFactory::getParametersMeta(static::class);
foreach ($parameters as $parameter) {
$parameterName = $parameter->reflection->getName();
foreach ($parameter->reflection->getAttributes(FromInput::class) as $attr) {
if ($value = $input[$attr->newInstance()->name] ?? null) {
$input[$parameterName] = $value;
continue 2;
}
}
if ($value = $input[$parameterName] ?? null) {
$input[$parameterName] = $value;
continue;
}
if ($parameter->reflection->isDefaultValueAvailable()) {
$input[$parameterName] = $parameter->reflection->getDefaultValue();
continue;
}
}
$rules = RuleFactory::buildRules($parameters, '');
$validator = static::withValidator($input, $rules);
if ($validator->fails()) {
$exception = new ValidationException($validator);
throw $exception;
}
$mappedInput = [];
foreach ($parameters as $parameter) {
$parameterName = $parameter->reflection->getName();
if ($mapper = array_first($parameter->reflection->getAttributes(FromMapper::class))) {
$value = App::call(
[App::make($mapper->newInstance()->class), 'map'],
['value' => $validator->getValue($parameterName)],
);
$mappedInput[$parameterName] = $value;
continue;
}
$mappedInput[$parameterName] = RuleFactory::resolveValue(
$validator->getValue($parameterName),
$parameter->tag instanceof Param ? $parameter->tag->getType() : null,
$parameter->reflection,
);
}
return App::make(static::class, $mappedInput);
}
public static function rules(): array
{
return [];
}
/**
* @param array<int,mixed> $data
* @param array<int,string|Rule> $rules
*/
public static function withValidator(array $data, array $rules): Validator
{
return App::makeWith(Validator::class, ['data' => $data, 'rules' => $rules]);
}
}

View file

@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace Icefox\DTO;
use Icefox\DTO\Support\DataObjectRegistrar;
use Illuminate\Support\ServiceProvider;
class DataObjectServiceProvider extends ServiceProvider
{
/**
* Register services.
*/
public function register(): void
{
$this->mergeConfigFrom(__DIR__ . '/config/dto.php', 'dto');
$registrar = new DataObjectRegistrar($this->app);
// Register from configured namespaces or manual class list
$config = $this->getConfig();
if (!empty($config['classes'])) {
// Manual registration (zero overhead)
$registrar->registerMany($config['classes']);
} elseif (!empty($config['namespaces'])) {
// Automatic namespace scanning
$registrar->registerFromNamespaces($config['namespaces']);
}
}
/**
* Bootstrap services.
*/
public function boot(): void
{
// Commands will be registered here
}
/**
* Get DataObject configuration.
*
* @return array{namespaces: string[], classes: class-string[]}
*/
protected function getConfig(): array
{
return config('dataobject', [
'namespaces' => [
'App\DataObjects',
],
'classes' => [],
]);
}
}

14
src/ParameterMeta.php Normal file
View file

@ -0,0 +1,14 @@
<?php
namespace Icefox\DTO;
use ReflectionParameter;
use phpDocumentor\Reflection\DocBlock\Tags\Param;
readonly class ParameterMeta
{
public function __construct(
public ReflectionParameter $reflection,
public ?Param $tag,
) {}
}