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;
}