Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
8094346358 | |||
4037bf2042 | |||
a9f9cbb9e5 | |||
559feda663 | |||
d4d51ffcea | |||
27567166aa | |||
2dab39a35c | |||
a1238f044a |
@ -1,5 +1,3 @@
|
|||||||
## Release 0.5.1p82 du 12/05/2025-15:31
|
|
||||||
|
|
||||||
## Release 0.5.1p74 du 12/05/2025-15:28
|
## Release 0.5.1p74 du 12/05/2025-15:28
|
||||||
|
|
||||||
* `d274a65` améliorer status
|
* `d274a65` améliorer status
|
||||||
|
@ -19,11 +19,8 @@ git checkout dev82
|
|||||||
|
|
||||||
prel -C
|
prel -C
|
||||||
|
|
||||||
commit="$(git log --grep="Init changelog . version ${version}p82" --format=%H)" &&
|
commit="$(git log --grep="Init changelog . version ${version}p82" --format=%H)"
|
||||||
echo "commit=$commit"
|
|
||||||
|
|
||||||
git checkout dev74
|
git checkout dev74
|
||||||
|
|
||||||
git cherry-pick "$commit"
|
git cherry-pick "$commit"
|
||||||
pp -a
|
pp -a
|
||||||
~~~
|
~~~
|
||||||
|
@ -426,7 +426,7 @@ EOF
|
|||||||
$(qvals echo "$(awk <"$changelog" '
|
$(qvals echo "$(awk <"$changelog" '
|
||||||
BEGIN { p = 0 }
|
BEGIN { p = 0 }
|
||||||
p == 0 && $0 == "" { p = 1; next }
|
p == 0 && $0 == "" { p = 1; next }
|
||||||
p == 1 { print }
|
p == 1 { gsub(/\$/, "\\$", $0); print }
|
||||||
')") >CHANGES.md
|
')") >CHANGES.md
|
||||||
git add CHANGES.md
|
git add CHANGES.md
|
||||||
EOF
|
EOF
|
||||||
|
@ -177,14 +177,6 @@ class A {
|
|||||||
return $pvalue;
|
return $pvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static final function shift(?array &$dest, int $count=1, $default=null) {
|
|
||||||
if ($dest === null) return null;
|
|
||||||
$values = array_slice($dest, 0, $count);
|
|
||||||
$dest = array_slice($dest, $count);
|
|
||||||
if ($values === []) return $default;
|
|
||||||
else return $count == 1? $values[0]: $values;
|
|
||||||
}
|
|
||||||
|
|
||||||
static final function pop(&$dest, $key, $default=null) {
|
static final function pop(&$dest, $key, $default=null) {
|
||||||
if ($dest === null) return $default;
|
if ($dest === null) return $default;
|
||||||
self::ensure_narray($dest);
|
self::ensure_narray($dest);
|
||||||
|
@ -86,12 +86,6 @@ class cv {
|
|||||||
$b = $tmp;
|
$b = $tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** cloner une valeur */
|
|
||||||
static final function clone($value) {
|
|
||||||
if (is_object($value)) $value = clone $value;
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
/** mettre à jour $dest avec $value si $cond($value) est vrai */
|
/** mettre à jour $dest avec $value si $cond($value) est vrai */
|
||||||
@ -203,29 +197,19 @@ class cv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* retourner [$bool, $scalar, $array] initialisés chacun en fonction du type
|
* retourner [$bool, $string, $array] initialisés chacun en fonction du type
|
||||||
* de $value.
|
* de $value.
|
||||||
*
|
*
|
||||||
* @throws ValueException si $value n'est d'aucun de ces types
|
* @throws ValueException si $value n'est d'aucun de ces types
|
||||||
*/
|
*/
|
||||||
static final function check_bsa($value, ?string $prefix=null, bool $throw_exception=true): array {
|
static final function check_bsa($value, ?string $prefix=null, bool $throw_exception=true): array {
|
||||||
$bool = is_bool($value)? $value : null;
|
$bool = is_bool($value)? $value : null;
|
||||||
$scalar = !is_bool($value) && is_scalar($value)? $value : null;
|
$string = is_string($value)? $value : null;
|
||||||
$array = is_array($value)? $value : null;
|
$array = is_array($value)? $value : null;
|
||||||
if ($bool === null && $scalar === null && $array === null && $throw_exception) {
|
if ($bool === null && $string === null && $array === null && $throw_exception) {
|
||||||
throw ValueException::invalid_kind($value, "value", $prefix);
|
throw ValueException::invalid_kind($value, "value", $prefix);
|
||||||
} else {
|
} else {
|
||||||
return [$bool, $scalar, $array];
|
return [$bool, $string, $array];
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static final function subclass_of($value, $class): bool {
|
|
||||||
if (is_string($value)) {
|
|
||||||
return $value === $class || is_subclass_of($value, $class);
|
|
||||||
} elseif (is_object($value)) {
|
|
||||||
return $value instanceof $class;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace nulib\db;
|
namespace nulib\db;
|
||||||
|
|
||||||
use nulib\cl;
|
|
||||||
use nulib\php\func;
|
use nulib\php\func;
|
||||||
use nulib\ValueException;
|
use nulib\ValueException;
|
||||||
use Traversable;
|
use Traversable;
|
||||||
@ -169,13 +168,6 @@ class Capacitor implements ITransactor {
|
|||||||
return $this->storage->_delete($this->channel, $filter, $func, $args);
|
return $this->storage->_delete($this->channel, $filter, $func, $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbUpdate(array $update) {
|
|
||||||
return $this->storage->db()->exec(cl::merge([
|
|
||||||
"update",
|
|
||||||
"table" => $this->getTableName(),
|
|
||||||
], $update));
|
|
||||||
}
|
|
||||||
|
|
||||||
function close(): void {
|
function close(): void {
|
||||||
$this->storage->close();
|
$this->storage->close();
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,7 @@ class CapacitorChannel implements ITransactor {
|
|||||||
|
|
||||||
const TABLE_NAME = null;
|
const TABLE_NAME = null;
|
||||||
|
|
||||||
protected function COLUMN_DEFINITIONS(): ?array {
|
const COLUMN_DEFINITIONS = null;
|
||||||
return static::COLUMN_DEFINITIONS;
|
|
||||||
} const COLUMN_DEFINITIONS = null;
|
|
||||||
|
|
||||||
const PRIMARY_KEYS = null;
|
const PRIMARY_KEYS = null;
|
||||||
|
|
||||||
@ -30,17 +28,19 @@ class CapacitorChannel implements ITransactor {
|
|||||||
static function verifix_name(?string &$name, ?string &$tableName=null): void {
|
static function verifix_name(?string &$name, ?string &$tableName=null): void {
|
||||||
if ($name !== null) {
|
if ($name !== null) {
|
||||||
$name = strtolower($name);
|
$name = strtolower($name);
|
||||||
$tableName ??= str_replace("-", "_", $name) . "_channel";
|
if ($tableName === null) {
|
||||||
|
$tableName = str_replace("-", "_", $name) . "_channel";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$name = static::class;
|
$name = static::class;
|
||||||
if ($name === self::class) {
|
if ($name === self::class) {
|
||||||
$name = "default";
|
$name = "default";
|
||||||
$tableName ??= "default_channel";
|
if ($tableName === null) $tableName = "default_channel";
|
||||||
} else {
|
} else {
|
||||||
$name = preg_replace('/^.*\\\\/', "", $name);
|
$name = preg_replace('/^.*\\\\/', "", $name);
|
||||||
$name = preg_replace('/Channel$/', "", $name);
|
$name = preg_replace('/Channel$/', "", $name);
|
||||||
$name = lcfirst($name);
|
$name = lcfirst($name);
|
||||||
$tableName ??= str::camel2us($name);
|
if ($tableName === null) $tableName = str::camel2us($name);
|
||||||
$name = strtolower($name);
|
$name = strtolower($name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ class CapacitorChannel implements ITransactor {
|
|||||||
$this->useCache = static::USE_CACHE;
|
$this->useCache = static::USE_CACHE;
|
||||||
$this->setup = false;
|
$this->setup = false;
|
||||||
$this->created = false;
|
$this->created = false;
|
||||||
$columnDefinitions = $this->COLUMN_DEFINITIONS();
|
$columnDefinitions = cl::withn(static::COLUMN_DEFINITIONS);
|
||||||
$primaryKeys = cl::withn(static::PRIMARY_KEYS);
|
$primaryKeys = cl::withn(static::PRIMARY_KEYS);
|
||||||
$migration = cl::withn(static::MIGRATION);
|
$migration = cl::withn(static::MIGRATION);
|
||||||
$lastMkey = 1;
|
$lastMkey = 1;
|
||||||
@ -482,10 +482,6 @@ class CapacitorChannel implements ITransactor {
|
|||||||
return $this->capacitor->delete($filter, $func, $args);
|
return $this->capacitor->delete($filter, $func, $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbUpdate(array $update) {
|
|
||||||
return $this->capacitor->dbUpdate($update);
|
|
||||||
}
|
|
||||||
|
|
||||||
function close(): void {
|
function close(): void {
|
||||||
$this->capacitor->close();
|
$this->capacitor->close();
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ namespace nulib\db;
|
|||||||
|
|
||||||
use nulib\cl;
|
use nulib\cl;
|
||||||
use nulib\db\_private\_migration;
|
use nulib\db\_private\_migration;
|
||||||
|
use nulib\db\cache\cache;
|
||||||
use nulib\php\func;
|
use nulib\php\func;
|
||||||
use nulib\ValueException;
|
use nulib\ValueException;
|
||||||
use Traversable;
|
use Traversable;
|
||||||
|
116
php/src/db/cache/CacheChannel.php
vendored
Normal file
116
php/src/db/cache/CacheChannel.php
vendored
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<?php
|
||||||
|
namespace nulib\db\cache;
|
||||||
|
|
||||||
|
use nulib\cl;
|
||||||
|
use nulib\db\CapacitorChannel;
|
||||||
|
use nulib\php\time\DateTime;
|
||||||
|
use nulib\php\time\Delay;
|
||||||
|
|
||||||
|
class CacheChannel extends CapacitorChannel {
|
||||||
|
/** @var int durée de vie par défaut du cache */
|
||||||
|
const DURATION = "1D"; // jusqu'au lendemain
|
||||||
|
|
||||||
|
const INCLUDES = null;
|
||||||
|
|
||||||
|
const EXCLUDES = null;
|
||||||
|
|
||||||
|
const COLUMN_DEFINITIONS = [
|
||||||
|
"group_id" => "varchar(64) not null",
|
||||||
|
"id" => "varchar(64) not null",
|
||||||
|
"date_start" => "datetime",
|
||||||
|
"duration_" => "text",
|
||||||
|
"primary key (group_id, id)",
|
||||||
|
];
|
||||||
|
|
||||||
|
static function get_cache_ids($id): array {
|
||||||
|
if (is_array($id)) {
|
||||||
|
$keys = array_keys($id);
|
||||||
|
if (array_key_exists("group_id", $id)) $groupIdKey = "group_id";
|
||||||
|
else $groupIdKey = $keys[1] ?? null;
|
||||||
|
$groupId = $id[$groupIdKey] ?? "";
|
||||||
|
if (array_key_exists("id", $id)) $idKey = "id";
|
||||||
|
else $idKey = $keys[0] ?? null;
|
||||||
|
$id = $id[$idKey] ?? "";
|
||||||
|
} else {
|
||||||
|
$groupId = "";
|
||||||
|
}
|
||||||
|
if (preg_match('/^(.*\\\\)?([^\\\\]+)$/', $groupId, $ms)) {
|
||||||
|
# si le groupe est une classe, faire un hash du package pour limiter la
|
||||||
|
# longueur du groupe
|
||||||
|
[$package, $groupId] = [$ms[1], $ms[2]];
|
||||||
|
$package = substr(md5($package), 0, 4);
|
||||||
|
$groupId = "${groupId}_$package";
|
||||||
|
}
|
||||||
|
return ["group_id" => $groupId, "id" => $id];
|
||||||
|
}
|
||||||
|
|
||||||
|
function __construct(?string $duration=null, ?string $name=null) {
|
||||||
|
parent::__construct($name);
|
||||||
|
$this->duration = $duration ?? static::DURATION;
|
||||||
|
$this->includes = static::INCLUDES;
|
||||||
|
$this->excludes = static::EXCLUDES;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected string $duration;
|
||||||
|
|
||||||
|
protected ?array $includes;
|
||||||
|
|
||||||
|
protected ?array $excludes;
|
||||||
|
|
||||||
|
function getItemValues($item): ?array {
|
||||||
|
return cl::merge(self::get_cache_ids($item), [
|
||||||
|
"item" => null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCreate($item, array $values, ?array $alwaysNull, ?string $duration=null): ?array {
|
||||||
|
$now = new DateTime();
|
||||||
|
$duration ??= $this->duration;
|
||||||
|
return [
|
||||||
|
"date_start" => $now,
|
||||||
|
"duration" => new Delay($duration, $now),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function onUpdate($item, array $values, array $pvalues, ?string $duration=null): ?array {
|
||||||
|
$now = new DateTime();
|
||||||
|
$duration ??= $this->duration;
|
||||||
|
return [
|
||||||
|
"date_start" => $now,
|
||||||
|
"duration" => new Delay($duration, $now),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldUpdate($id, bool $noCache=false): bool {
|
||||||
|
if ($noCache) return true;
|
||||||
|
|
||||||
|
$cacheIds = self::get_cache_ids($id);
|
||||||
|
$groupId = $cacheIds["group_id"];
|
||||||
|
if ($groupId) {
|
||||||
|
$includes = $this->includes;
|
||||||
|
$shouldInclude = $includes !== null && in_array($groupId, $includes);
|
||||||
|
$excludes = $this->excludes;
|
||||||
|
$shouldExclude = $excludes !== null && in_array($groupId, $excludes);
|
||||||
|
if (!$shouldInclude || $shouldExclude) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$found = false;
|
||||||
|
$expired = false;
|
||||||
|
$this->each($cacheIds,
|
||||||
|
function($item, $values) use (&$found, &$expired) {
|
||||||
|
$found = true;
|
||||||
|
$expired = $values["duration"]->isElapsed();
|
||||||
|
});
|
||||||
|
return !$found || $expired;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCached($id, ?string $duration=null): void {
|
||||||
|
$cacheIds = self::get_cache_ids($id);
|
||||||
|
$this->charge($cacheIds, null, [$duration]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetCached($id) {
|
||||||
|
$cacheIds = self::get_cache_ids($id);
|
||||||
|
$this->delete($cacheIds);
|
||||||
|
}
|
||||||
|
}
|
51
php/src/db/cache/RowsChannel.php
vendored
Normal file
51
php/src/db/cache/RowsChannel.php
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
namespace nulib\db\cache;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use IteratorAggregate;
|
||||||
|
use nulib\cl;
|
||||||
|
use nulib\db\CapacitorChannel;
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
|
class RowsChannel extends CapacitorChannel implements IteratorAggregate {
|
||||||
|
const COLUMN_DEFINITIONS = [
|
||||||
|
"key" => "varchar(128) primary key not null",
|
||||||
|
"all_values" => "mediumtext",
|
||||||
|
];
|
||||||
|
|
||||||
|
function __construct($id, callable $builder, ?string $duration=null) {
|
||||||
|
$this->cacheIds = $cacheIds = CacheChannel::get_cache_ids($id);
|
||||||
|
$this->builder = Closure::fromCallable($builder);
|
||||||
|
$this->duration = $duration;
|
||||||
|
$name = "{$cacheIds["group_id"]}-{$cacheIds["id"]}";
|
||||||
|
parent::__construct($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected array $cacheIds;
|
||||||
|
|
||||||
|
protected Closure $builder;
|
||||||
|
|
||||||
|
protected ?string $duration = null;
|
||||||
|
|
||||||
|
function getItemValues($item): ?array {
|
||||||
|
$key = array_keys($item)[0];
|
||||||
|
$row = $item[$key];
|
||||||
|
return [
|
||||||
|
"key" => $key,
|
||||||
|
"item" => $row,
|
||||||
|
"all_values" => implode(" ", cl::filter_n(cl::with($row))),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIterator(): Traversable {
|
||||||
|
$cm = cache::get();
|
||||||
|
if ($cm->shouldUpdate($this->cacheIds)) {
|
||||||
|
$this->capacitor->reset();
|
||||||
|
foreach (($this->builder)() as $key => $row) {
|
||||||
|
$this->charge([$key => $row]);
|
||||||
|
}
|
||||||
|
$cm->setCached($this->cacheIds, $this->duration);
|
||||||
|
}
|
||||||
|
return $this->discharge(false);
|
||||||
|
}
|
||||||
|
}
|
37
php/src/db/cache/cache.php
vendored
Normal file
37
php/src/db/cache/cache.php
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
namespace nulib\db\cache;
|
||||||
|
|
||||||
|
use nulib\db\Capacitor;
|
||||||
|
use nulib\db\CapacitorStorage;
|
||||||
|
use nulib\db\sqlite\SqliteStorage;
|
||||||
|
|
||||||
|
class cache {
|
||||||
|
protected static ?CapacitorStorage $storage = null;
|
||||||
|
|
||||||
|
static function set_storage(CapacitorStorage $storage): CapacitorStorage {
|
||||||
|
return self::$storage = $storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function get_storage(): CapacitorStorage {
|
||||||
|
return self::$storage ??= new SqliteStorage("");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static ?CacheChannel $channel = null;
|
||||||
|
|
||||||
|
static function set(?CacheChannel $channel): CacheChannel {
|
||||||
|
$channel ??= new CacheChannel();
|
||||||
|
new Capacitor(self::get_storage(), $channel);
|
||||||
|
return self::$channel = $channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function get(): CacheChannel {
|
||||||
|
if (self::$channel !== null) return self::$channel;
|
||||||
|
else return self::set(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function new(?RowsChannel $channel, $id=null, ?callable $builder=null): RowsChannel {
|
||||||
|
$channel ??= new RowsChannel($id, $builder);
|
||||||
|
new Capacitor(self::get_storage(), $channel);
|
||||||
|
return $channel;
|
||||||
|
}
|
||||||
|
}
|
@ -30,11 +30,7 @@ class Pgsql implements IDatabase {
|
|||||||
|
|
||||||
|
|
||||||
protected const OPTIONS = [
|
protected const OPTIONS = [
|
||||||
# XXX désactiver les connexions persistantes par défaut
|
"persistent" => true,
|
||||||
# pour réactiver par défaut, il faudrait vérifier la connexion à chaque fois
|
|
||||||
# qu'elle est ouverte avec un "select 1". en effet, l'expérience jusqu'ici
|
|
||||||
# est que la première connexion après un long timeout échoue
|
|
||||||
"persistent" => false,
|
|
||||||
"force_new" => false,
|
"force_new" => false,
|
||||||
"serial_support" => true,
|
"serial_support" => true,
|
||||||
];
|
];
|
||||||
|
@ -40,6 +40,4 @@ interface IReader extends _IFile {
|
|||||||
function unserialize(?array $options=null, bool $close=true, bool $alreadyLocked=false);
|
function unserialize(?array $options=null, bool $close=true, bool $alreadyLocked=false);
|
||||||
|
|
||||||
function copyTo(IWriter $dest, bool $closeWriter=false, bool $closeReader=true): void;
|
function copyTo(IWriter $dest, bool $closeWriter=false, bool $closeReader=true): void;
|
||||||
|
|
||||||
function setCsvFlavour(?string $flavour): void;
|
|
||||||
}
|
}
|
||||||
|
@ -299,8 +299,8 @@ class Stream extends AbstractIterator implements IReader, IWriter {
|
|||||||
|
|
||||||
/** retourner le contenu du fichier sous forme de chaine */
|
/** retourner le contenu du fichier sous forme de chaine */
|
||||||
function getContents(bool $close=true, bool $alreadyLocked=false): string {
|
function getContents(bool $close=true, bool $alreadyLocked=false): string {
|
||||||
$useLocking = $this->useLocking && !$alreadyLocked;
|
$useLocking = $this->useLocking;
|
||||||
if ($useLocking) $this->lock(LOCK_SH);
|
if ($useLocking && !$alreadyLocked) $this->lock(LOCK_SH);
|
||||||
try {
|
try {
|
||||||
return IOException::ensure_valid(stream_get_contents($this->fd), $this->throwOnError);
|
return IOException::ensure_valid(stream_get_contents($this->fd), $this->throwOnError);
|
||||||
} finally {
|
} finally {
|
||||||
@ -380,9 +380,7 @@ class Stream extends AbstractIterator implements IReader, IWriter {
|
|||||||
/** @throws IOException */
|
/** @throws IOException */
|
||||||
function ftruncate(int $size=0, bool $rewind=true): self {
|
function ftruncate(int $size=0, bool $rewind=true): self {
|
||||||
$fd = $this->getResource();
|
$fd = $this->getResource();
|
||||||
$r = ftruncate($fd, $size);
|
IOException::ensure_valid(ftruncate($fd, $size), $this->throwOnError);
|
||||||
$this->stat = null;
|
|
||||||
IOException::ensure_valid($r, $this->throwOnError);
|
|
||||||
if ($rewind) rewind($fd);
|
if ($rewind) rewind($fd);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -392,7 +390,6 @@ class Stream extends AbstractIterator implements IReader, IWriter {
|
|||||||
$fd = $this->getResource();
|
$fd = $this->getResource();
|
||||||
if ($length === null) $r = fwrite($fd, $data);
|
if ($length === null) $r = fwrite($fd, $data);
|
||||||
else $r = fwrite($fd, $data, $length);
|
else $r = fwrite($fd, $data, $length);
|
||||||
$this->stat = null;
|
|
||||||
return IOException::ensure_valid($r, $this->throwOnError);
|
return IOException::ensure_valid($r, $this->throwOnError);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,13 +403,9 @@ class Stream extends AbstractIterator implements IReader, IWriter {
|
|||||||
$line[] = strval($col);
|
$line[] = strval($col);
|
||||||
}
|
}
|
||||||
$line = implode($sep, $line);
|
$line = implode($sep, $line);
|
||||||
$r = fwrite($fd, "$line\n");
|
IOException::ensure_valid(fwrite($fd, "$line\n"), $this->throwOnError);
|
||||||
$this->stat = null;
|
|
||||||
IOException::ensure_valid($r, $this->throwOnError);
|
|
||||||
} else {
|
} else {
|
||||||
$r = fputcsv($fd, $row, $params[0], $params[1], $params[2]);
|
IOException::ensure_valid(fputcsv($fd, $row, $params[0], $params[1], $params[2]), $this->throwOnError);
|
||||||
$this->stat = null;
|
|
||||||
IOException::ensure_valid($r, $this->throwOnError);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,8 +471,8 @@ class Stream extends AbstractIterator implements IReader, IWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function putContents(string $contents, bool $close=true, bool $alreadyLocked=false): void {
|
function putContents(string $contents, bool $close=true, bool $alreadyLocked=false): void {
|
||||||
$useLocking = $this->useLocking && !$alreadyLocked;
|
$useLocking = $this->useLocking;
|
||||||
if ($useLocking) $this->lock(LOCK_EX);
|
if ($useLocking && !$alreadyLocked) $this->lock(LOCK_EX);
|
||||||
try {
|
try {
|
||||||
$this->fwrite($contents);
|
$this->fwrite($contents);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
namespace nulib\file\csv;
|
namespace nulib\file\csv;
|
||||||
|
|
||||||
use nulib\file;
|
use nulib\file;
|
||||||
use nulib\file\_IFile;
|
|
||||||
use nulib\file\FileReader;
|
use nulib\file\FileReader;
|
||||||
use nulib\file\IReader;
|
|
||||||
use nulib\file\tab\AbstractReader;
|
use nulib\file\tab\AbstractReader;
|
||||||
use nulib\file\tab\TAbstractReader;
|
use nulib\file\tab\TAbstractReader;
|
||||||
|
|
||||||
@ -22,12 +20,7 @@ class CsvReader extends AbstractReader {
|
|||||||
protected ?string $inputEncoding;
|
protected ?string $inputEncoding;
|
||||||
|
|
||||||
function getIterator() {
|
function getIterator() {
|
||||||
$input = $this->input;
|
$reader = new FileReader(file::fix_dash($this->input));
|
||||||
if ($input instanceof IReader) {
|
|
||||||
$reader = $input;
|
|
||||||
} else {
|
|
||||||
$reader = new FileReader(file::fix_dash($input));
|
|
||||||
}
|
|
||||||
$inputEncoding = $this->inputEncoding;
|
$inputEncoding = $this->inputEncoding;
|
||||||
if ($inputEncoding !== null) {
|
if ($inputEncoding !== null) {
|
||||||
$reader->appendFilter("convert.iconv.$inputEncoding.utf-8");
|
$reader->appendFilter("convert.iconv.$inputEncoding.utf-8");
|
||||||
|
@ -478,17 +478,11 @@ class func {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static function with($func, ?array $args=null, bool $strict=true): self {
|
static function with($func, ?array $args=null, bool $strict=true): self {
|
||||||
if ($func instanceof self) return $func;
|
|
||||||
$func = self::_with($func, $args, $strict, $reason);
|
$func = self::_with($func, $args, $strict, $reason);
|
||||||
if ($func !== null) return $func;
|
if ($func !== null) return $func;
|
||||||
throw self::not_a_callable($func, $reason);
|
throw self::not_a_callable($func, $reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
static function withn($func, ?array $args=null, bool $strict=true): ?self {
|
|
||||||
if ($func === null) return null;
|
|
||||||
else return self::with($func, $args, $strict);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function ensure($func, ?array $args=null, bool $strict=true): self {
|
static function ensure($func, ?array $args=null, bool $strict=true): self {
|
||||||
$func = self::with($func, $args, $strict);
|
$func = self::with($func, $args, $strict);
|
||||||
if (!$func->isBound()) {
|
if (!$func->isBound()) {
|
||||||
|
@ -29,7 +29,7 @@ class DateInterval extends \DateInterval {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function __construct($duration) {
|
function __construct($duration) {
|
||||||
if (is_numeric($duration)) $duration = "PT${duration}S";
|
if (is_int($duration)) $duration = "PT${duration}S";
|
||||||
if ($duration instanceof \DateInterval) {
|
if ($duration instanceof \DateInterval) {
|
||||||
$this->y = $duration->y;
|
$this->y = $duration->y;
|
||||||
$this->m = $duration->m;
|
$this->m = $duration->m;
|
||||||
|
@ -3,7 +3,6 @@ namespace nulib\php\time;
|
|||||||
|
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use nulib\ValueException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Delay: une durée jusqu'à un moment destination. le moment destination
|
* Class Delay: une durée jusqu'à un moment destination. le moment destination
|
||||||
@ -116,10 +115,6 @@ class Delay {
|
|||||||
$this->repr = $repr;
|
$this->repr = $repr;
|
||||||
}
|
}
|
||||||
|
|
||||||
function __clone() {
|
|
||||||
$this->dest = clone $this->dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
function __serialize(): array {
|
function __serialize(): array {
|
||||||
return [$this->dest, $this->repr];
|
return [$this->dest, $this->repr];
|
||||||
}
|
}
|
||||||
@ -135,7 +130,7 @@ class Delay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addDuration($duration) {
|
function addDuration($duration) {
|
||||||
if (is_numeric($duration) && $duration < 0) {
|
if (is_int($duration) && $duration < 0) {
|
||||||
$this->dest->sub(DateInterval::with(-$duration));
|
$this->dest->sub(DateInterval::with(-$duration));
|
||||||
} else {
|
} else {
|
||||||
$this->dest->add(DateInterval::with($duration));
|
$this->dest->add(DateInterval::with($duration));
|
||||||
@ -143,7 +138,7 @@ class Delay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function subDuration($duration) {
|
function subDuration($duration) {
|
||||||
if (is_numeric($duration) && $duration < 0) {
|
if (is_int($duration) && $duration < 0) {
|
||||||
$this->dest->add(DateInterval::with(-$duration));
|
$this->dest->add(DateInterval::with(-$duration));
|
||||||
} else {
|
} else {
|
||||||
$this->dest->sub(DateInterval::with($duration));
|
$this->dest->sub(DateInterval::with($duration));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user