My needs are to manage DTO in a php5.3 application. I've written few lines of code in TDD with phpunit 6. The scenario I want to implement is a request with following fields:
- name
- surname
password
alias
email
address
- civic_number
- country
And I need to create DTO's with
- credentials
- info
- address
Provide DTO properties
Each DTO should provide its own properties.
public function testProvideDtoPropertyNames()
{
$propertyNames = Person::getPropertyNames();
$expectedProperties = array(
'name',
'surname',
);
$this->assertEquals(
$expectedProperties,
$propertyNames
);
}
Getters
I also want that all properties are available via getters:
public function testProvidePropertyViaGeneralGetter()
{
$dto = Person::createFromArray(array(
'name' => 'Simone',
));
$this->assertEquals(
'Simone',
$dto->get('name')
);
}
Filtering
The main purpose here is to filter all fields and just keep consideration of the DTO's properties:
public function testDTOAcceptOnlyItsOwnProperties()
{
$dto = Person::createFromArray(array(
'name' => 'Simone',
'sfadfsa' => 'Simone',
));
$expectedProperties = array(
'name' => 'Simone',
'surname' => null,
);
$this->assertEquals(
$expectedProperties,
$dto->asArray()
);
}
Serialization
Serializing and un serializing I want that my code works fine and without side effect.
public function testSerializationKeepSameProperties()
{
$dto = Person::createFromArray(array(
'name' => 'Simone',
'surname' => 'Gentili',
'sadfasdrname' => 'Gentili',
));
$serialized = serialize($dto);
$unserialized = unserialize($serialized);
$this->assertEquals(
$dto->asArray(),
$unserialized->asArray()
);
$this->assertEquals(
array(
'name' => 'Simone',
'surname' => 'Gentili',
),
$unserialized->asArray()
);
}
Are those tests good? I hope yes but any suggestions are welcome.
Finally, ... the code:
A DTO can be easily done with a simple class with public properties:
class Person extends Dto
{
public $name;
public $surname;
}
Here the production code:
abstract class Dto
{
private $properties;
private function __construct(array $properties)
{
$this->properties = $properties;
}
public static function createFromArray($properties)
{
return new static($properties);
}
public function set($propertyName, $propertyValue)
{
$this->$propertyName = $propertyValue;
}
public function get($propertyName)
{
return isset($this->properties[$propertyName])
? $this->properties[$propertyName]
: null;
}
public static function getPropertyNames()
{
$reflected = new ReflectionClass(new static(array()));
$properties = $reflected->getProperties(
ReflectionProperty::IS_PUBLIC
);
return array_map(function ($item) {
return $item->getName();
}, $properties);
}
public function asArray()
{
$properties = array();
foreach (static::getPropertyNames() as $itemValue) {
$properties[$itemValue] = $this->get($itemValue);
}
return $properties;
}
public function __sleep()
{
foreach (self::getPropertyNames() as $propertyName) {
$this->set(
$propertyName,
$this->get($propertyName)
);
}
return self::getPropertyNames();
}
public function __wakeup()
{
foreach (self::getPropertyNames() as $propertyName) {
$this->properties[$propertyName] = $this->$propertyName;
$this->$propertyName = null;
}
return self::getPropertyNames();
}
}