146 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			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;
 | 
						|
  }
 | 
						|
}
 |