223 lines
6.8 KiB
PHP
223 lines
6.8 KiB
PHP
|
<?php
|
||
|
namespace nur\mapper\base;
|
||
|
|
||
|
use ArrayAccess;
|
||
|
use Countable;
|
||
|
use nur\b\coll\IArray;
|
||
|
use nur\b\coll\TBaseArray;
|
||
|
use nur\b\coll\TGenericArray;
|
||
|
use nur\b\ICloseable;
|
||
|
use nur\b\params\Parametrable;
|
||
|
use nur\b\params\Tparametrable;
|
||
|
use nur\b\ValueException;
|
||
|
use nur\func;
|
||
|
use nur\mapper\base\oobd\IOobdManager;
|
||
|
use nur\mapper\base\oobd\TOobdManager;
|
||
|
|
||
|
/**
|
||
|
* Class Consumer: une classe qui applique des mappers sur les données d'un
|
||
|
* producer.
|
||
|
*/
|
||
|
class Consumer extends Parametrable implements ArrayAccess, Countable, IArray, ICloseable, IOobdManager {
|
||
|
use TBaseArray, TGenericArray, Tparametrable, TOobdManager;
|
||
|
|
||
|
function __construct($producer=null, ...$mappers) {
|
||
|
parent::__construct();
|
||
|
$this->data = [];
|
||
|
if ($producer !== null) $this->setProducer($producer);
|
||
|
$this->addAll($mappers);
|
||
|
}
|
||
|
|
||
|
function _haveMethod(string $method): bool {
|
||
|
return method_exists($this, $method);
|
||
|
}
|
||
|
|
||
|
/** @var iterable */
|
||
|
private $producer;
|
||
|
|
||
|
/** @var PushProducer */
|
||
|
private $pushProducer;
|
||
|
|
||
|
function setProducer($producer, ...$args): self {
|
||
|
$producer = producer_utils::ensure_producer($producer, $args);
|
||
|
$this->producer = $producer;
|
||
|
$this->pushProducer = $producer instanceof PushProducer? $producer: null;
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
function set($key, $mapper): self { return $this->_set($key, mapper_utils::ensure_mapper_class($mapper)); }
|
||
|
function add($mapper): self { return $this->_set(null, mapper_utils::ensure_mapper_class($mapper)); }
|
||
|
|
||
|
/** @var bool */
|
||
|
private $setup = false;
|
||
|
|
||
|
private function ensureSetup(): bool {
|
||
|
if (!$this->setup) {
|
||
|
$this->setup();
|
||
|
$this->setup = true;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
protected function setup(): void {
|
||
|
}
|
||
|
|
||
|
/** @var iterable */
|
||
|
private $pushIterator;
|
||
|
|
||
|
private function _ensureSharedOobdManager(iterable $iterator): void {
|
||
|
if ($iterator instanceof IOobdManager) {
|
||
|
# récupérer le gestionnaire partagé le cas échéant
|
||
|
$sharedOobdManager = $iterator->getSharedOobdManager();
|
||
|
if ($sharedOobdManager !== null) $this->setSharedOobdManager($sharedOobdManager);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private function buildIterator(bool $ensurePushable=false): array {
|
||
|
$this->ensureSetup();
|
||
|
if ($this->pushIterator === null) {
|
||
|
if (!$ensurePushable) {
|
||
|
$iterator = $this->producer;
|
||
|
if ($iterator === null) {
|
||
|
throw new ValueException("a producer is required");
|
||
|
}
|
||
|
if ($this->pushProducer === null) {
|
||
|
if ($iterator instanceof IOobdManager) {
|
||
|
# s'assurer qu'il y a toujours un gestionnaire partagé
|
||
|
$iterator->ensureSharedOobdManager();
|
||
|
}
|
||
|
$iterator = mapper_utils::assemble_mappers($this->data, $iterator);
|
||
|
$this->_ensureSharedOobdManager($iterator);
|
||
|
return [true, $iterator];
|
||
|
}
|
||
|
}
|
||
|
$iterator = $this->pushProducer;
|
||
|
if ($iterator === null) $iterator = new PushProducer();
|
||
|
# s'assurer qu'il y a toujours un gestionnaire partagé
|
||
|
$iterator->ensureSharedOobdManager();
|
||
|
$this->pushProducer = $iterator;
|
||
|
$this->pushIterator = mapper_utils::assemble_mappers($this->data, $iterator);
|
||
|
$this->_ensureSharedOobdManager($this->pushIterator);
|
||
|
}
|
||
|
return [false, $this->pushIterator];
|
||
|
}
|
||
|
|
||
|
private $iterator;
|
||
|
|
||
|
function hasOvalue(string $name): bool {
|
||
|
if ($this->_hasOobdValue($name)) {
|
||
|
return true;
|
||
|
} elseif ($this->sharedOobdManager !== null
|
||
|
&& $this->sharedOobdManager->hasOvalue($name)) {
|
||
|
return true;
|
||
|
} elseif ($this->iterator instanceof IOobdManager) {
|
||
|
return $this->iterator->hasOvalue($name);
|
||
|
} elseif ($this->pushIterator instanceof IOobdManager) {
|
||
|
return $this->pushIterator->hasOvalue($name);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* c'est la méthode {@link consume()} qui construit $this->iterator. l'accès
|
||
|
* aux données OOB de la chaine de mapper n'est donc valide que dans les
|
||
|
* méthodes {@link _consume()} et {@link cook()}
|
||
|
*
|
||
|
* De même, en mode push, ce n'est qu'après l'appel d'une des méthodes
|
||
|
* {@link ensurePushable()}, {@link push()} ou {@link pushAll()} que les
|
||
|
* données OOB de la chaine de mapper sont disponibles
|
||
|
*/
|
||
|
function getOvalue(string $name, $default=null) {
|
||
|
if ($this->_hasOobdValue($name)) {
|
||
|
return $this->_getOobdValue($name, $default);
|
||
|
} elseif ($this->sharedOobdManager !== null
|
||
|
&& $this->sharedOobdManager->hasOvalue($name)) {
|
||
|
return $this->sharedOobdManager->getOvalue($name, $default);
|
||
|
} elseif ($this->iterator instanceof IOobdManager) {
|
||
|
return $this->iterator->getOvalue($name, $default);
|
||
|
} elseif ($this->pushIterator instanceof IOobdManager) {
|
||
|
return $this->pushIterator->getOvalue($name, $default);
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
function cook($item) {
|
||
|
}
|
||
|
|
||
|
protected function _consume(iterable $items): void {
|
||
|
$cookFunc = func::_prepare([$this, "cook"]);
|
||
|
foreach ($items as $key => $item) {
|
||
|
func::_call($cookFunc, [$item, $key]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* consommer toutes les valeurs du producer
|
||
|
*
|
||
|
* les méthodes {@link setup()} et {@link teardown()} sont appelées
|
||
|
* automatiquement
|
||
|
*/
|
||
|
function consume($producer=null, ...$mappers): void {
|
||
|
if ($producer !== null) $this->setProducer($producer);
|
||
|
if ($mappers) $this->resetAll($mappers);
|
||
|
|
||
|
$close = $this->ensureSetup();
|
||
|
try {
|
||
|
[$close, $iterator] = $this->buildIterator();
|
||
|
$this->iterator = $iterator;
|
||
|
$this->_consume($iterator);
|
||
|
} finally {
|
||
|
if ($close) $this->close();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected function teardown(): void {
|
||
|
if ($this->iterator instanceof ICloseable) $this->iterator->close();
|
||
|
$this->iterator = null;
|
||
|
if ($this->pushIterator !== null) {
|
||
|
if ($this->pushIterator instanceof ICloseable) $this->pushIterator->close();
|
||
|
$this->pushProducer = null;
|
||
|
$this->pushIterator = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** appeler la méthode {@link teardown()} si nécessaire */
|
||
|
function close(): void {
|
||
|
if ($this->setup) {
|
||
|
$this->teardown();
|
||
|
$this->setup = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* s'assurer que les données OOB sont disponibles avant l'utilisation de
|
||
|
* {@link push()} ou {@link pushAll()}. cette méthode n'a pas d'autre utilité
|
||
|
*/
|
||
|
function ensurePushable(): void {
|
||
|
$this->buildIterator(true);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* insérer une valeur, comme si elle provenait du producer.
|
||
|
*
|
||
|
* la méthodes {@link setup()} est appelée automatiquement si nécessaire, mais
|
||
|
* pas {@link teardown()}. il faut donc penser à appeler {@link close()} quand
|
||
|
* on a terminé
|
||
|
*/
|
||
|
function push($item, $key=null): void {
|
||
|
$this->buildIterator(true);
|
||
|
$this->pushProducer->push($item, $key);
|
||
|
$this->_consume($this->pushIterator);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* insérer des valeurs, comme si elles provenaient du producer
|
||
|
*/
|
||
|
function pushAll(iterable $items): void {
|
||
|
$this->buildIterator(true);
|
||
|
$this->pushProducer->pushAll($items);
|
||
|
$this->_consume($this->pushIterator);
|
||
|
}
|
||
|
}
|