spatie/value-object
Deprecated Spatie package for PHP 8+ data transfer objects. Create typed DTOs from arrays with casting, validation, and attribute mapping (e.g., nested keys). Consider migrating to spatie/laravel-data or cuyz/valinor.
Installation:
composer require spatie/data-transfer-object
(Note: Requires PHP 8.0+ for v3. For older versions, use v2.)
Define a DTO:
use Spatie\DataTransferObject\DataTransferObject;
class UserDto extends DataTransferObject
{
public string $name;
public int $age;
}
Instantiate and Use:
$dto = UserDto::from([
'name' => 'John Doe',
'age' => 30,
]);
echo $dto->name; // "John Doe"
$dto = UserDto::from(request()->all());
if ($dto->age < 18) {
abort(400, 'User must be at least 18 years old.');
}
DTO Creation:
DataTransferObject and define properties.from(array) to populate from associative arrays (e.g., API requests, database rows).fromJson(string) for JSON payloads.Validation:
string $name enforces strings).rules() or validate() methods (if extending further).if (!$dto->validate()) {
throw new \InvalidArgumentException($dto->errors()->first());
}
Transformation:
$user = User::find(1);
$dto = UserDto::from($user->toArray());
Immutable Data:
hydrate(array) to create mutable copies if needed.Nested DTOs:
class AddressDto extends DataTransferObject {
public string $street;
public string $city;
}
class UserDto extends DataTransferObject {
public string $name;
public AddressDto $address;
}
API Layer:
public function store(Request $request) {
$dto = UserDto::from($request->validated());
// Process $dto...
}
Service Layer:
$service->process(UserDto::from($request->all()));
Testing:
$dto = new UserDto();
$dto->name = 'Test User';
$this->assertEquals('Test User', $dto->name);
Database Seeding:
User::create(UserDto::from([
'name' => 'Admin',
'email' => 'admin@example.com',
'roles' => ['admin', 'editor'],
])->toArray());
Immutability:
$dto = new UserDto();
$dto->name = 'John'; // Throws Error!
from() or hydrate() to create new instances.Type Safety:
is_string()) are not.assert() or custom validation for critical fields:
assert(is_string($dto->name), 'Name must be a string!');
Nested DTO Initialization:
from() or constructor args.$dto = UserDto::from([
'address' => ['street' => '123 Main'] // Fails if AddressDto expects strict typing.
]);
Magic Methods:
__get() and __set(). Overriding these breaks hydration.Deprecation Warning:
spatie/laravel-data or cuyz/valinor for long-term projects.Validation Errors:
$dto->errors() to inspect validation failures:
$dto = UserDto::from(['name' => 123]);
$dto->validate(); // Fails
print_r($dto->errors()); // ['name' => 'Must be a string.']
Property Access:
Error (not UndefinedPropertyException).property_exists($dto, 'name') for safe checks.JSON Serialization:
JsonSerializable, but nested objects may not serialize as expected.JsonSerializable.Custom Validation:
class ValidatedUserDto extends DataTransferObject {
public string $name;
public int $age;
public function rules(): array {
return [
'name' => 'required|string|min:2',
'age' => 'integer|min:18',
];
}
}
Mass Assignment Protection:
fillable property to whitelist allowed fields:
class UserDto extends DataTransferObject {
public string $name;
public string $email;
protected array $fillable = ['name', 'email'];
}
Performance:
IDE Support:
includes:
- vendor/spatie/data-transfer-object/src/DataTransferObject.php
Migration Path:
spatie/laravel-data, note key differences:
->address vs. ->addressDto).How can I help you explore Laravel packages today?