nur-sery/src/db/Capacitor.php

167 lines
4.5 KiB
PHP

<?php
namespace nur\sery\db;
use nur\sery\php\func;
use nur\sery\ValueException;
/**
* Class Capacitor: un objet permettant d'attaquer un canal spécifique d'une
* instance de {@link CapacitorStorage}
*/
class Capacitor implements ITransactor {
function __construct(CapacitorStorage $storage, CapacitorChannel $channel, bool $ensureExists=true) {
$this->storage = $storage;
$this->channel = $channel;
if ($ensureExists) $this->ensureExists();
}
/** @var CapacitorStorage */
protected $storage;
function getStorage(): CapacitorStorage {
return $this->storage;
}
function db(): IDatabase {
return $this->getStorage()->db();
}
/** @var CapacitorChannel */
protected $channel;
function getChannel(): CapacitorChannel {
return $this->channel;
}
function getTableName(): string {
return $this->getChannel()->getTableName();
}
/** @var CapacitorChannel[] */
protected ?array $subChannels = null;
protected ?array $subManageTransactions = null;
function willUpdate(...$channels): self {
if ($this->subChannels === null) {
# désactiver la gestion des transaction sur le channel local aussi
$this->subChannels[] = $this->channel;
}
if ($channels) {
foreach ($channels as $channel) {
if ($channel instanceof Capacitor) $channel = $channel->getChannel();
if ($channel instanceof CapacitorChannel) {
$this->subChannels[] = $channel;
} else {
throw ValueException::invalid_type($channel, CapacitorChannel::class);
}
}
}
return $this;
}
function inTransaction(): bool {
return $this->db()->inTransaction();
}
function beginTransaction(?callable $func=null, bool $commit=true): void {
if ($this->subManageTransactions === null && $this->subChannels !== null) {
foreach ($this->subChannels as $channel) {
$name = $channel->getName();
$this->subManageTransactions ??= [];
if (!array_key_exists($name, $this->subManageTransactions)) {
$this->subManageTransactions[$name] = $channel->isManageTransactions();
}
$channel->setManageTransactions(false);
}
$db = $this->db();
if (!$db->inTransaction()) $db->beginTransaction();
}
if ($func !== null) {
$commited = false;
try {
func::call($func, $this);
if ($commit) {
$this->commit();
$commited = true;
}
} finally {
if ($commit && !$commited) $this->rollback();
}
}
}
protected function beforeEndTransaction(): void {
if ($this->subManageTransactions !== null) {
foreach ($this->subChannels as $channel) {
$name = $channel->getName();
$channel->setManageTransactions($this->subManageTransactions[$name]);
}
$this->subManageTransactions = null;
}
}
function commit(): void {
$this->beforeEndTransaction();
$db = $this->db();
if ($db->inTransaction()) $this->db()->commit();
}
function rollback(): void {
$this->beforeEndTransaction();
$db = $this->db();
if ($db->inTransaction()) $this->db()->rollback();
}
function getCreateSql(): string {
return $this->storage->_getCreateSql($this->channel);
}
function exists(): bool {
return $this->storage->_exists($this->channel);
}
function ensureExists(): void {
$this->storage->_ensureExists($this->channel);
}
function reset(bool $recreate=false): void {
$this->storage->_reset($this->channel, $recreate);
}
function charge($item, $func=null, ?array $args=null, ?array &$values=null): int {
$this->beginTransaction();
return $this->storage->_charge($this->channel, $item, $func, $args, $values);
}
function discharge(bool $reset=true): iterable {
return $this->storage->_discharge($this->channel, $reset);
}
function count($filter=null): int {
return $this->storage->_count($this->channel, $filter);
}
function one($filter): ?array {
return $this->storage->_one($this->channel, $filter);
}
function all($filter): iterable {
return $this->storage->_all($this->channel, $filter);
}
function each($filter, $func=null, ?array $args=null): int {
$this->beginTransaction();
return $this->storage->_each($this->channel, $filter, $func, $args);
}
function delete($filter, $func=null, ?array $args=null): int {
$this->beginTransaction();
return $this->storage->_delete($this->channel, $filter, $func, $args);
}
function close(): void {
$this->storage->close();
}
}