ajout transactor
This commit is contained in:
parent
ff6c5e8da4
commit
ad603e8e81
|
@ -1,11 +1,14 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\db;
|
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
|
* Class Capacitor: un objet permettant d'attaquer un canal spécifique d'une
|
||||||
* instance de {@link CapacitorStorage}
|
* instance de {@link CapacitorStorage}
|
||||||
*/
|
*/
|
||||||
class Capacitor {
|
class Capacitor implements ITransactor {
|
||||||
function __construct(CapacitorStorage $storage, CapacitorChannel $channel, bool $ensureExists=true) {
|
function __construct(CapacitorStorage $storage, CapacitorChannel $channel, bool $ensureExists=true) {
|
||||||
$this->storage = $storage;
|
$this->storage = $storage;
|
||||||
$this->channel = $channel;
|
$this->channel = $channel;
|
||||||
|
@ -34,6 +37,80 @@ class Capacitor {
|
||||||
return $this->getChannel()->getTableName();
|
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): 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);
|
||||||
|
$this->commit();
|
||||||
|
$commited = true;
|
||||||
|
} finally {
|
||||||
|
if (!$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 {
|
function getCreateSql(): string {
|
||||||
return $this->storage->_getCreateSql($this->channel);
|
return $this->storage->_getCreateSql($this->channel);
|
||||||
}
|
}
|
||||||
|
@ -51,6 +128,7 @@ class Capacitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
function charge($item, $func=null, ?array $args=null, ?array &$values=null): int {
|
function charge($item, $func=null, ?array $args=null, ?array &$values=null): int {
|
||||||
|
$this->beginTransaction();
|
||||||
return $this->storage->_charge($this->channel, $item, $func, $args, $values);
|
return $this->storage->_charge($this->channel, $item, $func, $args, $values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,10 +149,12 @@ class Capacitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
function each($filter, $func=null, ?array $args=null): int {
|
function each($filter, $func=null, ?array $args=null): int {
|
||||||
|
$this->beginTransaction();
|
||||||
return $this->storage->_each($this->channel, $filter, $func, $args);
|
return $this->storage->_each($this->channel, $filter, $func, $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function delete($filter, $func=null, ?array $args=null): int {
|
function delete($filter, $func=null, ?array $args=null): int {
|
||||||
|
$this->beginTransaction();
|
||||||
return $this->storage->_delete($this->channel, $filter, $func, $args);
|
return $this->storage->_delete($this->channel, $filter, $func, $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -204,6 +204,7 @@ EOT;
|
||||||
function _charge(CapacitorChannel $channel, $item, $func, ?array $args, ?array &$values=null): int {
|
function _charge(CapacitorChannel $channel, $item, $func, ?array $args, ?array &$values=null): int {
|
||||||
$this->_create($channel);
|
$this->_create($channel);
|
||||||
$tableName = $channel->getTableName();
|
$tableName = $channel->getTableName();
|
||||||
|
$db = $this->db();
|
||||||
|
|
||||||
$initFunc = [$channel, "getItemValues"];
|
$initFunc = [$channel, "getItemValues"];
|
||||||
$initArgs = $args;
|
$initArgs = $args;
|
||||||
|
@ -217,7 +218,7 @@ EOT;
|
||||||
$rowIds = $this->getRowIds($channel, $row, $primaryKeys);
|
$rowIds = $this->getRowIds($channel, $row, $primaryKeys);
|
||||||
if ($rowIds !== null) {
|
if ($rowIds !== null) {
|
||||||
# modification
|
# modification
|
||||||
$prow = $this->db()->one([
|
$prow = $db->one([
|
||||||
"select",
|
"select",
|
||||||
"from" => $tableName,
|
"from" => $tableName,
|
||||||
"where" => $rowIds,
|
"where" => $rowIds,
|
||||||
|
@ -276,28 +277,41 @@ EOT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($insert === null) {
|
# aucune modification
|
||||||
# aucune modification
|
if ($insert === null) return 0;
|
||||||
return 0;
|
|
||||||
} elseif ($insert) {
|
$manageTransactions = $channel->isManageTransactions();
|
||||||
$id = $this->db()->exec([
|
if ($manageTransactions) {
|
||||||
"insert",
|
$commited = false;
|
||||||
"into" => $tableName,
|
$db->beginTransaction();
|
||||||
"values" => $row,
|
}
|
||||||
]);
|
try {
|
||||||
if (count($primaryKeys) == 1 && $rowIds === null) {
|
if ($insert) {
|
||||||
# mettre à jour avec l'id généré
|
$id = $db->exec([
|
||||||
$values[$primaryKeys[0]] = $id;
|
"insert",
|
||||||
}
|
"into" => $tableName,
|
||||||
} else {
|
"values" => $row,
|
||||||
$this->db()->exec([
|
]);
|
||||||
"update",
|
if (count($primaryKeys) == 1 && $rowIds === null) {
|
||||||
"table" => $tableName,
|
# mettre à jour avec l'id généré
|
||||||
"values" => $row,
|
$values[$primaryKeys[0]] = $id;
|
||||||
"where" => $rowIds,
|
}
|
||||||
]);
|
} else {
|
||||||
|
$db->exec([
|
||||||
|
"update",
|
||||||
|
"table" => $tableName,
|
||||||
|
"values" => $row,
|
||||||
|
"where" => $rowIds,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if ($manageTransactions) {
|
||||||
|
$db->commit();
|
||||||
|
$commited = true;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
} finally {
|
||||||
|
if ($manageTransactions && !$commited) $db->rollback();
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function charge(?string $channel, $item, $func=null, ?array $args=null, ?array &$values=null): int {
|
function charge(?string $channel, $item, $func=null, ?array $args=null, ?array &$values=null): int {
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace nur\sery\db;
|
namespace nur\sery\db;
|
||||||
|
|
||||||
interface IDatabase {
|
interface IDatabase extends ITransactor {
|
||||||
function beginTransaction(): void;
|
|
||||||
|
|
||||||
function commit(): void;
|
|
||||||
|
|
||||||
function rollback(): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* - si c'est un insert, retourner l'identifiant autogénéré de la ligne
|
* - si c'est un insert, retourner l'identifiant autogénéré de la ligne
|
||||||
* - sinon retourner le nombre de lignes modifiées en cas de succès, ou false
|
* - sinon retourner le nombre de lignes modifiées en cas de succès, ou false
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
namespace nur\sery\db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ITransactor: un objet qui peut faire des opérations dans une
|
||||||
|
* transaction
|
||||||
|
*/
|
||||||
|
interface ITransactor {
|
||||||
|
/**
|
||||||
|
* Indiquer qu'une transaction va être étendue à tous les objets mentionnés
|
||||||
|
*/
|
||||||
|
function willUpdate(...$transactors): self;
|
||||||
|
|
||||||
|
function inTransaction(): bool;
|
||||||
|
|
||||||
|
/** si $func!==null, la lancer puis commiter la transaction */
|
||||||
|
function beginTransaction(?callable $func=null): void;
|
||||||
|
|
||||||
|
function commit(): void;
|
||||||
|
|
||||||
|
function rollback(): void;
|
||||||
|
}
|
|
@ -4,9 +4,11 @@ namespace nur\sery\db\pdo;
|
||||||
use Generator;
|
use Generator;
|
||||||
use nur\sery\cl;
|
use nur\sery\cl;
|
||||||
use nur\sery\db\IDatabase;
|
use nur\sery\db\IDatabase;
|
||||||
|
use nur\sery\db\ITransactor;
|
||||||
use nur\sery\php\func;
|
use nur\sery\php\func;
|
||||||
use nur\sery\php\time\Date;
|
use nur\sery\php\time\Date;
|
||||||
use nur\sery\php\time\DateTime;
|
use nur\sery\php\time\DateTime;
|
||||||
|
use nur\sery\ValueException;
|
||||||
|
|
||||||
class Pdo implements IDatabase {
|
class Pdo implements IDatabase {
|
||||||
static function with($pdo, ?array $params=null): self {
|
static function with($pdo, ?array $params=null): self {
|
||||||
|
@ -144,16 +146,60 @@ class Pdo implements IDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function beginTransaction(): void {
|
/** @var ITransactor[] */
|
||||||
|
protected ?array $transactors = null;
|
||||||
|
|
||||||
|
function willUpdate(...$transactors): self {
|
||||||
|
foreach ($transactors as $transactor) {
|
||||||
|
if ($transactor instanceof ITransactor) {
|
||||||
|
$this->transactors[] = $transactor;
|
||||||
|
$transactor->willUpdate();
|
||||||
|
} else {
|
||||||
|
throw ValueException::invalid_type($transactor, ITransactor::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inTransaction(): bool {
|
||||||
|
return $this->db()->inTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
function beginTransaction(?callable $func=null): void {
|
||||||
$this->db()->beginTransaction();
|
$this->db()->beginTransaction();
|
||||||
|
if ($this->transactors !== null) {
|
||||||
|
foreach ($this->transactors as $transactor) {
|
||||||
|
$transactor->beginTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($func !== null) {
|
||||||
|
$commited = false;
|
||||||
|
try {
|
||||||
|
func::call($func, $this);
|
||||||
|
$this->commit();
|
||||||
|
$commited = true;
|
||||||
|
} finally {
|
||||||
|
if (!$commited) $this->rollback();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function commit(): void {
|
function commit(): void {
|
||||||
$this->db()->commit();
|
$this->db()->commit();
|
||||||
|
if ($this->transactors !== null) {
|
||||||
|
foreach ($this->transactors as $transactor) {
|
||||||
|
$transactor->commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function rollback(): void {
|
function rollback(): void {
|
||||||
$this->db()->rollBack();
|
$this->db()->rollBack();
|
||||||
|
if ($this->transactors !== null) {
|
||||||
|
foreach ($this->transactors as $transactor) {
|
||||||
|
$transactor->rollback();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -82,7 +82,10 @@ class _query_base extends _base {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEBUG_QUERIES = false;
|
||||||
|
|
||||||
function useStmt(\PDO $db, ?\PDOStatement &$stmt=null, ?string &$sql=null): bool {
|
function useStmt(\PDO $db, ?\PDOStatement &$stmt=null, ?string &$sql=null): bool {
|
||||||
|
if (static::DEBUG_QUERIES) error_log($this->sql); #XXX
|
||||||
if ($this->bindings !== null) {
|
if ($this->bindings !== null) {
|
||||||
$stmt = $db->prepare($this->sql);
|
$stmt = $db->prepare($this->sql);
|
||||||
foreach ($this->bindings as $name => $value) {
|
foreach ($this->bindings as $name => $value) {
|
||||||
|
|
|
@ -4,6 +4,9 @@ namespace nur\sery\db\sqlite;
|
||||||
use Generator;
|
use Generator;
|
||||||
use nur\sery\cl;
|
use nur\sery\cl;
|
||||||
use nur\sery\db\IDatabase;
|
use nur\sery\db\IDatabase;
|
||||||
|
use nur\sery\db\ITransactor;
|
||||||
|
use nur\sery\php\func;
|
||||||
|
use nur\sery\ValueException;
|
||||||
use SQLite3;
|
use SQLite3;
|
||||||
use SQLite3Result;
|
use SQLite3Result;
|
||||||
use SQLite3Stmt;
|
use SQLite3Stmt;
|
||||||
|
@ -82,6 +85,7 @@ class Sqlite implements IDatabase {
|
||||||
$this->migration = $params["migrate"] ?? static::MIGRATE;
|
$this->migration = $params["migrate"] ?? static::MIGRATE;
|
||||||
#
|
#
|
||||||
$defaultAutoOpen = self::params_SCHEMA["auto_open"][1];
|
$defaultAutoOpen = self::params_SCHEMA["auto_open"][1];
|
||||||
|
$this->inTransaction = false;
|
||||||
if ($params["auto_open"] ?? $defaultAutoOpen) {
|
if ($params["auto_open"] ?? $defaultAutoOpen) {
|
||||||
$this->open();
|
$this->open();
|
||||||
}
|
}
|
||||||
|
@ -113,11 +117,14 @@ class Sqlite implements IDatabase {
|
||||||
/** @var SQLite3 */
|
/** @var SQLite3 */
|
||||||
protected $db;
|
protected $db;
|
||||||
|
|
||||||
|
protected bool $inTransaction;
|
||||||
|
|
||||||
function open(): self {
|
function open(): self {
|
||||||
if ($this->db === null) {
|
if ($this->db === null) {
|
||||||
$this->db = new SQLite3($this->file, $this->flags, $this->encryptionKey);
|
$this->db = new SQLite3($this->file, $this->flags, $this->encryptionKey);
|
||||||
_config::with($this->config)->configure($this);
|
_config::with($this->config)->configure($this);
|
||||||
_migration::with($this->migration)->migrate($this);
|
_migration::with($this->migration)->migrate($this);
|
||||||
|
$this->inTransaction = false;
|
||||||
}
|
}
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -126,6 +133,7 @@ class Sqlite implements IDatabase {
|
||||||
if ($this->db !== null) {
|
if ($this->db !== null) {
|
||||||
$this->db->close();
|
$this->db->close();
|
||||||
$this->db = null;
|
$this->db = null;
|
||||||
|
$this->inTransaction = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,16 +180,64 @@ class Sqlite implements IDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function beginTransaction(): void {
|
/** @var ITransactor[] */
|
||||||
|
protected ?array $transactors = null;
|
||||||
|
|
||||||
|
function willUpdate(...$transactors): self {
|
||||||
|
foreach ($transactors as $transactor) {
|
||||||
|
if ($transactor instanceof ITransactor) {
|
||||||
|
$this->transactors[] = $transactor;
|
||||||
|
$transactor->willUpdate();
|
||||||
|
} else {
|
||||||
|
throw ValueException::invalid_type($transactor, ITransactor::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inTransaction(): bool {
|
||||||
|
#XXX très imparfait, mais y'a rien de mieux pour le moment :-(
|
||||||
|
return $this->inTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
function beginTransaction(?callable $func=null): void {
|
||||||
$this->db()->exec("begin");
|
$this->db()->exec("begin");
|
||||||
|
$this->inTransaction = true;
|
||||||
|
if ($this->transactors !== null) {
|
||||||
|
foreach ($this->transactors as $transactor) {
|
||||||
|
$transactor->beginTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($func !== null) {
|
||||||
|
$commited = false;
|
||||||
|
try {
|
||||||
|
func::call($func, $this);
|
||||||
|
$this->commit();
|
||||||
|
$commited = true;
|
||||||
|
} finally {
|
||||||
|
if (!$commited) $this->rollback();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function commit(): void {
|
function commit(): void {
|
||||||
|
$this->inTransaction = false;
|
||||||
$this->db()->exec("commit");
|
$this->db()->exec("commit");
|
||||||
|
if ($this->transactors !== null) {
|
||||||
|
foreach ($this->transactors as $transactor) {
|
||||||
|
$transactor->commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function rollback(): void {
|
function rollback(): void {
|
||||||
$this->db()->exec("commit");
|
$this->inTransaction = false;
|
||||||
|
$this->db()->exec("rollback");
|
||||||
|
if ($this->transactors !== null) {
|
||||||
|
foreach ($this->transactors as $transactor) {
|
||||||
|
$transactor->rollback();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _get(string $query, bool $entireRow=false) {
|
function _get(string $query, bool $entireRow=false) {
|
||||||
|
|
|
@ -32,7 +32,10 @@ class _query_base extends _base {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEBUG_QUERIES = false;
|
||||||
|
|
||||||
function useStmt(SQLite3 $db, ?SQLite3Stmt &$stmt=null, ?string &$sql=null): bool {
|
function useStmt(SQLite3 $db, ?SQLite3Stmt &$stmt=null, ?string &$sql=null): bool {
|
||||||
|
if (static::DEBUG_QUERIES) error_log($this->sql); #XXX
|
||||||
if ($this->bindings !== null) {
|
if ($this->bindings !== null) {
|
||||||
/** @var SQLite3Stmt $stmt */
|
/** @var SQLite3Stmt $stmt */
|
||||||
$stmt = SqliteException::check($db, $db->prepare($this->sql));
|
$stmt = SqliteException::check($db, $db->prepare($this->sql));
|
||||||
|
|
|
@ -233,6 +233,18 @@ class DateTime extends \DateTime {
|
||||||
return static::with($this->add(new \DateInterval("P${nbDays}D")));
|
return static::with($this->add(new \DateInterval("P${nbDays}D")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getElapsedAt(?DateTime $now=null, ?int $resolution=null): string {
|
||||||
|
return Elapsed::format_at($this, $now, $resolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getElapsedSince(?DateTime $now=null, ?int $resolution=null): string {
|
||||||
|
return Elapsed::format_since($this, $now, $resolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getElapsedDelay(?DateTime $now=null, ?int $resolution=null): string {
|
||||||
|
return Elapsed::format_delay($this, $now, $resolution);
|
||||||
|
}
|
||||||
|
|
||||||
function __toString(): string {
|
function __toString(): string {
|
||||||
return $this->format();
|
return $this->format();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,16 @@ class Elapsed {
|
||||||
const DAY = 60 * 60 * 24;
|
const DAY = 60 * 60 * 24;
|
||||||
|
|
||||||
/** @var int résolution */
|
/** @var int résolution */
|
||||||
const RES_SECONDS = 0, RES_MINUTES = 1, RES_HOURS = 2, RES_DAYS = 3;
|
const RESOLUTION_SECONDS = 0, RESOLUTION_MINUTES = 1, RESOLUTION_HOURS = 2, RESOLUTION_DAYS = 3;
|
||||||
|
|
||||||
|
const DEFAULT_RESOLUTION = self::RESOLUTION_SECONDS;
|
||||||
|
|
||||||
private static function format(int $seconds, int $resolution, ?string $prefix=null, ?string $zero=null): string {
|
private static function format(int $seconds, int $resolution, ?string $prefix=null, ?string $zero=null): string {
|
||||||
if ($prefix === null) $prefix = "depuis";
|
if ($prefix === null) $prefix = "depuis";
|
||||||
switch ($resolution) {
|
switch ($resolution) {
|
||||||
case self::RES_DAYS: return self::format_days($seconds, $prefix, $zero);
|
case self::RESOLUTION_DAYS: return self::format_days($seconds, $prefix, $zero);
|
||||||
case self::RES_HOURS: return self::format_hours($seconds, $prefix, $zero);
|
case self::RESOLUTION_HOURS: return self::format_hours($seconds, $prefix, $zero);
|
||||||
case self::RES_MINUTES: return self::format_minutes($seconds, $prefix, $zero);
|
case self::RESOLUTION_MINUTES: return self::format_minutes($seconds, $prefix, $zero);
|
||||||
default: return self::format_seconds($seconds, $prefix, $zero);
|
default: return self::format_seconds($seconds, $prefix, $zero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,27 +124,28 @@ class Elapsed {
|
||||||
return self::format_generic($prefix, $d, 0, 0);
|
return self::format_generic($prefix, $d, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function format_at(DateTime $start, ?DateTime $now=null): string {
|
static function format_at(DateTime $start, ?DateTime $now=null, ?int $resolution=null): string {
|
||||||
$now ??= new DateTime();
|
$now ??= new DateTime();
|
||||||
$seconds = $now->getTimestamp() - $start->getTimestamp();
|
$seconds = $now->getTimestamp() - $start->getTimestamp();
|
||||||
return (new self($seconds))->formatAt();
|
return (new self($seconds, $resolution))->formatAt();
|
||||||
}
|
}
|
||||||
|
|
||||||
static function format_since(DateTime $start, ?DateTime $now=null): string {
|
static function format_since(DateTime $start, ?DateTime $now=null, ?int $resolution=null): string {
|
||||||
$now ??= new DateTime();
|
$now ??= new DateTime();
|
||||||
$seconds = $now->getTimestamp() - $start->getTimestamp();
|
$seconds = $now->getTimestamp() - $start->getTimestamp();
|
||||||
return (new self($seconds))->formatSince();
|
return (new self($seconds, $resolution))->formatSince();
|
||||||
}
|
}
|
||||||
|
|
||||||
static function format_delay(DateTime $start, ?DateTime $now=null): string {
|
static function format_delay(DateTime $start, ?DateTime $now=null, ?int $resolution=null): string {
|
||||||
$now ??= new DateTime();
|
$now ??= new DateTime();
|
||||||
$seconds = $now->getTimestamp() - $start->getTimestamp();
|
$seconds = $now->getTimestamp() - $start->getTimestamp();
|
||||||
return (new self($seconds))->formatDelay();
|
return (new self($seconds, $resolution))->formatDelay();
|
||||||
}
|
}
|
||||||
|
|
||||||
function __construct(int $seconds, int $resolution=self::RES_SECONDS) {
|
function __construct(int $seconds, ?int $resolution=null) {
|
||||||
if ($resolution < self::RES_SECONDS) $resolution = self::RES_SECONDS;
|
$resolution ??= static::DEFAULT_RESOLUTION;
|
||||||
elseif ($resolution > self::RES_DAYS) $resolution = self::RES_DAYS;
|
if ($resolution < self::RESOLUTION_SECONDS) $resolution = self::RESOLUTION_SECONDS;
|
||||||
|
elseif ($resolution > self::RESOLUTION_DAYS) $resolution = self::RESOLUTION_DAYS;
|
||||||
$this->seconds = $seconds;
|
$this->seconds = $seconds;
|
||||||
$this->resolution = $resolution;
|
$this->resolution = $resolution;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue