Cycle ORM v1.x has the only ability to add custom column types
via Column wrappers. Moreover, it doesn't have an ability to use proper type
casting for autogenerated values on a database side: lastInsertID couldn't have proper type after inserting a new
record to the database, and it could make some problem with strict type code. Since v2.x you can use more configurable
way to use custom types.
Cycle ORM v2.x has a new key SchemaInterface::TYPECAST_HANDLER in a schema declaration.
$schema = new Schema([
User::class => [
// ..
Schema::TYPECAST_HANDLER => //...
],
]);
By default, Schema::TYPECAST_HANDLER has null value. In this case the ORM uses default
typecast handler - Cycle\ORM\Parser\Typecast. You can define custom handler or array of handlers (int might be class
string or handler alias (in this case the ORM will try to load class from application container)).
$schema = new Schema([
User::class => [
// ..
Schema::TYPECAST_HANDLER => App\MyCustomTypecast::class
],
Post::class => [
// ..
Schema::TYPECAST_HANDLER => [
\Cycle\ORM\Parser\Typecast::class,
App\UuidTypecast::class,
'carbon_typecast'
]
],
]);
Array of handlers will be wrapped in to Cycle\ORM\Parser\CompositeTypecast and then applied in order they were set.
Handler class should implement at least one of presented interfaces:
\Cycle\ORM\Parser\CastableInterface
\Cycle\ORM\Parser\UncastableInterface
use Cycle\ORM\Parser\CastableInterface;
use Cycle\ORM\Parser\UncastableInterface;
final class UuidTypecast implements CastableInterface, UncastableInterface
{
private array $rules = [];
public function __construct(
private DatabaseInterface $database
) {
}
public function setRules(array $rules): array
{
foreach ($rules as $key => $rule) {
if ($rule === 'uuid') {
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] = Uuid::fromString($values[$column]);
}
return $values;
}
public function uncast(array $values): array
{
foreach ($this->rules as $column => $rule) {
if (! isset($values[$column]) || !$values[$column] instanceof UuidInterface) {
continue;
}
$values[$column] = $values[$column]->toString();
}
return $values;
}
}
Finally, you should add typecast attribute to property which should processed by UuidTypecast.
use Cycle\Annotated\Annotation\Entity;
use Ramsey\Uuid\UuidInterface;
#[Entity(
typecast: [
\Cycle\ORM\Parser\Typecast::class,
App\UuidTypecast::class,
'carbon_typecast'
]
)]
class User
{
#[Cycle\Column(type: 'string', typecast: 'uuid')]
public UuidInterface $uuid;
}