Dot Notation Access
SimpleDTO provides powerful get() and set() methods that allow you to access and modify nested DTO properties using dot notation. This makes working with complex, nested data structures much easier.
Features
Section titled “Features”The get() and set() methods support:
- Dot notation for nested property access (
user.address.city) - Wildcards for array operations (
emails.*.email) - Multi-level nesting with wildcards (
employees.*.orders.*.total) - Default values for missing properties
- Immutability -
set()returns a new DTO instance
The get() Method
Section titled “The get() Method”The get() method allows you to retrieve values from your DTO using dot notation.
Basic Usage
Section titled “Basic Usage”use event4u\DataHelpers\SimpleDTO;
class UserDTO extends SimpleDTO{ public function __construct( public readonly string $name, public readonly string $email, public readonly int $age, ) {}}
$user = new UserDTO( name: 'John Doe', email: 'john@example.com', age: 30);
// Get simple property$name = $user->get('name'); // 'John Doe'$email = $user->get('email'); // 'john@example.com'Default Values
Section titled “Default Values”You can provide a default value as the second parameter:
// Returns default if property doesn't exist$phone = $user->get('phone', 'N/A'); // 'N/A'$country = $user->get('address.country', 'Unknown'); // 'Unknown'Nested Properties
Section titled “Nested Properties”Access nested DTO properties using dot notation:
class AddressDTO extends SimpleDTO{ public function __construct( public readonly string $street, public readonly string $city, public readonly string $country, ) {}}
class UserDTO extends SimpleDTO{ public function __construct( public readonly string $name, public readonly AddressDTO $address, ) {}}
$user = new UserDTO( name: 'John Doe', address: new AddressDTO( street: 'Main St', city: 'New York', country: 'USA' ));
// Access nested properties$city = $user->get('address.city'); // 'New York'$country = $user->get('address.country'); // 'USA'Array Properties with Wildcards
Section titled “Array Properties with Wildcards”Use wildcards (*) to access values from arrays:
class EmailDTO extends SimpleDTO{ public function __construct( public readonly string $email, public readonly string $type, public readonly bool $verified = false, ) {}}
class UserDTO extends SimpleDTO{ /** * @param array<int, EmailDTO> $emails */ public function __construct( public readonly string $name, public readonly array $emails, ) {}}
$user = new UserDTO( name: 'John Doe', emails: [ new EmailDTO(email: 'john@work.com', type: 'work', verified: true), new EmailDTO(email: 'john@home.com', type: 'home', verified: false), ]);
// Get all email addresses$addresses = $user->get('emails.*.email');// ['john@work.com', 'john@home.com']
// Get all verified flags$verified = $user->get('emails.*.verified');// [true, false]Multi-Level Wildcards
Section titled “Multi-Level Wildcards”Combine multiple wildcards for deeply nested structures:
class OrderDTO extends SimpleDTO{ public function __construct( public readonly int $id, public readonly float $total, public readonly string $status, ) {}}
class EmployeeDTO extends SimpleDTO{ /** * @param array<int, EmailDTO> $emails * @param array<int, OrderDTO> $orders */ public function __construct( public readonly string $name, public readonly array $emails, public readonly array $orders, ) {}}
class DepartmentDTO extends SimpleDTO{ /** * @param array<int, EmployeeDTO> $employees */ public function __construct( public readonly string $name, public readonly array $employees, ) {}}
$department = new DepartmentDTO( name: 'Engineering', employees: [ new EmployeeDTO( name: 'Alice', emails: [ new EmailDTO(email: 'alice@work.com', type: 'work', verified: true), ], orders: [ new OrderDTO(id: 1, total: 100.50, status: 'pending'), new OrderDTO(id: 2, total: 250.00, status: 'shipped'), ] ), new EmployeeDTO( name: 'Bob', emails: [ new EmailDTO(email: 'bob@work.com', type: 'work', verified: false), ], orders: [ new OrderDTO(id: 3, total: 75.25, status: 'pending'), ] ), ]);
// Get all employee emails$allEmails = $department->get('employees.*.emails.*.email');// ['alice@work.com', 'bob@work.com']
// Get all order totals$allTotals = $department->get('employees.*.orders.*.total');// [100.50, 250.00, 75.25]
// Get all order statuses$allStatuses = $department->get('employees.*.orders.*.status');// ['pending', 'shipped', 'pending']The set() Method
Section titled “The set() Method”The set() method allows you to update DTO properties using dot notation. Since DTOs are immutable, set() returns a new instance with the updated value.
Basic Usage
Section titled “Basic Usage”$user = new UserDTO( name: 'John Doe', email: 'john@example.com', age: 30);
// Set simple property - returns new instance$updatedUser = $user->set('name', 'Jane Doe');
echo $user->name; // 'John Doe' (original unchanged)echo $updatedUser->name; // 'Jane Doe' (new instance)Nested Properties
Section titled “Nested Properties”Update nested DTO properties:
$user = new UserDTO( name: 'John Doe', address: new AddressDTO( street: 'Main St', city: 'New York', country: 'USA' ));
// Update nested property$updatedUser = $user->set('address.city', 'Los Angeles');
echo $user->get('address.city'); // 'New York' (original)echo $updatedUser->get('address.city'); // 'Los Angeles' (new)Array Properties with Wildcards
Section titled “Array Properties with Wildcards”Update all items in an array using wildcards:
$user = new UserDTO( name: 'John Doe', emails: [ new EmailDTO(email: 'john@work.com', type: 'work', verified: false), new EmailDTO(email: 'john@home.com', type: 'home', verified: false), ]);
// Verify all emails at once$updatedUser = $user->set('emails.*.verified', true);
$verified = $updatedUser->get('emails.*.verified');// [true, true] - all emails are now verifiedMulti-Level Wildcards
Section titled “Multi-Level Wildcards”Update deeply nested values:
$department = new DepartmentDTO( name: 'Sales', employees: [ new EmployeeDTO( name: 'Charlie', emails: [], orders: [ new OrderDTO(id: 1, total: 100.50, status: 'pending'), new OrderDTO(id: 2, total: 250.00, status: 'pending'), ] ), new EmployeeDTO( name: 'Diana', emails: [], orders: [ new OrderDTO(id: 3, total: 75.25, status: 'pending'), ] ), ]);
// Ship all orders at once$updated = $department->set('employees.*.orders.*.status', 'shipped');
$statuses = $updated->get('employees.*.orders.*.status');// ['shipped', 'shipped', 'shipped'] - all orders shippedChaining set() Calls
Section titled “Chaining set() Calls”Since set() returns a new instance, you can chain multiple calls:
$user = new UserDTO( name: 'John Doe', email: 'john@example.com', age: 30);
$updatedUser = $user ->set('name', 'Jane Doe') ->set('age', 25) ->set('email', 'jane@example.com');
// Original unchangedecho $user->name; // 'John Doe'
// New instance with all updatesecho $updatedUser->name; // 'Jane Doe'echo $updatedUser->age; // 25echo $updatedUser->email; // 'jane@example.com'Edge Cases
Section titled “Edge Cases”Non-Existent Paths
Section titled “Non-Existent Paths”$user = new UserDTO(name: 'John', email: 'john@example.com', age: 30);
// Returns null for non-existent paths$result = $user->get('nonexistent'); // null
// Use default value$result = $user->get('nonexistent', 'default'); // 'default'Empty Arrays
Section titled “Empty Arrays”$user = new UserDTO(name: 'John', emails: []);
// Wildcard on empty array returns empty array$emails = $user->get('emails.*.email'); // []
// Set on empty array returns unchanged DTO$updated = $user->set('emails.*.verified', true);// $updated->emails is still []Numeric Indices
Section titled “Numeric Indices”You can access array elements by numeric index:
$user = new UserDTO( name: 'John', emails: [ new EmailDTO(email: 'first@example.com', type: 'work', verified: false), new EmailDTO(email: 'second@example.com', type: 'home', verified: false), ]);
// Access by index$first = $user->get('emails.0.email'); // 'first@example.com'$second = $user->get('emails.1.email'); // 'second@example.com'
// Update by index$updated = $user->set('emails.0.verified', true);// Only first email is verifiedPerformance Considerations
Section titled “Performance Considerations”get()andset()use the underlyingDataAccessorandDataMutatorclasses- Both methods convert the DTO to an array recursively
set()creates a new DTO instance (immutability)- For bulk operations, consider using
DataMapperorDataMutatordirectly
See Also
Section titled “See Also”- Dot Notation - Core concept documentation
- Wildcards - Wildcard patterns
- DataAccessor - Low-level data access
- DataMutator - Low-level data mutation
- Nested DTOs - Working with nested structures