Initial Commit
This commit is contained in:
commit
88b5850c32
12 changed files with 11441 additions and 0 deletions
111
src/DataObject.php
Normal file
111
src/DataObject.php
Normal 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]);
|
||||
}
|
||||
}
|
||||
55
src/DataObjectServiceProvider.php
Normal file
55
src/DataObjectServiceProvider.php
Normal 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
14
src/ParameterMeta.php
Normal 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,
|
||||
) {}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue