Skip to content

Commit

Permalink
add serialisation and deserialisation to DataTransferObject
Browse files Browse the repository at this point in the history
  • Loading branch information
d8vjork committed Oct 12, 2023
1 parent 229b01a commit 11261ea
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
65 changes: 65 additions & 0 deletions src/DataTransferObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

namespace OpenSoutheners\LaravelDto;

use Carbon\Carbon;
use Exception;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use OpenSoutheners\LaravelDto\Attributes\BindModelUsing;
use OpenSoutheners\LaravelDto\Attributes\BindModelWith;
use Symfony\Component\PropertyInfo\Type;

abstract class DataTransferObject implements Arrayable
Expand Down Expand Up @@ -163,4 +168,64 @@ public function fromRequestContext(bool $value = true): self

return $this;
}

public function __serialize(): array
{
$reflection = new \ReflectionClass($this);

/** @var array<\ReflectionProperty> $properties */
$properties = $reflection->getProperties(\ReflectionProperty::IS_PUBLIC);

$serialisableArr = [];

foreach ($properties as $property) {
$key = $property->getName();
$value = $property->getValue($this);

/** @var array<\ReflectionAttribute> $propertyAttributes */
$propertyAttributes = $property->getAttributes();
$propertyBindingAttributes = [
'using' => null,
];

foreach ($propertyAttributes as $attribute) {
$attributeInstance = $attribute->newInstance();

if ($attributeInstance instanceof BindModelUsing) {
$propertyBindingAttributes['using'] = $attributeInstance->attribute;
}
}

$serialisableArr[$key] = match (true) {
$value instanceof Model => $value->getAttribute($propertyBindingAttributes['using'] ?? $value->getRouteKeyName()),
$value instanceof Collection => $value->first() instanceof Model ? $value->map(fn (Model $model) => $model->getAttribute($propertyBindingAttributes['using'] ?? $model->getRouteKeyName()))->join(',') : $value->join(','),
$value instanceof Arrayable => $value->toArray(),
$value instanceof \Stringable => (string) $value,
is_array($value) => head($value) instanceof Model ? implode(',', array_map(fn (Model $model) => $model->getAttribute($propertyBindingAttributes['using'] ?? $model->getRouteKeyName()))) : implode(',', $value),
default => $value,
};
}

return $serialisableArr;
}

/**
* Called during unserialization of the object.
*/
public function __unserialize(array $data): void
{
$properties = (new \ReflectionClass($this))->getProperties(\ReflectionProperty::IS_PUBLIC);

$propertiesMapper = new PropertiesMapper(array_merge($data), static::class);

$propertiesMapper->run();

$data = $propertiesMapper->get();

foreach ($properties as $property) {
$key = $property->getName();

$this->{$key} = $data[$key] ?? $property->getDefaultValue();
}
}
}
29 changes: 29 additions & 0 deletions tests/Integration/ValidatedDataTransferObjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,34 @@ public function testDataTransferObjectWithModelSentDoesNotRunQueriesToFetchItAga
]);

$this->assertEmpty(DB::getQueryLog());
$this->assertTrue($data->post->is($post));
}

public function testDataTransferObjectCanBeSerializedAndDeserialized()
{
$this->withoutExceptionHandling();

Post::factory()->create();

Tag::factory()->create();
Tag::factory()->create();

$data = UpdatePostWithRouteBindingData::fromArray([
'post' => '1',
'tags' => '1,2',
'post_status' => 'test_non_existing_status',
'published_at' => '2023-09-06 17:35:53',
]);

$serializedData = serialize($data);

$this->assertIsString($serializedData);

$deserializedData = unserialize($serializedData);

$this->assertTrue($data->post->is($deserializedData->post));
$this->assertTrue($deserializedData->post->relationLoaded('tags'));
$this->assertTrue($data->tags->first()->is($deserializedData->tags->first()));
$this->assertTrue($data->publishedAt->eq($deserializedData->publishedAt));
}
}

0 comments on commit 11261ea

Please sign in to comment.