Typecast handlers: setRules
method
#307
-
Hi, cycle 2.0 has opportunity of adding TYPECAST_HANDLER, but I can't understand one thing about setRules. Should I check all my fields there, for example I have more than 100 fields which would use this handler it means I must check all these fields in setRules method? Do I have opportunity to set like TYPECAST_HANDLER⇾ field⇾handler? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Method For example we have two typecast handlers: Defaultfinal class Typecast implements CastableInterface
{
private const RULES = ['int', 'bool', 'float', 'datetime'];
/** @var array<non-empty-string, bool> */
private array $callableRules = [];
/** @var array<non-empty-string, mixed> */
private array $rules = [];
public function __construct(
private DatabaseInterface $database
) {
}
public function setRules(array $rules): array
{
foreach ($rules as $key => $rule) {
if (in_array($rule, self::RULES, true)) {
$this->rules[$key] = $rule;
unset($rules[$key]);
} elseif (\is_callable($rule)) {
$this->callableRules[$key] = true;
$this->rules[$key] = $rule;
unset($rules[$key]);
}
}
return $rules;
}
public function cast(array $data): array
{
try {
foreach ($this->rules as $key => $rule) {
if (!isset($data[$key])) {
continue;
}
if (isset($this->callableRules[$key])) {
$data[$key] = $rule($data[$key], $this->database);
continue;
}
$data[$key] = $this->castPrimitive($rule, $data[$key]);
}
} catch (Throwable $e) {
throw new TypecastException(
sprintf('Unable to typecast the `%s` field. %s', $key, $e->getMessage()),
$e->getCode(),
$e
);
}
return $data;
}
/**
* @throws \Exception
*/
private function castPrimitive(mixed $rule, mixed $value): mixed
{
return match ($rule) {
'int' => (int)$value,
'bool' => (bool)$value,
'float' => (float)$value,
'datetime' => new DateTimeImmutable(
$value,
$this->database->getDriver()->getTimezone()
),
default => $value,
};
}
} Customuse App\Domain\ValueObjects\Uuid;
use Cycle\ORM\Parser\CastableInterface;
use Cycle\ORM\Parser\UncastableInterface;
use Ramsey\Uuid\UuidInterface;
final class ExtendedTypecast implements CastableInterface, UncastableInterface
{
private array $rules = [];
private array $availableRules = ['uuid', 'json'];
public function setRules(array $rules): array
{
foreach ($rules as $key => $rule) {
if (\in_array($rule, $this->availableRules, true)) {
unset($rules[$key]);
$this->rules[$key] = $rule;
}
}
return $rules;
}
public function cast(array $values): array
{
foreach ($this->rules as $column => $rule) {
if (! isset($values[$column])) {
continue;
}
$values[$column] = match ($rule) {
'uuid' => Uuid::fromString($values[$column]),
'json' => new Json(json_decode($values[$column], true)),
default => $values[$column]
};
}
return $values;
}
public function uncast(array $values): array
{
foreach ($this->rules as $column => $rule) {
if (! isset($values[$column])) {
continue;
}
$values[$column] = match ($rule) {
'uuid' => $this->uncastUuid($values[$column]),
'json' => $this->uncastJson($values[$column]),
default => $values[$column]
};
}
return $values;
}
private function uncastUuid(mixed $value): string
{
if ($value instanceof Uuid || $value instanceof UuidInterface) {
return $value->toString();
}
return $value;
}
private function uncastJson(mixed $value): string
{
return (string)$value;
}
} Both of this handler will be handled via It will look like this $handler = new CompositeTypecast(new Typecast(), new ExtendedTypecast()); At first composite handler will call |
Beta Was this translation helpful? Give feedback.
Method
setRules
runs only once when typecast handlers initialize. In this method you can decide which rules should be processed by each handler.For example we have two typecast handlers:
Default