1. Go to this page and download the library: Download zolta/cqrs library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
use Zolta\Cqrs\Commands\Command;
class CreateUserCommand extends Command
{
public function __construct(
public readonly string $name,
public readonly string $email,
public readonly string $password,
) {}
}
use Zolta\Cqrs\Attributes\HandlesCommand;
use Zolta\Cqrs\Services\Result;
#[HandlesCommand(CreateUserCommand::class)]
class CreateUserHandler
{
public function __construct(
private readonly UserRepositoryInterface $repository,
) {}
public function __invoke(CreateUserCommand $command): Result
{
$user = User::create(
id: UserId::generate(),
name: Username::resolve(['value' => $command->name]),
email: Email::resolve(['address' => $command->email]),
password: HashedPassword::fromPlaintext($command->password),
);
$this->repository->save($user);
return Result::success(
value: $user->toArray(),
events: $user->releaseEvents(),
);
}
}
use Zolta\Cqrs\Attributes\ValidatesCommand;
#[ValidatesCommand(CreateUserCommand::class)]
class CreateUserValidator
{
public function validate(CreateUserCommand $command): void
{
if ($this->repository->findByEmail($command->email)) {
throw new ValidationException(['email' => 'Already registered.']);
}
}
}
use Zolta\Cqrs\Queries\Query;
use Zolta\Cqrs\Attributes\HandlesQuery;
use Zolta\Cqrs\Services\Option;
class GetUserQuery extends Query
{
public function __construct(public readonly string $userId) {}
}
#[HandlesQuery(GetUserQuery::class)]
class GetUserHandler
{
public function __invoke(GetUserQuery $query): Option
{
$user = $this->repository->findById($query->userId);
return $user ? Option::some($user->toArray()) : Option::none();
}
}
$option = $cqrs->ask(new GetUserQuery(userId: '123'));
$data = $option->getOrFail(fn() => new NotFoundException('User not found'));
class RegistrationService
{
public function __construct(private ApplicationService $appService) {}
public function register(string $name, string $email, string $password): array
{
return $this->appService->transactional(function () use ($name, $email, $password) {
$this->appService->runAndCapture(new CreateUserCommand($name, $email, $password));
$this->appService->cqrs()->dispatch(new AssignRoleCommand(
userId: new MapPlaceholder('createUser.id'),
role: 'user',
));
return $this->appService->response([
'id' => 'createUser.id',
'name' => 'createUser.name',
'email' => 'createUser.email',
]);
});
}
}
// Result: success or failure, always carrying domain events
$result = Result::success(value: $user->toArray(), events: $user->releaseEvents());
$result = Result::failure(new DomainException('Email taken'));
$result->isSuccess(); // bool
$result->getValue(); // mixed — the success value
$result->getError(); // Throwable — the failure
$result->getEvents(); // EventInterface[] — extracted post-commit
// Option: some, none, or error — null-safe query results
$option = Option::some(['id' => '123', 'name' => 'John']);
$option = Option::none();
$option->getOrElse(['fallback']);
$option->getOrFail(fn() => new NotFoundException('User not found'));
return $this->appService->transactional(function () use ($name, $email, $password) {
// Each command result is captured with a key
$this->appService->runAndCapture(new CreateUserCommand($name, $email, $password));
// Reference earlier results via MapPlaceholder
$this->appService->cqrs()->dispatch(new AssignRoleCommand(
userId: new MapPlaceholder('createUser.id'),
role: 'user',
));
// Build response from captured values across commands
return $this->appService->response([
'id' => 'createUser.id',
'name' => 'createUser.name',
'email' => 'createUser.email',
]);
});
// If any command fails → auto-rollback. Events dispatch only on commit.