modifs.mineures sans commentaires
This commit is contained in:
		
							parent
							
								
									c1ce91ec81
								
							
						
					
					
						commit
						c4e1496b82
					
				
							
								
								
									
										39
									
								
								src/A.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/A.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery;
 | 
			
		||||
 | 
			
		||||
use Traversable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class A: gestion de tableaux ou d'instances de {@link IArrayWrapper}
 | 
			
		||||
 *
 | 
			
		||||
 * contrairement à {@link cl}, les méthodes de cette classes sont plutôt conçues
 | 
			
		||||
 * pour modifier le tableau en place
 | 
			
		||||
 */
 | 
			
		||||
class A {
 | 
			
		||||
  /**
 | 
			
		||||
   * s'assurer que $array est un array non null. retourner true si $array n'a
 | 
			
		||||
   * pas été modifié (s'il était déjà un array), false sinon.
 | 
			
		||||
   */
 | 
			
		||||
  static final function ensure_array(&$array): bool {
 | 
			
		||||
    if (is_array($array)) return true;
 | 
			
		||||
    if ($array instanceof IArrayWrapper) $array = $array->wrappedArray();
 | 
			
		||||
    if ($array === null || $array === false) $array = [];
 | 
			
		||||
    elseif ($array instanceof Traversable) $array =  iterator_to_array($array);
 | 
			
		||||
    else $array = [$array];
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * s'assurer que $array est un array s'il est non null. retourner true si
 | 
			
		||||
   * $array n'a pas été modifié (s'il était déjà un array ou s'il valait null).
 | 
			
		||||
   */
 | 
			
		||||
  static final function ensure_narray(&$array): bool {
 | 
			
		||||
    if ($array === null || is_array($array)) return true;
 | 
			
		||||
    if ($array instanceof IArrayWrapper) $array = $array->wrappedArray();
 | 
			
		||||
    if ($array === false) $array = [];
 | 
			
		||||
    elseif ($array instanceof Traversable) $array =  iterator_to_array($array);
 | 
			
		||||
    else $array = [$array];
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								src/IArrayWrapper.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/IArrayWrapper.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Interface IArrayWrapper: un objet qui encapsule un array auquel on peut
 | 
			
		||||
 * accéder
 | 
			
		||||
 */
 | 
			
		||||
interface IArrayWrapper {
 | 
			
		||||
  /** retourne une référence sur l'array encapsulé */
 | 
			
		||||
  function &wrappedArray(): ?array;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								src/cl.php
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								src/cl.php
									
									
									
									
									
								
							@ -5,7 +5,11 @@ use ArrayAccess;
 | 
			
		||||
use Traversable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class cl: gestion de tableau de valeurs scalaires
 | 
			
		||||
 * Class cl: gestion de tableaux ou d'instances de {@link ArrayAccess} le cas
 | 
			
		||||
 * échéant
 | 
			
		||||
 *
 | 
			
		||||
 * contrairement à {@link A}, les méthodes de cette classes sont plutôt conçues
 | 
			
		||||
 * pour retourner un nouveau tableau
 | 
			
		||||
 */
 | 
			
		||||
class cl {
 | 
			
		||||
  /** retourner un array non null à partir de $array */
 | 
			
		||||
@ -24,30 +28,6 @@ class cl {
 | 
			
		||||
    else return [$array];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * s'assurer que $array est un array non null. retourner true si $array n'a
 | 
			
		||||
   * pas été modifié (s'il était déjà un array), false sinon.
 | 
			
		||||
   */
 | 
			
		||||
  static final function ensure_array(&$array): bool {
 | 
			
		||||
    if (is_array($array)) return true;
 | 
			
		||||
    elseif ($array === null || $array === false) $array = [];
 | 
			
		||||
    elseif ($array instanceof Traversable) $array =  iterator_to_array($array);
 | 
			
		||||
    else $array = [$array];
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * s'assurer que $array est un array s'il est non null. retourner true si
 | 
			
		||||
   * $array n'a pas été modifié (s'il était déjà un array ou s'il valait null).
 | 
			
		||||
   */
 | 
			
		||||
  static final function ensure_narray(&$array): bool {
 | 
			
		||||
    if ($array === null || is_array($array)) return true;
 | 
			
		||||
    elseif ($array === false) $array = [];
 | 
			
		||||
    elseif ($array instanceof Traversable) $array =  iterator_to_array($array);
 | 
			
		||||
    else $array = [$array];
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** tester si $array a au moins une clé numérique */
 | 
			
		||||
  static final function have_num_keys(?array $array): bool {
 | 
			
		||||
    if ($array === null) return false;
 | 
			
		||||
@ -159,7 +139,7 @@ class cl {
 | 
			
		||||
  static final function merge(...$arrays): ?array {
 | 
			
		||||
    $merges = [];
 | 
			
		||||
    foreach ($arrays as $array) {
 | 
			
		||||
      self::ensure_narray($array);
 | 
			
		||||
      A::ensure_narray($array);
 | 
			
		||||
      if ($array !== null) $merges[] = $array;
 | 
			
		||||
    }
 | 
			
		||||
    return $merges? array_merge(...$merges): null;
 | 
			
		||||
@ -170,7 +150,7 @@ class cl {
 | 
			
		||||
  /**
 | 
			
		||||
   * vérifier que le chemin $keys existe dans le tableau $array
 | 
			
		||||
   *
 | 
			
		||||
   * si $keys est vide ou null, retourner true
 | 
			
		||||
   * si $pkey est vide ou null, retourner true
 | 
			
		||||
   */
 | 
			
		||||
  static final function phas($array, $pkey): bool {
 | 
			
		||||
    # optimisations
 | 
			
		||||
@ -214,7 +194,7 @@ class cl {
 | 
			
		||||
  /**
 | 
			
		||||
   * obtenir la valeur correspondant au chemin $keys dans $array
 | 
			
		||||
   *
 | 
			
		||||
   * si $keys est vide ou null, retourner $default
 | 
			
		||||
   * si $pkey est vide ou null, retourner $default
 | 
			
		||||
   */
 | 
			
		||||
  static final function pget($array, $pkey, $default=null) {
 | 
			
		||||
    # optimisations
 | 
			
		||||
@ -264,7 +244,7 @@ class cl {
 | 
			
		||||
   * - pset($array, ["a", "b", ""], $value) est équivalent à $array["a"]["b"][] = $value
 | 
			
		||||
   * la clé "" n'a pas de propriété particulière quand elle n'est pas en dernière position
 | 
			
		||||
   *
 | 
			
		||||
   * si $keys est vide ou null, $array est remplacé par $value
 | 
			
		||||
   * si $pkey est vide ou null, $array est remplacé par $value
 | 
			
		||||
   */
 | 
			
		||||
  static final function pset(&$array, $pkey, $value): void {
 | 
			
		||||
    # optimisations
 | 
			
		||||
@ -281,7 +261,7 @@ class cl {
 | 
			
		||||
      $pkey = explode(".", strval($pkey));
 | 
			
		||||
    }
 | 
			
		||||
    # pset
 | 
			
		||||
    self::ensure_array($array);
 | 
			
		||||
    A::ensure_array($array);
 | 
			
		||||
    $current =& $array;
 | 
			
		||||
    $key = null;
 | 
			
		||||
    $last = count($pkey) - 1;
 | 
			
		||||
@ -297,7 +277,7 @@ class cl {
 | 
			
		||||
          $current = [$current];
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        self::ensure_array($current[$key]);
 | 
			
		||||
        A::ensure_array($current[$key]);
 | 
			
		||||
        $current =& $current[$key];
 | 
			
		||||
      }
 | 
			
		||||
      $i++;
 | 
			
		||||
@ -318,7 +298,7 @@ class cl {
 | 
			
		||||
   * supprimer la valeur au chemin de clé $keys dans $array
 | 
			
		||||
   *
 | 
			
		||||
   * si $array vaut null ou false, sa valeur est inchangée.
 | 
			
		||||
   * si $keys est vide ou null, $array devient null
 | 
			
		||||
   * si $pkey est vide ou null, $array devient null
 | 
			
		||||
   */
 | 
			
		||||
  static final function pdel(&$array, $pkey): void {
 | 
			
		||||
    # optimisations
 | 
			
		||||
@ -334,7 +314,7 @@ class cl {
 | 
			
		||||
      $pkey = explode(".", strval($pkey));
 | 
			
		||||
    }
 | 
			
		||||
    # pdel
 | 
			
		||||
    self::ensure_array($array);
 | 
			
		||||
    A::ensure_array($array);
 | 
			
		||||
    $current =& $array;
 | 
			
		||||
    $key = null;
 | 
			
		||||
    $last = count($pkey) - 1;
 | 
			
		||||
 | 
			
		||||
@ -112,15 +112,18 @@ class Sqlite {
 | 
			
		||||
    return SqliteException::check($this->db, $result);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function _exec(string $query): bool {
 | 
			
		||||
  protected function db(): SQLite3 {
 | 
			
		||||
    $this->open();
 | 
			
		||||
    return $this->db->exec($query);
 | 
			
		||||
    return $this->db;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function _exec(string $query): bool {
 | 
			
		||||
    return $this->db()->exec($query);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function exec($query, ?array $params=null): bool {
 | 
			
		||||
    $this->open();
 | 
			
		||||
    $db = $this->db();
 | 
			
		||||
    $query = new _query($query, $params);
 | 
			
		||||
    $db = $this->db;
 | 
			
		||||
    if ($query->useStmt($db, $stmt, $sql)) {
 | 
			
		||||
      try {
 | 
			
		||||
        return $stmt->execute()->finalize();
 | 
			
		||||
@ -132,15 +135,25 @@ class Sqlite {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function beginTransaction(): void {
 | 
			
		||||
    $this->db()->exec("begin");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function commit(): void {
 | 
			
		||||
    $this->db()->exec("commit");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function rollback(): void {
 | 
			
		||||
    $this->db()->exec("commit");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function _get(string $query, bool $entireRow=false) {
 | 
			
		||||
    $this->open();
 | 
			
		||||
    return $this->db->querySingle($query, $entireRow);
 | 
			
		||||
    return $this->db()->querySingle($query, $entireRow);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function get($query, ?array $params=null, bool $entireRow=false) {
 | 
			
		||||
    $this->open();
 | 
			
		||||
    $db = $this->db();
 | 
			
		||||
    $query = new _query($query, $params);
 | 
			
		||||
    $db = $this->db;
 | 
			
		||||
    if ($query->useStmt($db, $stmt, $sql)) {
 | 
			
		||||
      try {
 | 
			
		||||
        $result = $this->checkResult($stmt->execute());
 | 
			
		||||
@ -164,27 +177,23 @@ class Sqlite {
 | 
			
		||||
    return $this->get($query, $params, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function _fetchResult(SQLite3Result $result): Generator {
 | 
			
		||||
  protected function _fetchResult(SQLite3Result $result, ?SQLite3Stmt $stmt=null): Generator {
 | 
			
		||||
    try {
 | 
			
		||||
      while (($row = $result->fetchArray(SQLITE3_ASSOC)) !== false) {
 | 
			
		||||
        yield $row;
 | 
			
		||||
      }
 | 
			
		||||
    } finally {
 | 
			
		||||
      $result->finalize();
 | 
			
		||||
      if ($stmt !== null) $stmt->close();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function all($query, ?array $params=null): iterable {
 | 
			
		||||
    $this->open();
 | 
			
		||||
    $db = $this->db();
 | 
			
		||||
    $query = new _query($query, $params);
 | 
			
		||||
    $db = $this->db;
 | 
			
		||||
    if ($query->useStmt($db, $stmt, $sql)) {
 | 
			
		||||
      try {
 | 
			
		||||
      $result = $this->checkResult($stmt->execute());
 | 
			
		||||
        return $this->_fetchResult($result);
 | 
			
		||||
      } finally {
 | 
			
		||||
        $stmt->close();
 | 
			
		||||
      }
 | 
			
		||||
      return $this->_fetchResult($result, $stmt);
 | 
			
		||||
    } else {
 | 
			
		||||
      $result = $this->checkResult($db->query($sql));
 | 
			
		||||
      return $this->_fetchResult($result);
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,10 @@ class SqliteCapacitor {
 | 
			
		||||
  /** @var Sqlite */
 | 
			
		||||
  protected $sqlite;
 | 
			
		||||
 | 
			
		||||
  function sqlite(): Sqlite {
 | 
			
		||||
    return $this->sqlite;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function getTableName(?string $channel): string {
 | 
			
		||||
    return ($channel ?? "default")."_channel";
 | 
			
		||||
  }
 | 
			
		||||
@ -30,7 +34,7 @@ class SqliteCapacitor {
 | 
			
		||||
  function reset(?string $channel=null) {
 | 
			
		||||
    $tableName = $this->getTableName($channel);
 | 
			
		||||
    $this->sqlite->exec("drop table if exists $tableName");
 | 
			
		||||
    #XXX maj de la tables channels
 | 
			
		||||
    #XXX maj de la tables channels dans une transaction
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @var array */
 | 
			
		||||
@ -68,7 +72,7 @@ class SqliteCapacitor {
 | 
			
		||||
    ]);
 | 
			
		||||
    #XXX^^^ migrer vers la syntaxe tableau de create
 | 
			
		||||
    $this->sqlite->exec($query);
 | 
			
		||||
    #XXX maj de la tables channels
 | 
			
		||||
    #XXX maj de la tables channels dans une transaction
 | 
			
		||||
    $this->created[$channel] = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -85,10 +89,13 @@ class SqliteCapacitor {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** décharger les données du canal spécifié */
 | 
			
		||||
  function discharge(?string $channel=null, bool $reset=true): iterable {
 | 
			
		||||
  function discharge($keys=null, ?string $channel=null, ?bool $reset=null): iterable {
 | 
			
		||||
    if ($keys !== null && !is_array($keys)) $keys = ["_id" => $keys];
 | 
			
		||||
    if ($reset === null) $reset = $keys === null;
 | 
			
		||||
    $rows = $this->sqlite->all([
 | 
			
		||||
      "select _item",
 | 
			
		||||
      "from" => $this->getTableName($channel),
 | 
			
		||||
      "where" => $keys,
 | 
			
		||||
    ]);
 | 
			
		||||
    foreach ($rows as $row) {
 | 
			
		||||
      $item = unserialize($row['_item']);
 | 
			
		||||
@ -97,22 +104,6 @@ class SqliteCapacitor {
 | 
			
		||||
    if ($reset) $this->reset($channel);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * appeler une fonction pour chaque élément du canal spécifié.
 | 
			
		||||
   *
 | 
			
		||||
   * $keys permet de filtrer parmi les élements chargés
 | 
			
		||||
   *
 | 
			
		||||
   * si $func retourne un tableau, il est utilisé pour mettre à jour
 | 
			
		||||
   * l'enregistrement.
 | 
			
		||||
   */
 | 
			
		||||
  function each(callable $func, ?array $keys, ?string $channel=null): void {
 | 
			
		||||
    $context = func::_prepare($func);
 | 
			
		||||
    foreach ($this->discharge($channel, false) as $item) {
 | 
			
		||||
      $result = func::_call($context, [$item]);
 | 
			
		||||
      #XXX
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * obtenir l'élément identifié par les clés spécifiées sur le canal spécifié
 | 
			
		||||
   *
 | 
			
		||||
@ -121,34 +112,56 @@ class SqliteCapacitor {
 | 
			
		||||
  function get($keys, ?string $channel=null) {
 | 
			
		||||
    if ($keys === null) throw ValueException::null("keys");
 | 
			
		||||
    if (!is_array($keys)) $keys = ["_id" => $keys];
 | 
			
		||||
    #XXX
 | 
			
		||||
    $row = $this->sqlite->one([
 | 
			
		||||
      "select _item",
 | 
			
		||||
      "from" => $this->getTableName($channel),
 | 
			
		||||
      "where" => $keys,
 | 
			
		||||
    ]);
 | 
			
		||||
    if ($row === null) return null;
 | 
			
		||||
    else return unserialize($row["_item"]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * appeler une fonction pour chaque élément du canal spécifié.
 | 
			
		||||
   *
 | 
			
		||||
   * $keys permet de filtrer parmi les élements chargés
 | 
			
		||||
   *
 | 
			
		||||
   * si $func retourne un tableau, il est utilisé pour mettre à jour
 | 
			
		||||
   * l'enregistrement.
 | 
			
		||||
   */
 | 
			
		||||
  function each($keys, callable $func, ?array $args=null, ?string $channel=null): void {
 | 
			
		||||
    if ($keys !== null && !is_array($keys)) $keys = ["_id" => $keys];
 | 
			
		||||
    $context = func::_prepare($func);
 | 
			
		||||
    $sqlite = $this->sqlite;
 | 
			
		||||
    $tableName = $this->getTableName($channel);
 | 
			
		||||
    $rows = $sqlite->all([
 | 
			
		||||
      "select",
 | 
			
		||||
      "from" => $tableName,
 | 
			
		||||
      "where" => $keys,
 | 
			
		||||
    ]);
 | 
			
		||||
    $args ??= [];
 | 
			
		||||
    foreach ($rows as $row) {
 | 
			
		||||
      $item = unserialize($row['_item']);
 | 
			
		||||
      $updates = func::_call($context, [$item, $row, ...$args]);
 | 
			
		||||
      if (is_array($updates)) {
 | 
			
		||||
        if (array_key_exists("_item", $updates)) {
 | 
			
		||||
          $updates["_item"] = serialize($updates["_item"]);
 | 
			
		||||
        }
 | 
			
		||||
        #XXXvvv migrer vers la syntaxe tableau de update
 | 
			
		||||
        $params = null;
 | 
			
		||||
        $sql = ["update", $tableName, "set"];
 | 
			
		||||
        _query::parse_set_values($updates, $setsql, $params);
 | 
			
		||||
        $sql[] = implode(", ", $setsql);
 | 
			
		||||
        $sql[] = "where";
 | 
			
		||||
        _query::parse_conds(["_id" => $row["_id"]], $wheresql, $params);
 | 
			
		||||
        $sql[] = implode(" and ", $wheresql);
 | 
			
		||||
        $sqlite->exec(implode(" ", $sql), $params);
 | 
			
		||||
        #XXX^^^ migrer vers la syntaxe tableau de update
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function close(): void {
 | 
			
		||||
    $this->sqlite->close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sqlite__exec(string $query): bool {
 | 
			
		||||
    return $this->sqlite->_exec($query);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sqlite_exec($query, ?array $params=null): bool {
 | 
			
		||||
    return $this->sqlite->exec($query, $params);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sqlite__get(string $query, bool $entireRow=false) {
 | 
			
		||||
    return $this->sqlite->_get($query, $entireRow);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sqlite_get($query, ?array $params=null, bool $entireRow=false) {
 | 
			
		||||
    return $this->sqlite->get($query, $params, $entireRow);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sqlite_one($query, ?array $params=null): ?array {
 | 
			
		||||
    return $this->sqlite->one($query, $params);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sqlite_all($query, ?array $params=null): iterable {
 | 
			
		||||
    return $this->sqlite->all($query, $params);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -91,6 +91,8 @@ class _query {
 | 
			
		||||
        }
 | 
			
		||||
        # value ou [operator, value]
 | 
			
		||||
        if (is_array($cond)) {
 | 
			
		||||
          #XXX implémenter le support de ["between", lower, upper]
 | 
			
		||||
          # et aussi ["in", values]
 | 
			
		||||
          $op = null;
 | 
			
		||||
          $value = null;
 | 
			
		||||
          $condkeys = array_keys($cond);
 | 
			
		||||
 | 
			
		||||
@ -5,12 +5,13 @@ use ArrayAccess;
 | 
			
		||||
use Countable;
 | 
			
		||||
use Iterator;
 | 
			
		||||
use nur\sery\cl;
 | 
			
		||||
use nur\sery\IArrayWrapper;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class BaseArray: implémentation de base d'un objet array-like, qui peut aussi
 | 
			
		||||
 * servir comme front-end pour un array
 | 
			
		||||
 */
 | 
			
		||||
class BaseArray implements ArrayAccess, Countable, Iterator {
 | 
			
		||||
class BaseArray implements ArrayAccess, Countable, Iterator, IArrayWrapper {
 | 
			
		||||
  function __construct(?array &$data=null) {
 | 
			
		||||
    $this->reset($data);
 | 
			
		||||
  }
 | 
			
		||||
@ -18,10 +19,11 @@ class BaseArray implements ArrayAccess, Countable, Iterator {
 | 
			
		||||
  /** @var array */
 | 
			
		||||
  protected $data;
 | 
			
		||||
 | 
			
		||||
  function &wrappedArray(): ?array { return $this->data; }
 | 
			
		||||
 | 
			
		||||
  function __toString(): string { return var_export($this->data, true); }
 | 
			
		||||
  #function __debugInfo() { return $this->data; }
 | 
			
		||||
  function reset(?array &$data): void { $this->data =& $data; }
 | 
			
		||||
  function &array(): ?array { return $this->data; }
 | 
			
		||||
  function count(): int { return $this->data !== null? count($this->data): 0; }
 | 
			
		||||
  function keys(): array { return $this->data !== null? array_keys($this->data): []; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@ class SqliteCapacitorTest extends TestCase {
 | 
			
		||||
    $capacitor->charge("first", $channel);
 | 
			
		||||
    $capacitor->charge("second", $channel);
 | 
			
		||||
    $capacitor->charge("third", $channel);
 | 
			
		||||
    $items = iterator_to_array($capacitor->discharge($channel, false));
 | 
			
		||||
    $items = iterator_to_array($capacitor->discharge(null, $channel, false));
 | 
			
		||||
    self::assertSame(["first", "second", "third"], $items);
 | 
			
		||||
  }
 | 
			
		||||
  function _testChargeArrays(SqliteCapacitor $capacitor, ?string $channel) {
 | 
			
		||||
@ -45,4 +45,42 @@ class SqliteCapacitorTest extends TestCase {
 | 
			
		||||
    $this->_testChargeArrays($capacitor, "arrays");
 | 
			
		||||
    $capacitor->close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testEach() {
 | 
			
		||||
    $capacitor = new class(__DIR__.'/capacitor.db') extends SqliteCapacitor {
 | 
			
		||||
      protected function getKeyDefinitions(?string $channel): ?array {
 | 
			
		||||
        return [
 | 
			
		||||
          "age" => "integer",
 | 
			
		||||
          "done" => "integer default 0",
 | 
			
		||||
        ];
 | 
			
		||||
      }
 | 
			
		||||
      protected function getKeyValues($item, ?string $channel): ?array {
 | 
			
		||||
        return [
 | 
			
		||||
          "age" => $item["age"],
 | 
			
		||||
        ];
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $channel = "each";
 | 
			
		||||
    $capacitor->reset($channel);
 | 
			
		||||
    $capacitor->charge(["name" => "first", "age" => 5], $channel);
 | 
			
		||||
    $capacitor->charge(["name" => "second", "age" => 10], $channel);
 | 
			
		||||
    $capacitor->charge(["name" => "third", "age" => 15], $channel);
 | 
			
		||||
    $capacitor->charge(["name" => "fourth", "age" => 20], $channel);
 | 
			
		||||
 | 
			
		||||
    $setDone = function ($item, $row, $suffix=null) {
 | 
			
		||||
      $updates = ["done" => 1];
 | 
			
		||||
      if ($suffix !== null) {
 | 
			
		||||
        $item["name"] .= $suffix;
 | 
			
		||||
        $updates["_item"] = $item;
 | 
			
		||||
      }
 | 
			
		||||
      return $updates;
 | 
			
		||||
    };
 | 
			
		||||
    $capacitor->each(["age" => [">", 10]], $setDone, ["++"], $channel);
 | 
			
		||||
    $capacitor->each(["done" => 0], $setDone, null, $channel);
 | 
			
		||||
    Txx(iterator_to_array($capacitor->discharge(null, $channel, false)));
 | 
			
		||||
 | 
			
		||||
    $capacitor->close();
 | 
			
		||||
    self::assertTrue(true);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user