Skip to content

Instantly share code, notes, and snippets.

@Gummibeer
Created November 30, 2022 12:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Gummibeer/764547ef1248b701ce1b2470853f38eb to your computer and use it in GitHub Desktop.
Save Gummibeer/764547ef1248b701ce1b2470853f38eb to your computer and use it in GitHub Desktop.
<?php
namespace Hospitable\Avalara\DTOs;
use Carbon\CarbonInterface;
use Hospitable\Avalara\Collections\Collection;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;
use JsonSerializable;
use ReflectionClass;
use TypeError;
abstract class DataTransferObject implements Arrayable, Jsonable, JsonSerializable
{
public static function fromArray(array $data): static
{
$class = new ReflectionClass(static::class);
$properties = $class->getProperties();
$arguments = [];
foreach ($properties as $property) {
$type = $property->getType()?->getName() ?? 'string';
$value = data_get($data, $property->getName());
if (enum_exists($type)) {
$arguments[$property->getName()] = $type::from($value);
continue;
}
if (! class_exists($type)) {
$arguments[$property->getName()] = $value;
continue;
}
if (is_subclass_of($type, Collection::class)) {
$arguments[$property->getName()] = $type::fromArray($value ?? []);
continue;
}
if (is_subclass_of($type, self::class)) {
$arguments[$property->getName()] = $value ? $type::fromArray($value) : null;
continue;
}
if (in_array(CarbonInterface::class, class_implements($type), true)) {
$arguments[$property->getName()] = $type::make($value);
continue;
}
throw new TypeError("[{$type}] is an existing class but not handled by DataTransferObject::fromArray() implementation.");
}
return new static(...$arguments);
}
/**
* @param array|static $data
* @return static
*/
public function merge(array|self $data): static
{
return static::fromArray(array_merge(
$this->toArray(),
$data instanceof self ? $data->toArray() : $data
));
}
public function toArray(): array
{
return collect(get_object_vars($this))
->filter(fn (mixed $value): bool => filled($value))
->map(fn (mixed $value): mixed => $value instanceof CarbonInterface ? $value->toDateString() : $value)
->toArray();
}
public function toJson($options = 0): string
{
return json_encode($this, JSON_THROW_ON_ERROR | $options);
}
public function jsonSerialize(): array
{
return $this->toArray();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment