diff --git a/src/db/Capacitor.php b/src/db/Capacitor.php index 0c2f161..6341741 100644 --- a/src/db/Capacitor.php +++ b/src/db/Capacitor.php @@ -64,7 +64,7 @@ class Capacitor implements ITransactor { return $this->db()->inTransaction(); } - function beginTransaction(?callable $func=null): void { + function beginTransaction(?callable $func=null, bool $commit=true): void { if ($this->subManageTransactions === null && $this->subChannels !== null) { foreach ($this->subChannels as $channel) { $name = $channel->getName(); @@ -81,10 +81,12 @@ class Capacitor implements ITransactor { $commited = false; try { func::call($func, $this); - $this->commit(); - $commited = true; + if ($commit) { + $this->commit(); + $commited = true; + } } finally { - if (!$commited) $this->rollback(); + if ($commit && !$commited) $this->rollback(); } } } diff --git a/src/db/ITransactor.php b/src/db/ITransactor.php index a485a7b..d9e2ccc 100644 --- a/src/db/ITransactor.php +++ b/src/db/ITransactor.php @@ -13,8 +13,16 @@ interface ITransactor { function inTransaction(): bool; - /** si $func!==null, la lancer puis commiter la transaction */ - function beginTransaction(?callable $func=null): void; + /** + * démarrer une transaction + * + * si $func!==null, l'apppeler. ensuite, si $commit===true, commiter la + * transaction. si une erreur se produit lors de l'appel de la fonction, + * annuler la transaction + * + * $func est appelée avec la signature ($this) + */ + function beginTransaction(?callable $func=null, bool $commit=true): void; function commit(): void; diff --git a/src/db/pdo/Pdo.php b/src/db/pdo/Pdo.php index 50bf576..393a310 100644 --- a/src/db/pdo/Pdo.php +++ b/src/db/pdo/Pdo.php @@ -165,7 +165,7 @@ class Pdo implements IDatabase { return $this->db()->inTransaction(); } - function beginTransaction(?callable $func=null): void { + function beginTransaction(?callable $func=null, bool $commit=true): void { $this->db()->beginTransaction(); if ($this->transactors !== null) { foreach ($this->transactors as $transactor) { @@ -176,10 +176,12 @@ class Pdo implements IDatabase { $commited = false; try { func::call($func, $this); - $this->commit(); - $commited = true; + if ($commit) { + $this->commit(); + $commited = true; + } } finally { - if (!$commited) $this->rollback(); + if ($commit && !$commited) $this->rollback(); } } } diff --git a/src/db/sqlite/Sqlite.php b/src/db/sqlite/Sqlite.php index 2c30763..dc8266f 100644 --- a/src/db/sqlite/Sqlite.php +++ b/src/db/sqlite/Sqlite.php @@ -200,7 +200,7 @@ class Sqlite implements IDatabase { return $this->inTransaction; } - function beginTransaction(?callable $func=null): void { + function beginTransaction(?callable $func=null, bool $commit=true): void { $this->db()->exec("begin"); $this->inTransaction = true; if ($this->transactors !== null) { @@ -212,10 +212,12 @@ class Sqlite implements IDatabase { $commited = false; try { func::call($func, $this); - $this->commit(); - $commited = true; + if ($commit) { + $this->commit(); + $commited = true; + } } finally { - if (!$commited) $this->rollback(); + if ($commit && !$commited) $this->rollback(); } } } diff --git a/src/ext/spreadsheet/SpoutBuilder.php b/src/ext/spreadsheet/SpoutBuilder.php index e05bfba..ad0d72b 100644 --- a/src/ext/spreadsheet/SpoutBuilder.php +++ b/src/ext/spreadsheet/SpoutBuilder.php @@ -4,6 +4,7 @@ namespace nur\sery\ext\spreadsheet; use nur\sery\file\csv\AbstractBuilder; use nur\sery\file\csv\TAbstractBuilder; use nur\sery\os\path; +use nur\sery\php\func; use nur\sery\php\time\Date; use nur\sery\php\time\DateTime; use nur\sery\web\http; @@ -77,7 +78,7 @@ class SpoutBuilder extends AbstractBuilder { /** * @param string|int|null $wsname */ - function setWsname($wsname): self { + function setWsname($wsname, ?array $params=null): self { $ss = $this->ss; $this->rowStyle = self::STYLE_ROW; if ($this->firstSheet) { @@ -85,11 +86,42 @@ class SpoutBuilder extends AbstractBuilder { $ws = $ss->getCurrentSheet(); } else { $ws = $ss->addNewSheetAndMakeItCurrent(); + $this->wroteHeaders = false; + $this->built = false; } if ($wsname !== null) $ws->setName($wsname); - $ws->setSheetView((new SheetView()) - ->setFreezeRow(2) - ); + $sheetView = (new SheetView()) + ->setFreezeRow(2); + $ws->setSheetView($sheetView); + if ($params !== null) { + if (array_key_exists("schema", $params)) { + $this->schema = $params["schema"] ?? null; + } + if (array_key_exists("headers", $params)) { + $this->headers = $params["headers"] ?? null; + } + if (array_key_exists("rows", $params)) { + $rows = $params["rows"] ?? null; + if (is_callable($rows)) $rows = $rows(); + $this->rows = $rows; + } + if (array_key_exists("cook_func", $params)) { + $cookFunc = $params["cook_func"] ?? null; + $cookCtx = $cookArgs = null; + if ($cookFunc !== null) { + func::ensure_func($cookFunc, $this, $cookArgs); + $cookCtx = func::_prepare($cookFunc); + } + $this->cookCtx = $cookCtx; + $this->cookArgs = $cookArgs; + } + if (array_key_exists("type_numeric", $params)) { + $this->typeNumeric = boolval($params["type_numeric"] ?? static::TYPE_NUMERIC); + } + if (array_key_exists("type_date", $params)) { + $this->typeDate = boolval($params["type_date"] ?? static::TYPE_DATE); + } + } return $this; } diff --git a/src/file/csv/AbstractBuilder.php b/src/file/csv/AbstractBuilder.php index 8df2e39..a21b87a 100644 --- a/src/file/csv/AbstractBuilder.php +++ b/src/file/csv/AbstractBuilder.php @@ -105,7 +105,7 @@ abstract class AbstractBuilder extends TempStream implements IBuilder { } if ($rows !== null) { foreach ($rows as $row) { - $this->write($row); + $this->write(cl::with($row)); } } if ($unsetRows) $this->rows = null; @@ -132,14 +132,30 @@ abstract class AbstractBuilder extends TempStream implements IBuilder { abstract protected function _checkOk(): bool; - function build(?iterable $rows=null): bool { - $this->_build($rows); - return $this->_checkOk(); + protected bool $built = false, $closed = false; + + function build(?iterable $rows=null, bool $close=true): bool { + $ok = true; + if (!$this->built) { + $this->_build($rows); + $this->built = true; + } + if ($close && !$this->closed) { + $ok = $this->_checkOk(); + $this->closed = true; + } + return $ok; } function sendFile(?iterable $rows=null): int { - $this->_build($rows); - if (!$this->_checkOk()) return 0; + if (!$this->built) { + $this->_build($rows); + $this->built = true; + } + if (!$this->closed) { + if (!$this->_checkOk()) return 0; + $this->closed = true; + } $this->sendHeaders(); return $this->fpassthru(); }