null}. cela permet d'implémenter des * méthodes de mapping plus complexes. */ protected function MAP_SOF(): bool { return static::MAP_SOF; } const MAP_SOF = false; /** * @return bool indiquer s'il faut appeler {@link mapper()} une dernière fois * à la fin de l'itération avec {null => null}. cela permet d'implémenter des * méthodes de mapping plus complexes. */ protected function MAP_EOF(): bool { return static::MAP_EOF; } const MAP_EOF = false; /** * @param iterable|null $source dans les classes dérivées, cet argument doit * par convention être le dernier de la liste */ function __construct(?iterable $source=null) { $params = null; if ($source !== null) $params["source"] = $source; parent::__construct($params); } /** * @var array liste de paramètres pour la configuration générique de cet objet */ const PARAMETRABLE_PARAMS_SCHEMA = [ "source" => ["iterable", null, "source de données"], ]; /** @var iterable */ protected $ppSource; function hasOvalue(string $name): bool { if ($this->_hasOobdValue($name)) { return true; } elseif ($this->sharedOobdManager !== null && $this->sharedOobdManager->hasOvalue($name)) { return true; } elseif ($this->ppSource instanceof IOobdManager) { return $this->ppSource->hasOvalue($name); } return false; } 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->ppSource instanceof IOobdManager) { return $this->ppSource->getOvalue($name, $default); } return null; } /** @var bool */ private $setup = false; function ensureSetup(): void { if (!$this->setup) { $this->setup(); $this->setup = true; } } /** * initialiser l'itérateur. cette méthode est appelée avant de lancer * l'itération */ protected function setup(): void { } function getIterator(): iterable { $this->ensureSetup(); $this->sof = false; $this->eof = false; try { $mapFunc = func::_prepare([$this, "mapper"]); $outIndex = 0; $srcIndex = 0; if ($this->MAP_SOF()) { $this->sof = true; while (true) { $this->action = self::USE_MAPPED_VALUE_ACTION; $this->mappedIterables = null; $mappedValue = func::_call($mapFunc, [null, null]); if ($this->action !== self::RETRY_ACTION) break; } switch ($this->action) { case self::USE_MAPPED_VALUE_ACTION: if ($mappedValue !== null) { yield $outIndex => $mappedValue; $outIndex++; } break; case self::USE_MAPPED_ITERABLES_ACTION: foreach ($this->mappedIterables as $mappedIterable) { $seqIndex = 0; foreach ($mappedIterable as $mappedKey => $mappedValue) { if ($mappedKey === $seqIndex) { # seq yield $outIndex => $mappedValue; $outIndex++; $seqIndex++; } else { # assoc yield $mappedKey => $mappedValue; } } } break; } $this->sof = false; } if ($this->ppSource !== null) { foreach ($this->ppSource as $key => $value) { while (true) { $this->mappedIterables = null; $this->action = self::USE_MAPPED_VALUE_ACTION; $mappedValue = func::_call($mapFunc, [$value, $key]); if ($this->action !== self::RETRY_ACTION) break; } switch ($this->action) { case self::USE_MAPPED_VALUE_ACTION: if ($mappedValue !== null) { if ($key === $srcIndex) { yield $outIndex => $mappedValue; $outIndex++; } else { yield $key => $mappedValue; } } break; case self::USE_MAPPED_ITERABLES_ACTION: foreach ($this->mappedIterables as $mappedIterable) { $seqIndex = 0; foreach ($mappedIterable as $mappedKey => $mappedValue) { if ($mappedKey === $seqIndex) { # seq yield $outIndex => $mappedValue; $outIndex++; $seqIndex++; } else { # assoc yield $mappedKey => $mappedValue; } } } break; } if ($key === $srcIndex) $srcIndex++; } } if ($this->MAP_EOF()) { $this->eof = true; while (true) { $this->action = self::USE_MAPPED_VALUE_ACTION; $this->mappedIterables = null; $mappedValue = func::_call($mapFunc, [null, null]); if ($this->action !== self::RETRY_ACTION) break; } switch ($this->action) { case self::USE_MAPPED_VALUE_ACTION: if ($mappedValue !== null) { yield $outIndex => $mappedValue; } break; case self::USE_MAPPED_ITERABLES_ACTION: foreach ($this->mappedIterables as $mappedIterable) { $seqIndex = 0; foreach ($mappedIterable as $mappedKey => $mappedValue) { if ($mappedKey === $seqIndex) { # seq yield $outIndex => $mappedValue; $outIndex++; $seqIndex++; } else { # assoc yield $mappedKey => $mappedValue; } } } break; } } } finally { $this->close(); } } /** terminer l'itération. cette méthode est appelée à la fin de l'itération */ protected function teardown(): void { if ($this->ppSource instanceof ICloseable) $this->ppSource->close(); } function close(): void { if ($this->setup) { $this->teardown(); $this->setup = false; } } /** * @var bool indique que l'on est au début de l'itération si et seulement si * {@link MAP_SOF()} retourne true */ protected $sof; /** * @var bool indique que l'on est à la fin de l'itération si et seulement si * {@link MAP_EOF()} retourne true */ protected $eof; const USE_MAPPED_VALUE_ACTION = 0; const USE_MAPPED_ITERABLES_ACTION = 1; const RETRY_ACTION = 2; /** @var bool action à effectuer au retour de la fonction {@link mapper()} */ private $action; /** @var array valeurs générées par les méthodes {@link mapTo()} */ private $mappedIterables; /** * indiquer que la valeur courante doit être mappée vers $values. si $values * est null, la valeur courante n'est pas mappée. * Cette méthode doit être appelée depuis le corps de {@link mapper()} */ function mapTo(?iterable $values) { if ($this->action !== self::USE_MAPPED_ITERABLES_ACTION) { $this->action = self::USE_MAPPED_ITERABLES_ACTION; $this->mappedIterables = []; } if ($values !== null) { $this->mappedIterables[] = $values; } return null; } /** * indiquer que la valeur courante doit être mappée vers $value avec * éventuellement la clé $key. $value est fournie telle quelle: notamment, * cette méthode peut être utilisée pour mapper la valeur courante vers null. * Cette méthode doit être appelée depuis le corps de {@link mapper()} */ function mapToValue($value, $key=null) { if ($key !== null) return $this->mapTo([$key => $value]); else return $this->mapTo([$value]); } /** * indiquer que la valeur courante n'est pas mappée. * Cette méthode doit être appelée depuis le corps de {@link mapper()} */ function mapToNone() { return $this->mapTo(null); } /** * indiquer que la valeur courante ne peut pas être traitée pour le moment et * qu'elle doit de nouveau être présentée à la fonction {@link mapper()} la * fois suivante. cela permet d'implémenter des méthodes de mapping plus * complexes. attention tout de même à ne pas créer de boucles infinies. * Cette méthode doit être appelée depuis le corps de {@link mapper()} */ function retry() { $this->action = self::RETRY_ACTION; return null; } /** * mapper la valeur courante $item. il faut * - soit retourner la valeur mappée. si on retourne null, la valeur n'est pas * mappée (il n'y a pas de valeur correspondante, elle est donc ignorée). * avec cette façon de faire, les clés originales sont conservées * - soit appeler l'une des méthodes {@link mapTo()}, {@link mapToValue()}, * {@link mapToNone()} pour indiquer la ou les valeurs correspondantes (ainsi * que les clés correspondantes le cas échéant). avec cette façon de faire, * les clés originales sont perdues * * Dans les classes dérivées, il est possible de rajouter "$key=null" à la * signature de cette fonction pour avoir aussi la clé */ abstract function mapper($item); ############################################################################# const _AUTOGEN_CONSTS = [ "" => [self::class, "_autogen_consts"], ]; const _AUTOGEN_LITERALS = /*autogen*/[ [ \nur\b\params\parametrable_utils::class, '\\nur\\b\\params\\parametrable_utils::class', ], [ self::PARAMETRABLE_PARAMS_SCHEMA, 'self::PARAMETRABLE_PARAMS_SCHEMA', ], ]; const _AUTOGEN_METHODS = /*autogen*/[ [ \nur\b\params\parametrable_utils::class, '_autogen_methods_getters', self::PARAMETRABLE_PARAMS_SCHEMA, null, ], [ \nur\b\params\parametrable_utils::class, '_autogen_methods_setters', self::PARAMETRABLE_PARAMS_SCHEMA, null, ], ]; const _AUTO_GETTERS = /*autogen*/[ 'getSource' => 'source', ]; const _AUTO_SETTERS = /*autogen*/[ 'setSource' => 'source', ]; #--autogen-dynamic-- }