Here's a step-by-step example on how to create Data Transfer Objects (DTOs) using Laravel Data:
1. Install Laravel Data Package
To begin, install the spatie/laravel-data
package using Composer. This package helps in creating DTOs and managing data efficiently.
composer require spatie/laravel-data
2. Create a Data Transfer Object (DTO)
After installing the package, we can create a DTO class for handling data transfer. Suppose we have a User
entity, and we want to create a DTO for transferring user data.
Run the following Artisan command to generate a new DTO class:
php artisan make:data UserData
This will create a UserData
class inside the App/Data
directory.
3. Define Properties and Types in DTO
Now, let's edit the UserData
class to define the properties and data types you expect for your DTO.
namespace App\Data;
use Spatie\LaravelData\Data;
class UserData extends Data
{
public function __construct(
public string $name,
public string $email,
public string $address,
public ?string $phone = null // Optional phone field
) {}
}
Explanation:
- The
__construct
method automatically assigns the incoming values to the DTO properties. - The
?string $phone = null
indicates that thephone
property is optional.
4. Use DTO in a Controller
Now that the UserData
DTO is created, we can use it inside our controller to handle incoming data, transform it, and pass it between layers of the application.
namespace App\Http\Controllers;
use App\Data\UserData;
use App\Models\User;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function store(Request $request)
{
// Validate the incoming request data
$validatedData = $request->validate([
'name' => 'required|string',
'email' => 'required|email',
'address' => 'required|string',
'phone' => 'nullable|string',
]);
// Create a UserData DTO
$userData = UserData::from($validatedData);
// You can now access $userData->name, $userData->email, etc.
User::create([
'name' => $userData->name,
'email' => $userData->email,
'address' => $userData->address,
'phone' => $userData->phone,
]);
return response()->json(['message' => 'User created successfully']);
}
}
Explanation:
- The
UserData::from()
method automatically maps the validated request data into the DTO object. - The DTO object can now be used to transfer data between the controller and the model (or other layers of the application).
5. Transform Data Using DTO
You can use the DTO for transforming data when returning responses as well. Let's modify the show
method in the UserController
to return user data through the DTO.
public function show(User $user)
{
// Convert the User model to UserData DTO
$userData = new UserData(
name: $user->name,
email: $user->email,
address: $user->address,
phone: $user->phone
);
return response()->json($userData);
}
Explanation:
- Here, we manually create a
UserData
DTO by passing the User model’s properties into the DTO constructor. - This DTO can be returned directly as a JSON response, ensuring a structured data format.
6. DTO with Collections
If you are working with collections of data, like fetching a list of users, the DTO package provides a simple method to handle collections as well.
public function index()
{
$users = User::all();
// Convert the collection of User models to a collection of UserData DTOs
$userCollection = UserData::collection($users);
return response()->json($userCollection);
}
Explanation:
- The
UserData::collection($users)
method maps eachUser
model to theUserData
DTO, transforming the entire collection into a list of DTOs.
7. Customize Data Transformation
The spatie/laravel-data
package allows customization of the transformation, for example, renaming attributes or adding computed fields.
class UserData extends Data
{
public function __construct(
public string $name,
public string $email,
public string $address,
public ?string $phone = null
) {}
// Add a custom method to compute a full contact string
public function fullContact(): string
{
return "{$this->name} ({$this->email})";
}
}
Now, you can use fullContact()
to get a custom formatted string when working with this DTO.
8. Data Validation and DTOs
You can add validation rules directly in the DTO using Laravel Data’s Rules
feature.
namespace App\Data;
use Spatie\LaravelData\Attributes\Validation\Email;
use Spatie\LaravelData\Attributes\Validation\Required;
use Spatie\LaravelData\Data;
class UserData extends Data
{
public function __construct(
#[Required] public string $name,
#[Email] public string $email,
public string $address,
public ?string $phone = null
) {}
}
Explanation:
- With validation attributes like
#[Required]
and#[Email]
, you can enforce validation directly on the DTO level, streamlining the process even further.
Conclusion
In this hands-on tutorial, we explored how to create and use Data Transfer Objects (DTOs) using Laravel Data. With the DTO pattern, you can cleanly manage and transform your data, ensuring separation of concerns between your application's layers, while making code easier to maintain. The spatie/laravel-data
package simplifies DTO management, offering easy-to-use features for both developers and large-scale applications.
Top comments (1)
Very nice