name = self::verifix_name($name ?? static::NAME); $this->tableName = static::TABLE_NAME ?? ($this->name."_channel"); $this->manageTransactions = $manageTransactions ?? static::MANAGE_TRANSACTIONS; $this->eachCommitThreshold = self::verifix_eachCommitThreshold($eachCommitThreshold); $this->setup = false; $this->created = false; $columnDefinitions = cl::withn(static::COLUMN_DEFINITIONS); $primaryKeys = cl::withn(static::PRIMARY_KEYS); if ($primaryKeys === null && $columnDefinitions !== null) { $index = 0; foreach ($columnDefinitions as $col => $def) { if ($col === $index) { $index++; if (preg_match('/\bprimary\s+key\s+\((.+)\)/i', $def, $ms)) { $primaryKeys = preg_split('/\s*,\s*/', trim($ms[1])); } } else { if (preg_match('/\bprimary\s+key\b/i', $def)) { $primaryKeys[] = $col; } } } } $this->columnDefinitions = $columnDefinitions; $this->primaryKeys = $primaryKeys; } protected string $name; function getName(): string { return $this->name; } protected string $tableName; function getTableName(): string { return $this->tableName; } /** * @var bool indiquer si les modifications de each doivent être gérées dans * une transaction. si false, l'utilisateur doit lui même gérer la * transaction. */ protected bool $manageTransactions; function isManageTransactions(): bool { return $this->manageTransactions; } function setManageTransactions(bool $manageTransactions=true): self { $this->manageTransactions = $manageTransactions; return $this; } /** * @var ?int nombre maximum de modifications dans une transaction avant un * commit automatique dans {@link Capacitor::each()}. Utiliser null pour * désactiver la fonctionnalité. * * ce paramètre n'a d'effet que si $manageTransactions==true */ protected ?int $eachCommitThreshold; function getEachCommitThreshold(): ?int { return $this->eachCommitThreshold; } function setEachCommitThreshold(?int $eachCommitThreshold=null): self { $this->eachCommitThreshold = self::verifix_eachCommitThreshold($eachCommitThreshold); return $this; } /** * initialiser ce channel avant sa première utilisation. */ protected function setup(): void { } protected bool $setup; function ensureSetup() { if (!$this->setup) { $this->setup(); $this->setup = true; } } protected bool $created; function isCreated(): bool { return $this->created; } function setCreated(bool $created=true): void { $this->created = $created; } protected ?array $columnDefinitions; /** * retourner un ensemble de définitions pour des colonnes supplémentaires à * insérer lors du chargement d'une valeur * * la clé primaire "id_" a pour définition "integer primary key autoincrement". * elle peut être redéfinie, et dans ce cas la valeur à utiliser doit être * retournée par {@link getItemValues()} * * la colonne "item__" contient la valeur sérialisée de l'élément chargé. bien * que ce soit possible techniquement, cette colonne n'a pas à être redéfinie * * les colonnes dont le nom se termine par "_" sont réservées. * les colonnes dont le nom se termine par "__" sont automatiquement sérialisées * lors de l'insertion dans la base de données, et automatiquement désérialisées * avant d'être retournées à l'utilisateur (sans le suffixe "__") */ function getColumnDefinitions(): ?array { return $this->columnDefinitions; } protected ?array $primaryKeys; function getPrimaryKeys(): ?array { return $this->primaryKeys; } /** * calculer les valeurs des colonnes supplémentaires à insérer pour le * chargement de $item * * Cette méthode est utilisée par {@link Capacitor::charge()}. Si la clé * primaire est incluse (il s'agit généralement de "id_"), la ligne * correspondate est mise à jour si elle existe. * * Retourner la clé primaire par cette méthode est l'unique moyen de * déclencher une mise à jour plutôt qu'une nouvelle création. */ function getItemValues($item): ?array { return null; } /** * Avant d'utiliser un id pour rechercher dans la base de donnée, corriger sa * valeur le cas échéant. * * Cette fonction assume que l'unique clé primaire est "id_". Elle n'est pas * utilisée si une clé primaire multiple est définie. */ function verifixId(string &$id): void { } /** * retourne true si un nouvel élément ou un élément mis à jour a été chargé. * false si l'élément chargé est identique au précédent. * * cette méthode doit être utilisée dans {@link self::onUpdate()} */ function wasRowModified(array $rowValues): bool { return array_key_exists("modified_", $rowValues); } final function serialize($item): ?string { return $item !== null? serialize($item): null; } final function unserialize(?string $serial) { return $serial !== null? unserialize($serial): null; } const SERIAL_DEFINITION = "mediumtext"; const SUM_DEFINITION = "varchar(40)"; final function sum(?string $serial, $value=null): ?string { if ($serial === null) $serial = $this->serialize($value); return $serial !== null? sha1($serial): null; } final function isSerialCol(string &$key): bool { return str::del_suffix($key, "__"); } final function getSumCols(string $key): array { return ["${key}__", "${key}__sum_"]; } function getSum(string $key, $value): array { $sumCols = $this->getSumCols($key); $serial = $this->serialize($value); $sum = $this->sum($serial, $value); return array_combine($sumCols, [$serial, $sum]); } function wasSumModified(string $key, $value, array $prowValues): bool { $sumCol = $this->getSumCols($key)[1]; $sum = $this->sum(null, $value); $psum = $prowValues[$sumCol] ?? $this->sum(null, $prowValues[$key] ?? null); return $sum !== $psum; } function _wasSumModified(string $key, array $row, array $prow): bool { $sumCol = $this->getSumCols($key)[1]; $sum = $row[$sumCol] ?? null; $psum = $prow[$sumCol] ?? null; return $sum !== $psum; } /** * méthode appelée lors du chargement avec {@link Capacitor::charge()} pour * créer un nouvel élément * * @param mixed $item l'élément à charger * @param array $rowValues la ligne à créer, calculée à partir de $item et des * valeurs retournées par {@link getItemValues()} * @return ?array le cas échéant, un tableau non null à merger dans $rowValues * et utilisé pour provisionner la ligne nouvellement créée * * Si $item est modifié dans cette méthode, il est possible de le retourner * avec la clé "item" pour mettre à jour la ligne correspondante. * * la création ou la mise à jour est uniquement décidée en fonction des * valeurs calculées par {@link self::getItemValues()}. Bien que cette méthode * peut techniquement retourner de nouvelles valeurs pour la clé primaire, ça * risque de créer des doublons */ function onCreate($item, array $rowValues, ?array $alwaysNull): ?array { return null; } /** * méthode appelée lors du chargement avec {@link Capacitor::charge()} pour * mettre à jour un élément existant * * @param mixed $item l'élément à charger * @param array $rowValues la nouvelle ligne, calculée à partir de $item et * des valeurs retournées par {@link getItemValues()} * @param array $prowValues la précédente ligne, chargée depuis la base de * données * @return ?array null s'il ne faut pas mettre à jour la ligne. sinon, ce * tableau est mergé dans $values puis utilisé pour mettre à jour la ligne * existante * * - Il est possible de mettre à jour $item en le retourant avec la clé "item" * - La clé primaire (il s'agit généralement de "id_") ne peut pas être * modifiée. si elle est retournée, elle est ignorée */ function onUpdate($item, array $rowValues, array $prowValues): ?array { return null; } /** * méthode appelée lors du parcours des éléments avec * {@link Capacitor::each()} * * @param mixed $item l'élément courant * @param ?array $rowValues la ligne courante * @return ?array le cas échéant, un tableau non null utilisé pour mettre à * jour la ligne courante * * - Il est possible de mettre à jour $item en le retourant avec la clé "item" * - La clé primaire (il s'agit généralement de "id_") ne peut pas être * modifiée. si elle est retournée, elle est ignorée */ function onEach($item, array $rowValues): ?array { return null; } /** * méthode appelée lors du parcours des éléments avec * {@link Capacitor::delete()} * * @param mixed $item l'élément courant * @param ?array $rowValues la ligne courante * @return bool true s'il faut supprimer la ligne, false sinon */ function onDelete($item, array $rowValues): bool { return true; } }