Skip to content

Instantly share code, notes, and snippets.

@roquie
Last active September 12, 2022 17:44
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 roquie/21ae3db03e45bc9b8d3f30d8694d6264 to your computer and use it in GitHub Desktop.
Save roquie/21ae3db03e45bc9b8d3f30d8694d6264 to your computer and use it in GitHub Desktop.
Cycle ORM typecaster
<?php
declare(strict_types=1);
namespace App\Domain\Common;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
final class SortableUuid implements \Stringable
{
private UuidInterface $value;
public function __construct(
?UuidInterface $uuid = null
) {
$uuid = $uuid ?: Uuid::uuid6();
if (!method_exists($uuid, 'getDateTime')) {
throw new \ValueError('Only UUID V6 supported.');
}
$this->value = $uuid;
}
public function getValue(): UuidInterface
{
return $this->value;
}
public function __toString(): string
{
return (string) $this->value;
}
public function getDateTime(): \DateTimeImmutable
{
return \DateTimeImmutable::createFromInterface(
$this->value->getDateTime()
);
}
}
<?php
declare(strict_types=1);
namespace App\Infrastructure\CycleORM;
use App\Domain\Common\Cause;
use App\Domain\Common\SortableUuid;
use App\Domain\Common\URL;
use App\Domain\Event\Duration;
use Cycle\ORM\Exception\TypecastException;
use Cycle\ORM\Parser\CastableInterface;
use Cycle\ORM\Parser\UncastableInterface;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
final class TypeCaster implements CastableInterface, UncastableInterface
{
/** @var array<class-string> */
private const SUPPORTED_RULES = [
URL::class,
Duration::class,
Cause::class,
UuidInterface::class,
SortableUuid::class,
];
private array $rules = [];
public function setRules(array $rules): array
{
foreach ($rules as $key => $rule) {
if (\in_array($rule, self::SUPPORTED_RULES, true)) {
unset($rules[$key]);
$this->rules[$key] = $rule;
}
}
return $rules;
}
public function cast(array $data): array
{
foreach ($this->rules as $column => $rule) {
if (! isset($data[$column])) {
continue;
}
try {
if (\is_object($data[$column])) {
continue;
}
$data[$column] = match ($rule) {
URL::class => new URL($data[$column]),
Duration::class => new Duration($data[$column]),
Cause::class => new Cause($data[$column]),
SortableUuid::class => new SortableUuid(Uuid::fromString($data[$column])),
UuidInterface::class => Uuid::fromString($data[$column]),
default => $data[$column]
};
} catch (\Throwable $e) {
throw new TypecastException("Unable to cast the `$column` field: {$e->getMessage()}");
}
}
return $data;
}
public function uncast(array $data): array
{
foreach ($this->rules as $column => $rule) {
if (! isset($data[$column])) {
continue;
}
try {
$data[$column] = match ($rule) {
URL::class,
UuidInterface::class,
Cause::class,
SortableUuid::class => (string) $data[$column],
Duration::class => $data[$column]->getValue(),
default => $data[$column]
};
} catch (\Throwable $e) {
throw new TypecastException("Unable to uncast the `$column` field: {$e->getMessage()}");
}
}
return $data;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment