Skip to content

Instantly share code, notes, and snippets.

@dersonsena
Created January 3, 2023 18:14
Show Gist options
  • Save dersonsena/9dbb68aa58cd18aed288dee3cedfcfe9 to your computer and use it in GitHub Desktop.
Save dersonsena/9dbb68aa58cd18aed288dee3cedfcfe9 to your computer and use it in GitHub Desktop.
<?php
declare(strict_types=1);
namespace App\Shared\Adapter\Contracts;
/**
* Interface Dto
*/
interface Dto
{
/**
* Associative array such as `'property' => 'value'` with all boundary values
* @return array
*/
public function values(): array;
/**
* Get a DTO value by property
* @param string $property
* @return mixed
*/
public function get(string $property): mixed;
/**
* Rules to validate DTO
* @return array ['fieldName' => ValidatorFieldCollection]
*/
public function rules(): array;
}
<?php
declare(strict_types=1);
namespace App\Shared\Adapter;
use App\Shared\Adapter\Contracts\Dto;
use App\Shared\Adapter\Exception\InvalidDtoParam;
use JsonSerializable;
use ReflectionClass;
use ReflectionProperty;
/**
* Class DtoBase
*/
abstract class DtoBase implements Dto, JsonSerializable
{
private array $values = [];
private bool $strict;
/**
* Boundary constructor.
* @param array $values
* @param bool $strict
* @throws InvalidDtoParam
*/
private function __construct(array $values, bool $strict)
{
$this->strict = $strict;
$reflect = new ReflectionClass($this);
$dtoProps = $reflect->getProperties(ReflectionProperty::IS_PROTECTED);
$dtoProps = array_map(fn (ReflectionProperty $property) => $property->name, $dtoProps);
foreach ($dtoProps as $propertyName) {
$property = new ReflectionProperty($this, $propertyName);
$defaultValue = match ($property->getType()->getName()) {
'string' => '',
'array' => [],
'bool' => true,
'int', 'double', 'float' => 0,
default => null
};
if ($property->getType()->allowsNull()) {
$defaultValue = null;
}
$this->{$propertyName} = $defaultValue;
$this->values[$propertyName] = $defaultValue;
}
foreach ($values as $key => $value) {
if (mb_strstr($key, '_') !== false) {
$key = lcfirst(str_replace('_', '', ucwords($key, '_')));
}
if (!property_exists($this, $key)) {
if (!$this->strict) {
continue;
}
throw InvalidDtoParam::dynamicParam(get_class(), $key);
}
$this->{$key} = $value;
$this->values[$key] = $this->get($key);
}
}
/**
* Static method to create a Boundary (TextField or Output)
* @param array $values Associative array such as `'property' => 'value'`
* @throws InvalidDtoParam
*/
public static function create(array $values, bool $strict = false): static
{
return new static($values, $strict);
}
/**
* {@inheritdoc}
*/
public function values(): array
{
return $this->values;
}
/**
* {@inheritdoc}
* @throws InvalidDtoParam
*/
public function get(string $property): mixed
{
$getter = "get" . ucfirst($property);
if (method_exists($this, $getter)) {
return $this->{$getter}();
}
if (!property_exists($this, $property)) {
throw InvalidDtoParam::dynamicParam(get_class(), $property);
}
return $this->{$property};
}
public function jsonSerialize()
{
return $this->values();
}
public function rules(): array
{
return [];
}
/**
* Magic getter method to get a DTO property value
* @param string $name
* @return mixed
* @throws InvalidDtoParam
*/
public function __get(string $name)
{
return $this->get($name);
}
public function __set(string $name, mixed $value)
{
throw InvalidDtoParam::readonlyProperty(get_class(), $name, $value);
}
public function __isset($name): bool
{
return property_exists($this, $name);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment