nur-sery/nur_src/mapper/base/capacitor/Capacitor.php

146 lines
4.2 KiB
PHP

<?php
namespace nur\mapper\base\capacitor;
use ArrayAccess;
use nur\A;
use nur\data\types\Metadata;
/**
* Class Capacitor: classe outil qui permet d'accumuler des données pour les
* fournir en une seule fois au moment voulu
*/
class Capacitor implements ICapacitor, ArrayAccess {
use TCapacitor;
/** @var Metadata */
private static $key_md;
private static function key_md(): Metadata {
if (self::$key_md === null) {
self::$key_md = new Metadata(self::KEY_SCHEMA);
}
return self::$key_md;
}
/** @var Metadata */
private static $sort_md;
private static function sort_md(): Metadata {
if (self::$sort_md === null) {
self::$sort_md = new Metadata(self::SORT_SCHEMA);
}
return self::$sort_md;
}
/** @var array */
protected $kinfos;
/**
* spécifier les clés à traquer lors du chargement d'une donnée.
*
* si une clé est marquée comme primaire, alors les doublons éventuels sont
* supprimés au fur et à mesure du chargement.
*/
function setKeys(array $keys, ?string $channel=null): void {
self::key_md()->eachEnsureSchema($keys);
$namedkeys = [];
$pkeys = null;
foreach ($keys as $key) {
$namedkeys[$key["name"]] = $key;
if ($key["primary"]) $pkeys[] = $key;
}
$this->kinfos[$channel] = ["keys" => $namedkeys, "pkeys" => $pkeys];
}
private static function get_kvalues(array $keys, $item): array {
$item = A::with($item);
$kvalues = [];
foreach ($keys as $kname => $key) {
$kvalues[$kname] = A::get($item, $key["name"]);
}
return $kvalues;
}
private static function compute_itemkey(array $pkvalues): string {
return implode("-", $pkvalues);
}
private static function get_itemkey(?array $kinfos, $item): ?string {
if ($kinfos === null) return null;
$pkeys = $kinfos["pkeys"];
if ($pkeys === null) return null;
$pkvalues = self::get_kvalues($pkeys, $item);
return self::compute_itemkey($pkvalues);
}
/** @var array */
protected $data;
/**
* trier les données selon les clés spécifiées. NB: cette implémentation
* autorise qu'on utilise des clés qui n'ont pas été déclarées avec
* {@link setKeys()}
*
* @see ICapacitor::sort()
*/
function sort(?array $keys=null, ?string $channel=null): void {
$kinfos = A::get($this->kinfos, $channel);
$asort = $kinfos !== null && $kinfos["pkeys"] !== null;
$defaultKeys = $kinfos !== null? $kinfos["keys"]: null;
if ($keys !== null) {
self::sort_md()->eachEnsureSchema($keys);
} else {
$keys = $defaultKeys;
if ($keys === null) return;
}
foreach ($keys as $kname => &$key) {
if ($key["reverse"] === null && $defaultKeys !== null && array_key_exists($kname, $defaultKeys)) {
$key["reverse"] = $defaultKeys[$kname]["reverse"];
}
if ($key["reverse"] === null) $key["reverse"] = false;
}; unset($key);
$sortfunc = function ($a, $b) use ($keys) {
$akvs = self::get_kvalues($keys, $a);
$bkvs = self::get_kvalues($keys, $b);
foreach ($keys as $kname => $key) {
$akv = $akvs[$kname];
$bkv = $bkvs[$kname];
if ($akv == $bkv) continue;
if ($akv < $bkv) {
return $key["reverse"] ? 1 : -1;
} else {
return $key["reverse"] ? -1 : 1;
}
}
return 0;
};
if ($asort) uasort($this->data[$channel], $sortfunc);
else usort($this->data[$channel], $sortfunc);
}
function charge($item, ?string $channel=null, $pkvalues=null): void {
$kinfos = A::get($this->kinfos, $channel);
$itemkey = self::get_itemkey($kinfos, $item);
if ($itemkey === null && $item === null) {
if ($pkvalues === null) return;
$itemkey = self::compute_itemkey($pkvalues);
}
A::set($this->data[$channel], $itemkey, $item);
}
function getItem($pkvalues, ?string $channel=null, $default=null) {
if (is_array($pkvalues)) {
$itemkey = self::compute_itemkey($pkvalues);
} else {
$itemkey = $pkvalues;
}
return A::_pget($this->data, [$channel, $itemkey], $default);
}
function discharge(?string $channel=null, bool $remove=true): iterable {
$items = A::get($this->data, $channel, []);
if ($remove) A::del($this->data, $channel);
return $items;
}
}