@vladimir_dekster

Как сделать опциональные поля в DTO?

В проекте на Laravel использую DTO. Нужно обновить модель пользователя, но в реквесте могут прийти не полные данные, тогда выкидывается ошибка Too few arguments, потому что в методе fromRequest не хватает аргументов при разворачивании ...$request->validated(), а сделать поле null по умолчанию нельзя. Как это поправить?

DTO
abstract readonly class DTO
{
    public function toArray(): array
    {
        return get_object_vars($this);
    }

    public static function fromRequest(FormRequest $request): static
    {
        return new static(...$request->validated());
    }
}

final readonly class UpdateUserDTO extends DTO
{
    public function __construct(
        public ?string $name,
        public ?string $email,
    ) {
    }
}


UpdateUserRequest
class UpdateUserRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'name' => ['string', 'max:255'],
            'email' => ['string', 'max:255', 'email', 'unique:users'],
        ];
    }
}


UserController
final class UserController extends Controller
{
    public function update(int $userId, UpdateUserRequest $request): UserResource
    {
        return UserResource::make(
            $this->userService->update($userId, UpdateUserDTO::fromRequest($request))
        );
    }
}


UserService
final class UserService
{
    public function update(int $userId, UpdateUserDTO $userDTO): User
    {
        $user = User::findOrFail($userId);

        $user->update([
            'name' => $userDTO->name,
            'email' => $userDTO->email,
        ]);

        return $user;
    }
}
  • Вопрос задан
  • 370 просмотров
Пригласить эксперта
Ответы на вопрос 3
delphinpro
@delphinpro Куратор тега PHP
frontend developer
ну как вариант в методе prepareForValidation() форм-реквеста заполнять недостающие поля нулями
Ответ написан
Комментировать
@iljaGolubev
Не уверен, что правильно понял вопрос, но если ?string $name = null нельзя, то проще всего изменить fromRequest
public static function fromRequest(FormRequest $request): static
    {
        $v = $request->validated()
        return new static($v['name']??null, $v['email']??null);
    }


Ещё вопрос почему нельзя ?string $name = null.
UserService->update что должен записать если с формы ничего не пришло? Null? Пустую строку? Ну так почему бы не отразить это в ваших классах?

Но вообще, излишне сложно как-то. Всё же в ларавель столько всего накручено уже, что писать ещё вокруг что-то - чаще всего дублировать функционал.
// кмк так проще и понятнее
final class UserController extends Controller
{
    public function update(int $userId, UpdateUserRequest $request): UserResource
    {
       $valid = $request->validated();
       $user = User::findOrFail($userId);
       $user->update([
            'name' => $valid['name'] ?? "xyz"
            'email' => $valid['name'] ?? "null or not",
        ]);
      return new UserResource($user);
    }
}
Ответ написан
Комментировать
iMedved2009
@iMedved2009
Не люблю людей
Как то так?
public static function fromRequest(FormRequest $request): static
    {
        $data = $request->validated();
        $properties = (new \ReflectionClass(self::class))->getProperties(\ReflectionProperty::IS_PUBLIC);
        foreach ($properties as $property){
            if(!isset($data[$property->name])){
                   $data[$property->name] = $property->getDefaultValue();
            }
        }
        return new static(...$data);
    }
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы