_create($channel); $this->channels[$channel->getName()] = $channel; return $channel; } protected function getChannel(?string $name): CapacitorChannel { $name = CapacitorChannel::verifix_name($name); $channel = $this->channels[$name] ?? null; if ($channel === null) { $channel = $this->addChannel(new CapacitorChannel($name)); } return $channel; } /** DOIT être défini dans les classes dérivées */ const PRIMARY_KEY_DEFINITION = null; const COLUMN_DEFINITIONS = [ "item__" => "text", "sum_" => "varchar(40)", "created_" => "datetime", "modified_" => "datetime", ]; protected function ColumnDefinitions(CapacitorChannel $channel): array { $definitions = []; if ($channel->getPrimaryKeys() === null) { $definitions[] = static::PRIMARY_KEY_DEFINITION; } $definitions[] = static::COLUMN_DEFINITIONS; $definitions[] = $channel->getColumnDefinitions(); return cl::merge(...$definitions); } /** sérialiser les valeurs qui doivent l'être dans $values */ protected function serialize(CapacitorChannel $channel, ?array $values): ?array { if ($values === null) return null; $cols = $this->ColumnDefinitions($channel); $index = 0; $row = []; foreach (array_keys($cols) as $col) { $key = $col; if ($key === $index) { $index++; continue; } elseif (str::del_suffix($key, "__")) { if (!array_key_exists($key, $values)) continue; $value = $values[$key]; if ($value !== null) $value = serialize($value); } else { if (!array_key_exists($key, $values)) continue; $value = $values[$key]; } $row[$col] = $value; } return $row; } /** désérialiser les valeurs qui doivent l'être dans $values */ protected function unserialize(CapacitorChannel $channel, ?array $row): ?array { if ($row === null) return null; $cols = $this->ColumnDefinitions($channel); $index = 0; $values = []; foreach (array_keys($cols) as $col) { $key = $col; if ($key === $index) { $index++; continue; } elseif (!array_key_exists($col, $row)) { continue; } elseif (str::del_suffix($key, "__")) { $value = $row[$col]; if ($value !== null) $value = unserialize($value); } else { $value = $row[$col]; } $values[$key] = $value; } return $values; } protected function getPrimaryKeys(CapacitorChannel $channel): array { $primaryKeys = $channel->getPrimaryKeys(); if ($primaryKeys === null) $primaryKeys = ["id_"]; return $primaryKeys; } protected function getRowIds(CapacitorChannel $channel, ?array $row, ?array &$primaryKeys=null): ?array { $primaryKeys = $this->getPrimaryKeys($channel); $rowIds = cl::select($row, $primaryKeys); if (cl::all_n($rowIds)) return null; else return $rowIds; } abstract function _exists(CapacitorChannel $channel): bool; /** tester si le canal spécifié existe */ function exists(?string $channel): bool { return $this->_exists($this->getChannel($channel)); } abstract function _ensureExists(CapacitorChannel $channel): void; /** s'assurer que le canal spécifié existe */ function ensureExists(?string $channel): void { $this->_ensureExists($this->getChannel($channel)); } abstract function _reset(CapacitorChannel $channel): void; /** supprimer le canal spécifié */ function reset(?string $channel): void { $this->_reset($this->getChannel($channel)); } abstract function _charge(CapacitorChannel $channel, $item, $func, ?array $args): int; /** * charger une valeur dans le canal * * Si $func!==null, après avoir calculé les valeurs des clés supplémentaires * avec {@link CapacitorChannel::getItemValues()}, la fonction est appelée avec * la signature ($item, $keyValues, $row, ...$args) * Si la fonction retourne un tableau, il est utilisé pour modifier les valeurs * insérées/mises à jour * * @return int 1 si l'objet a été chargé ou mis à jour, 0 s'il existait * déjà à l'identique dans le canal */ function charge(?string $channel, $item, $func=null, ?array $args=null): int { return $this->_charge($this->getChannel($channel), $item, $func, $args); } abstract function _discharge(CapacitorChannel $channel, bool $reset=true): iterable; /** décharger les données du canal spécifié */ function discharge(?string $channel, bool $reset=true): iterable { return $this->_discharge($this->getChannel($channel), $reset); } abstract function _count(CapacitorChannel $channel, $filter): int; /** indiquer le nombre d'éléments du canal spécifié */ function count(?string $channel, $filter=null): int { return $this->_count($this->getChannel($channel), $filter); } abstract function _one(CapacitorChannel $channel, $filter): ?array; /** * obtenir la ligne correspondant au filtre sur le canal spécifié * * si $filter n'est pas un tableau, il est transformé en ["id_" => $filter] */ function one(?string $channel, $filter): ?array { return $this->_one($this->getChannel($channel), $filter); } abstract function _all(CapacitorChannel $channel, $filter): iterable; /** * obtenir les lignes correspondant au filtre sur le canal spécifié * * si $filter n'est pas un tableau, il est transformé en ["id_" => $filter] */ function all(?string $channel, $filter): iterable { return $this->_all($this->getChannel($channel), $filter); } abstract function _each(CapacitorChannel $channel, $filter, $func, ?array $args): int; /** * appeler une fonction pour chaque élément du canal spécifié. * * $filter permet de filtrer parmi les élements chargés * * $func est appelé avec la signature ($item, $row, ...$args). si la fonction * retourne un tableau, il est utilisé pour mettre à jour la ligne * * @return int le nombre de lignes parcourues */ function each(?string $channel, $filter, $func=null, ?array $args=null): int { return $this->_each($this->getChannel($channel), $filter, $func, $args); } abstract function close(): void; }