BaseModel
The BaseModel class is an abstract base class that implements the ObjectCopyInterface and provides basic functionality for model objects.
Overview
This class:
- Implements
ObjectCopyInterfaceusing theObjectCopyTrait - Provides a constructor that can initialize the object from a source
- Includes a
toArray()method for easy array conversion
Usage
To create a model class:
use ByJG\Serializer\BaseModel;
class User extends BaseModel
{
public $id;
public $name;
public $email;
// Inherits copyFrom(), copyTo(), and toArray() methods
}
Constructor
The BaseModel constructor can initialize the object from a source and apply property transformations during construction:
/**
* Create a BaseModel that implements ObjectCopyInterface and toArray() method
*
* @param array|object|null $object The source object to copy properties from
* @param PropertyHandlerInterface|null $propertyHandler Property handling interface
*/
public function __construct(array|object|null $object = null, ?PropertyHandlerInterface $propertyHandler = null)
Parameters
$object (array|object|null)
- The source data to initialize the model with
- Can be an array, object, or null
- If null, creates an empty model
- Properties are copied using ObjectCopy
$propertyHandler (PropertyHandlerInterface|null)
- Optional property handler to transform property names and values during initialization
- Useful for converting between naming conventions (e.g., snake_case to camelCase)
- See Property Handlers documentation for details
Basic Usage
Creating an empty model:
class User extends BaseModel {
public $id;
public $name;
public $email;
}
// Empty model
$user = new User();
Initializing from an array:
// Initialize with data
$user = new User([
'id' => 1,
'name' => 'John Doe',
'email' => '[email protected]'
]);
// Properties are automatically set:
// $user->id = 1
// $user->name = 'John Doe'
// $user->email = '[email protected]'
Initializing from another object:
$stdClass = new stdClass();
$stdClass->id = 1;
$stdClass->name = 'John Doe';
$stdClass->email = '[email protected]';
$user = new User($stdClass);
Using Property Handlers in Constructor
Converting snake_case to camelCase:
use ByJG\Serializer\PropertyHandler\SnakeToCamelCase;
class User extends BaseModel {
public $userId;
public $firstName;
public $lastName;
}
// Database row with snake_case
$dbRow = [
'user_id' => 1,
'first_name' => 'John',
'last_name' => 'Doe'
];
// Convert during construction
$user = new User($dbRow, new SnakeToCamelCase());
// Result:
// $user->userId = 1
// $user->firstName = 'John'
// $user->lastName = 'Doe'
Applying value transformations:
use ByJG\Serializer\PropertyHandler\DirectTransform;
class User extends BaseModel {
public $name;
public $email;
public DateTime $createdAt;
}
// Value handler to transform data during construction
$valueHandler = function ($prop, $target, $value, $instance) {
if ($target === 'createdAt' && is_string($value)) {
return new DateTime($value);
}
if ($target === 'email' && is_string($value)) {
return strtolower(trim($value));
}
return $value;
};
$data = [
'name' => 'John Doe',
'email' => ' [email protected] ',
'createdAt' => '2024-01-01 12:00:00'
];
$user = new User($data, new DirectTransform($valueHandler));
For detailed information about value handler parameters and advanced transformation patterns, see the Property Handlers Guide - Value Handler Parameters.
Mapping custom field names:
use ByJG\Serializer\PropertyHandler\PropertyNameMapper;
class User extends BaseModel {
public $id;
public $fullName;
public $emailAddress;
}
$apiResponse = [
'user_id' => 1,
'display_name' => 'John Doe',
'contact_email' => '[email protected]'
];
$mapper = new PropertyNameMapper([
'user_id' => 'id',
'display_name' => 'fullName',
'contact_email' => 'emailAddress'
]);
$user = new User($apiResponse, $mapper);
// Result:
// $user->id = 1
// $user->fullName = 'John Doe'
// $user->emailAddress = '[email protected]'
Constructor vs copyFrom()
The constructor and copyFrom() method are similar but have different use cases:
Constructor - Use when:
- Creating a new instance and initializing it immediately
- Working with immutable-style objects
- Building objects from API responses or database rows
// Constructor approach
$user = new User($data, $handler);
copyFrom() - Use when:
- Updating an existing instance
- Reusing an object instance
- Separating object creation from data population
// copyFrom approach
$user = new User();
// ... do other setup ...
$user->copyFrom($data, $handler);
toArray() Method
The BaseModel includes a toArray() method for easy serialization:
$user = new User([
'id' => 1,
'name' => 'John Doe',
'email' => '[email protected]'
]);
$array = $user->toArray();
// Returns: ['id' => 1, 'name' => 'John Doe', 'email' => '[email protected]']
The toArray() method uses the Serialize class internally, which:
- Calls getter methods if available
- Accesses public properties
- Handles nested objects recursively
- Respects property visibility rules
Advanced Example: API DTO
use ByJG\Serializer\BaseModel;
use ByJG\Serializer\PropertyHandler\SnakeToCamelCase;
class UserDTO extends BaseModel {
public int $userId;
public string $firstName;
public string $lastName;
public string $email;
public DateTime $createdAt;
public static function fromApiResponse(array $response): self {
$valueHandler = function ($prop, $target, $value, $instance) {
if ($target === 'createdAt' && is_string($value)) {
return new DateTime($value);
}
if ($target === 'email') {
return strtolower($value);
}
return $value;
};
return new self($response, new SnakeToCamelCase($valueHandler));
}
public function toApiResponse(): array {
$data = $this->toArray();
// Format DateTime for API
if (isset($data['createdAt']) && $data['createdAt'] instanceof DateTime) {
$data['createdAt'] = $data['createdAt']->format('c');
}
return $data;
}
}
// Usage
$apiData = [
'user_id' => 1,
'first_name' => 'John',
'last_name' => 'Doe',
'email' => '[email protected]',
'created_at' => '2024-01-01T12:00:00+00:00'
];
$dto = UserDTO::fromApiResponse($apiData);
$response = $dto->toApiResponse();
The BaseModel provides all the functionality of ObjectCopyTrait, plus additional convenience features.
Benefits of using BaseModel
- Ready-to-use base class: Includes common functionality needed for model objects
- Object copying: Built-in support for copying properties from/to other objects
- Array conversion: Easy conversion to arrays with the
toArray()method - Initialization from source: Constructor can initialize the object from various sources
When to use BaseModel vs. ObjectCopyTrait
- Use
BaseModelwhen you need a complete base model class with additional utility methods - Use
ObjectCopyTraitdirectly when you need to add copy functionality to a class that already extends another class
Related Components
- ObjectCopyInterface - Interface implemented by this class
- ObjectCopyTrait - Trait used by this class
- ObjectCopy - Utility class for property copying