How to use?¶
Using jetcod/data-transport is a straightforward process. You can create customized data object classes by extending JetcodDataTransportAbstractDTO. Here’s how to initialize and work with these classes:
Creating a Custom DTO¶
Begin by creating a custom data object class that extends AbstractDTO. This class will serve as the blueprint for your data objects.
<?php
namespace App\DTO;
use Jetcod\DataTransport\AbstractDTO;
class Student extends AbstractDTO
{
}
Initializing Your Data Object¶
There are two primary methods to initialize your data object with data: using the constructor or assigning values to individual attributes.
Using the Constructor¶
Import your custom data object class:
<?php
use App\DTO\Student;
// ...
Construct your data object and inject an array of data into it:
<?php
$data = [
'name' => 'John Doe',
'email' => 'john.doe@example.com',
];
$dto = new \App\DTO\Student($data);
Utilizing the Make Function¶
In addition to the traditional constructor method, you can also utilize the convenient make function to create instances of your data object class. The make function simplifies the initialization process and provides an alternative way to create objects.
<?php
$data = [
'name' => 'John Doe',
'email' => 'john.doe@example.com',
];
$dto = \App\DTO\Student::make($data);
Assigning Values¶
Import your custom data object class:
<?php
use App\DTO\Student;
// ...
Create an instance of your data object:
<?php
$dto = new \App\DTO\Student();
// Assign values to individual attributes
$dto->name = "John Doe";
$dto->email = 'john.doe@example.com';
Checking attribute existance¶
The has() function serves the purpose of verifying the presence of a specified key within the data of the DTO class. It returns a boolean value indicating the result of this check.
Its behavior closely resembles that of the PHP built-in function isset(). For instance, if you have an object like this:
<?php
$student = new Student([
'first_name' => 'John',
'last_name' => 'Doe',
'email' => 'john.doe@example.com'
]);
Both functions will yield the same result:
isset($student->email); // Returns true
isset($student->phone); // Returns false
Alternatively, you can achieve the same outcome using the has() function:
$student->has('email'); // Returns true
$student->has('phone'); // Returns false
In essence, has() offers a convenient way to perform existence checks within the DTO class data, paralleling the functionality of isset().
Read-only Object¶
Starting from version 1.3.0, DTOs can be instantiated in read-only mode. This ensures that once created, their attributes cannot be modified, providing an extra layer of immutability and data integrity.
Usage¶
You can enable read-only mode by passing true as the second parameter when constructing the DTO:
<?php
use App\DTOs\Student;
$dto = new Student([
'fullname' => 'John Doe',
'email' => 'john.doe@example.com',
], true); // 👈 read-only enabled
Behavior¶
When a DTO is read-only:
Attempting to set a new attribute will throw a ValidationException.
Attempting to update an existing attribute will also throw a ValidationException.
Object Validation¶
Starting from version 1.3.0, DTOs can now be validated directly using built-in or custom validators. This allows developers to ensure that DTO attributes comply with their defined schema before using or persisting the object.
Defining Validation Rules¶
To enable validation for your DTO, use the HasValidator trait and define your validation rules in the getSchema() method. The keys represent attribute names, and the values define their validation type or rule.
<?php
use Jetcod\DataTransport\AbstractDTO;
use Jetcod\DataTransport\Contracts\TypedEntity;
use Jetcod\DataTransport\Traits\HasValidator;
class Product extends AbstractDTO implements TypedEntity
{
use HasValidator;
public function getSchema(): array
{
return [
'name' => 'string',
'price' => 'numeric',
'sku' => 'string',
'inStock' => 'boolean',
'category_id' => 'numeric',
];
}
}
Validating the DTO¶
You can validate the object using the validate() method. It returns a validator result object that contains the validation outcome and any errors found.
<?php
$product = new Product([
'name' => 'Wireless Keyboard',
'price' => '39.90',
'sku' => 12345, // invalid: should be string
'inStock' => true,
'category_id' => 'electronics', // invalid: should be numeric
]);
$validation = $product->validate();
if (!$validation->isValid()) {
dump($validation->errors());
}
Output:
[
'sku' => ['The sku must be a string.'],
'category_id' => ['The category_id must be numeric.'],
]
Built-in Validators¶
The following validation types are supported out of the box:
Type | Description |
---|---|
string | Ensures the value is a string. |
numeric | Ensures the value is numeric. |
int | Ensures the value is integer. |
float | Ensures the value is float. |
boolean | Ensures the value is boolean. |
array | Ensures the value is an array. |
Ensures the value is a valid email address. | |
url | Ensures the value is a valid url. |
Custom Validators¶
Custom validators allow you to define your own validation logic beyond the built-in types. Use custom validators when you need to enforce specific rules or complex validation that cannot be handled by simple type checks.
To create a custom validator, implement the ValidatorInterface, which requires three methods:
validate(mixed $value): bool — Returns true if the value passes validation, false otherwise.
getError(): string — Returns the error message to be used if validation fails.
alias(): string — Returns a string alias for the validator, used for identification.
Here is an example of a custom validator class:
<?php
use Jetcod\DataTransport\Contracts\ValidatorInterface;
class CustomValidator implements ValidatorInterface
{
public function validate($value): bool
{
// Custom validation logic, e.g., check department code format
return is_string($value) && preg_match('/^[A-Z]{2,3}-\d{2}$/', $value);
}
public function getError(): string
{
return 'The department code must follow the format ABC-12 (2–3 uppercase letters, a dash, and 2 digits).';
}
public function alias(): string
{
return 'custom_validator'; // This only works for built-in validators. It cane be left as empty string.
}
}
You can then use this custom validator inside a DTO’s getSchema() method like this:
<?php
use Jetcod\DataTransport\AbstractDTO;
use Jetcod\DataTransport\Contracts\TypedEntity;
use Jetcod\DataTransport\Traits\HasValidator;
class Employee extends AbstractDTO implements TypedEntity
{
use HasValidator;
public function getSchema(): array
{
return [
'firstName' => 'string',
'email' => 'email',
'roomNo' => 'numeric',
'departmentCode' => CustomValidator::class
];
}
}
When a value fails the custom validation, the DTO will use the error message provided by the custom validator’s getError() method to report the validation failure.
Strict Mode Validation¶
DTOs support Strict Mode which automatically validates the data during object initialization. When strict mode is enabled, any validation failure immediately throws a ValidationException, preventing the creation of invalid DTO instances.
Usage¶
Strict mode can be activated by passing true as the third constructor argument:
<?php
use App\DataObjects\Employee;
// Example: strict mode enabled
$employee = new Employee([
'firstName' => null,
'email' => 'john.doe@example.com',
], false, true);
// ❌ Throws ValidationException:
// "The firstName must be a string."
In the example above:
The second parameter (false) indicates that the DTO is not read-only.
The third parameter (true) activates strict mode validation.
Because firstName is invalid (null instead of string), the constructor immediately throws a ValidationException.
Behavior¶
When strict mode is active:
Validation runs automatically during object creation.
If any attribute fails its validation rule, a ValidationException is thrown with the detailed validation errors.
The DTO will not be created if validation fails.
This behavior ensures data consistency and integrity at the moment of object instantiation.
Note: Strict mode is especially useful in critical data layers where invalid data should never enter your application’s flow.