To work with the Cycle Active Record, you need to extend the entity class with the ActiveRecord
.
Note Below are examples of defining entities using attributes (see Annotated Entities), but you are still free to define entities in any other way.
Strict Approach:
In the strict approach, you define your entity with private properties and provide public getter and setter methods to access and modify the properties.
This approach encapsulates the entity's internal state and provides better control over how the properties are accessed and modified.
<?php
declare(strict_types=1);
namespace App\Entities;
use Cycle\ActiveRecord\ActiveRecord;
use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Entity;
use Cycle\ORM\Entity\Behavior\CreatedAt;
#[CreatedAt(field: 'createdAt')]
#[Entity(table: 'users')]
class User extends ActiveRecord
{
#[Column(type: 'bigInteger', primary: true, typecast: 'int')]
private int $id;
#[Column(type: 'string')]
private string $name;
#[Column(type: 'string', unique: true)]
private string $email;
private \DatetimeImmutable $createdAt;
public function __construct(string $name, string $email)
{
$this->name = $name;
$this->email = $email;
}
public static function create(string $name, string $email): static
{
return static::make([
'name' => $name,
'email' => $email,
]);
}
public function id(): int
{
return $this->id;
}
public function name(): string
{
return $this->name;
}
public function changeName(string $name): void
{
$this->name = $name;
}
public function email(): string
{
return $this->email;
}
public function changeEmail(string $email): void
{
$this->email = $email;
}
}
Once the entities are described, we can start working with them.
Using constructors is not recommended, as it can lead to undesirable effects, but it's still possible to use them. Look at the Extended Defining Entities section for more information.
make()
MethodThe make()
method is a static factory method that accepts an array of properties and returns a new instance of the entity.
$user = User::make([
'name' => $name,
'email' => $email,
]);
To save the entity to the database, you can use the save()
method:
The save()
method returns a result object that contains information about the operation.
$result = $user->save();
// Check if the operation was successful
$result->isSuccess();
If you prefer to have an exception thrown when the operation fails, you can use the saveOrFail()
method:
$user->saveOrFail();
Entities that extends ActiveRecord
class includes powerful Cycle-ORM Query Builder
allowing you to fluently query the database table associated with the Entity.
The process of querying data usually takes the following three steps:
ActiveRecord::query()
method;The ActiveRecord::query()
method returns a new instance of the ActiveQuery
class,
which is a wrapper around the query builder provided by Cycle ORM.
It means that you can use all the methods provided by the query builder and additionally some methods provided by the related ActiveQuery
class.
// Query all the dog people
$dogsGuys = User::query()
->where('likes_dogs', true)
->fetchAll();
// Query 10 users who have a dog named Rex
$rexOwners = User::query()
->load('pet', ['where' => ['type' => 'dog', 'name' => 'Rex']])
->limit(10)
->fetchAll();
// Query user by id
$user = User::findByPK($id);
To delete a single record, first retrieve the Active Record entity and then call the delete()
or deleteOrFail()
method.
User::findByPK($id)->delete();
Post::findByPK($id)->deleteOrFail();
Each call to the save()
, delete()
, deleteOrFail()
, or saveOrFail()
method
runs at least one transaction to the database.
However, you may need to save multiple distinct entities in a single transaction.
To achieve this, you can use the transact()
method:
ActiveRecord::transct(
function () use ($users, $user, $account, $post) {
array_walk($users, fn ($user) => $user->save());
$user->save();
$account->save();
$post->delete();
}
);
All the ActiveRecord write operations within the callback will be registered using the common Entity Manager without being executed until the end of the callback.
It is different from the database transaction because it doesn't start
a new DB transaction outside the Entity Manager.
To configure the transaction behavior of the Entity Manager, you can use the second parameter of the transact()
method:
ActiveRecord::transact(
function () use ($users, $user, $account, $post) {
array_walk($users, fn ($user) => $user->save());
$user->save();
$account->save();
$post->delete();
},
TransactionMode::Ignore,
);
The TransactionMode
enum provides the following options:
TransactionMode::OpenNew
(default) starts a new transaction when the Entity Manager is running after the callback.TransactionMode::Current
uses the current transaction and throws an exception if there is no active transaction.TransactionMode::Ignore
does nothing about transactions. If there is an active transaction,
it won't be committed or rolled back.