We know, that you are looking forward to a CycleORM updates and this fact motivates us working faster and more efficiently.
Here they are!
CycleORM is used to allow otping a column type among the primitive types such as int
, string
, float
, datetime
and callable
, but now you can create typecast handler class, that implements Cycle\ORM\Parser\TypecastInterface
and define it (or array of handlers) as an Entity columns typecast handler.
Example
use Cycle\ORM\Parser\TypecastInterface;
class UuidTypecast implements TypecastInterface
{
private array $rules = [];
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 $key => $rule) {
if (!isset($values[$key])) {
continue;
}
$values[$key] = Uuid::fromString($values[$key]);
}
return $values;
}
}
use Cycle\ORM\Parser\Typecast as PrimitiveTypecast;
#[Entity(
typecast: [
UuidTypecast::class,
PrimitiveTypecast::class
]
)]
class User {
#[Column]
private UuidInterface $id;
}
By default all etities use \Cycle\ORM\Parser\Typecast::class
typecast handler, but you can change default behavior globally in the next release of spiral/app
or you can do it right now in your app via \Cycle\Schema\Compiler
.
Example
use Cycle\Schema\Compiler;
use Cycle\ORM\SchemaInterface;
use Cycle\ORM\Parser\Typecast as PrimitiveTypecast;
(new Compiler)->compile($r, [/* Generators[] */], [
SchemaInterface::TYPECAST_HANDLER = [
UuidTypecast::class,
PrimitiveTypecast::class
]
])
Example
#[Entity]
class User
{
// ...
#[ManyToMany(
target: Tag::class,
collection: \Doctrine\Common\Collections\Collection::class,
// or
collection: 'doctrine'
)]
protected \Doctrine\Common\Collections\Collection $tags;
#[HasMany(
target: Post::class,
collection: \Illuminate\Support\Collection::class,
// or
collection: 'illuminate'
)]
protected \Illuminate\Support\Collection $tags;
#[HasMany(
target: Post::class,
collection: 'array'
)]
protected array $comments;
}
CycleORM has support Single Table Inheritance and Joined Table Inheritance, but now you can configure JTI/STI via attributes (annotations) also.
STI
use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Entity;
use Cycle\Annotated\Annotation\Inheritance\DiscriminatorColumn;
use Cycle\Annotated\Annotation\Inheritance\SingleTable as InheritanceSingleTable;
#[Entity]
#[DiscriminatorColumn(name: 'type')] // Discriminator column (required)
class Person
{
#[Column(type: 'primary', primary: true)]
protected int $id;
#[Column(type: 'string')]
protected string $name;
}
#[Entity]
#[InheritanceSingleTable]
class Employee extends Person
{
#[Column(type: 'int')]
protected int $salary;
}
#[Entity]
#[InheritanceSingleTable(value: 'foo_customer')]
class Customer extends Person
{
#[Column(type: 'json')]
protected array $preferences;
}
JTI
use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Entity;
use Cycle\Annotated\Annotation\Inheritance\JoinedTable as InheritanceJoinedTable;
#[Entity]
class Person
{
#[Column(primary: true)]
protected int $id;
#[Column()]
protected int $fooId;
#[Column(type: 'string')]
protected string $name;
}
#[Entity]
#[InheritanceJoinedTable(outerKey: 'fooId')]
class Employee extends Person
{
#[Column(type: 'int')]
protected int $salary;
}
#[Entity]
#[InheritanceJoinedTable(outerKey: 'id')]
class Customer extends Person
{
#[Column(type: 'json')]
protected array $preferences;
}
You can combine STI and JTI
use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Entity;
use Cycle\Annotated\Annotation\Inheritance\DiscriminatorColumn;
use Cycle\Annotated\Annotation\Inheritance\SingleTable as InheritanceSingleTable;
use Cycle\Annotated\Annotation\Inheritance\JoinedTable as InheritanceJoinedTable;
#[Entity]
#[DiscriminatorColumn(name: 'type')]
class Person
{
#[Column(type: 'primary', primary: true)]
protected int $id;
#[Column(type: 'string')]
protected string $name;
}
#[Entity]
#[InheritanceSingleTable]
class Employee extends Person
{
#[Column(type: 'int')]
protected int $salary;
}
#[Entity]
#[InheritanceSingleTable(value: 'foo_customer')]
class Customer extends Person
{
#[Column(type: 'json')]
protected array $preferences;
}
#[Entity]
#[InheritanceJoinedTable(outerKey: 'foo_id')]
class Executive extends Employee
{
#[Column(type: 'int')]
protected int $bonus;
}
As I mentioned above, you can configure Typecast handlers via attributes (annotatios).
use Cycle\ORM\Parser\Typecast as PrimitiveTypecast;
#[Entity(
typecast: [
UuidTypecast::class,
PrimitiveTypecast::class
]
)]
class User {
#[Column]
private UuidInterface $id;
}
The package allows to render CycleORM schema in a terminal or to prepare schemas to save into a php file. The package will be a part of spiral/app
in the next release and there can be used a console command php app.php cycle:render
for rendering entity schemas in a terminal.
Example
use Cycle\Schema\Compiler;
use ycle\Schema\Renderer\OutputSchemaRenderer;
use ycle\Schema\Renderer\SchemaToArrayConverter;
// Create schema from generators
$schema = (new Compiler)->compile(...);
// Or getting schema form object \Cycle\ORM\SchemaInterface
$schema = (new SchemaToArrayConverter())->convert($schema);
$renderer = new OutputSchemaRenderer();
// Render to a terminal
$output->writeln(
$renderer->render($schemaArray)
);
Output example
The package is in progress yet, but you can try it right now. The package allows you to use macros for changing default entity columns behavior.
Macros replace https://cycle-orm.dev/docs/advanced-timestamp
Example
use Cycle\ORM\Entity\Macros\Timestamped;
#[Entity]
#[Timestamped\CreatedAtMacro(field: 'createdAt')]
#[Timestamped\UpdatedAtMacro(field: 'updatedAt')]
#[Timestamped\DeletedAtMacro(field: 'deletedAt')]
class Post {
#[Column(type: 'datetime')]
private \DateTimeImmutable $createdAt;
#[Column(type: 'datetime')]
private \DateTimeImmutable $updatedAt;
#[Column(type: 'datetime')]
private \DateTimeImmutable $deletedAt;
}
In addition to use macros including in this package, there is an ability easily to create your own macros!
!!! Some features can be changed in the final release.
Enough! Now there are no more arrays and attempts to understand what settings a driver supports.
Before
use Cycle\Database\Driver;
'drivers' => [
'mysql' => [
'driver' => Driver\MySQL\MySQLDriver::class,
'options' => [
'connection' => 'mysql:host=127.0.0.1;dbname=' . env('DB_NAME'),
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
]
],
'postgres' => [
'driver' => Driver\Postgres\PostgresDriver::class,
'options' => [
'connection' => 'pgsql:host=127.0.0.1;dbname=' . env('DB_NAME'),
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
]
],
'runtime' => [
'driver' => Driver\SQLite\SQLiteDriver::class,
'options' => [
'connection' => 'sqlite:' . directory('runtime') . 'runtime.db',
'username' => 'sqlite',
'password' => '',
]
],
'sqlServer' => [
'driver' => Driver\SQLServer\SQLServerDriver::class,
'options' => [
'connection' => 'sqlsrv:Server=MY-PC;Database=' . env('DB_NAME'),
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
]
]
]
After
use Cycle\Database\Config;
'drivers' => [
'sqlite_memory' => new Config\SQLiteDriverConfig(
connection: new SQLite\MemoryConnectionConfig(),
queryCache: true,
),
'sqlite_file' => new Config\SQLiteDriverConfig(
connection: new Config\SQLite\FileConnectionConfig(
database: env('DB_DATABASE', __DIR__.'./../../runtime/database.sqlite')
),
queryCache: true,
),
'mysql' => new Config\MySQLDriverConfig(
connection: new Config\MySQL\TcpConnectionConfig(
database: env('DB_DATABASE', 'forge'),
host: env('DB_HOST', '127.0.0.1'),
port: (int)env('DB_PORT', 3306),
user: env('DB_USERNAME', 'forge'),
password: env('DB_PASSWORD', ''),
),
queryCache: true
),
'postgres' => new \Config\PostgresDriverConfig(
connection: new Config\Postgres\TcpConnectionConfig(
database: env('DB_DATABASE', 'forge'),
host: env('DB_HOST', '127.0.0.1'),
port: (int)env('DB_PORT', 5432),
user: env('DB_USERNAME', 'forge'),
password: env('DB_PASSWORD', ''),
),
schema: 'public',
queryCache: true,
),
],
We will provide more information about driver DTOs after CycleORM v2.0 release.
We prepared a demo app of spiral/app where you can try CycleORM v2 with all new features
CycleORM is one of the most high performance by speed ORM, and soon by functionality!