You do what feels right to you.
DTOs are only really beneficial when passing data between classes
I would not use one just to pass request data to an eloquent model (the model itself is the DTO)
But I would not use request->all() at all....
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
Hi,
I recently read spaties "beyond crud" blog post and everything from the folder structure, to the actions and state made sense to me, but the DTO's didn't.
If we look at this quote
"First of all: we already established that DTOs are the entry point for data into the codebase. As soon as we're working with data from the outside, we want to convert it to a DTO"
That tells me that all data (3rd party APIs, internal APIS, everything!) should use DTOs.
So when I build an API-first laravel app I usually do this :
UserController
<?php
class UserController extends Controller
{
public function store(StoreUserRequest $request)
{
$this->authorize('create', User::class);
return User::create($request->all());
}
}
But with DTOs, I feel like I just add a bunch of redundant code for no reason
UserController
<?php
class UserController extends Controller
{
public function store(StoreUserRequest $request)
{
$userData = tap(new UserData)->fromRequest($request);
$this->authorize('create', User::class);
return User::create($userData->toArray());
}
}
UserData DTO
<?php
namespace Domain\User\DTOs;
use Domain\User\Models\User;
use Illuminate\Http\Request;
use Spatie\DataTransferObject\DataTransferObject;
class UserData extends DataTransferObject
{
public string $email;
public bool $is_admin;
public bool $is_moderator;
public bool $is_worker;
public bool $is_active;
public string $name;
public ?string $phone;
public ?int $hourly_cost;
public function fromRequest(Request $request)
{
return new self([
'email' => $request->get('email'),
'is_admin' => $request->get('is_admin'),
'is_moderator' => $request->get('is_moderator'),
'is_worker' => $request->get('is_worker'),
'is_active' => $request->get('is_active'),
'name' => $request->get('name'),
'phone' => $request->get('phone'),
'hourly_cost' => $request->get('hourly_cost'),
]);
}
public function fromModel(User $user)
{
return new self([
'email' => $user->email,
'is_admin' => $user->is_admin,
'is_moderator' => $user->is_moderator,
'is_worker' => $user->is_worker,
'is_active' => $user->is_active,
'name' => $user->name,
'phone' => $user->phone,
'hourly_cost' => $user->hourly_cost,
]);
}
}
I can understand why using DTOs for external APIs are a good idea, but for my applications internal http requests that has an indirect relationship to to a model, I don't get it.
Here is how I compare them
DTO
Model
So when I want to add an attribute to my table, not only do I have to
I also have to add it to my DTO!?
"My point of view is that we should embrace the framework, instead of trying to fight it; though we should embrace it in such a way that large projects stay maintainable."
Taking this quote into account, DTOs on application is fighting the framework by adding redundant code.
I am confused, scared and sad. Can someone help me on this.
@enterusername I don’t like this proliferation of DTOs recently. It’s not what the design pattern was intended for. Data mappers exist for converting data from one representation (i.e. an third-party API) to another (i.e. your application’s internal models).
It’s just another case where Spatie have taken something and then every one’s jumped on the bandwagon (see: when Spatie re-christened command classes as “Actions” and then every Laravel developer started re-factoring everything in their apps to “actions” even though the pattern had existed for literally decades before).
Please or to participate in this conversation.