nur-sery/nur_src/mapper/csv/Csv2AssocMapper.php

145 lines
4.0 KiB
PHP

<?php
namespace nur\mapper\csv;
use nur\b\params\Tparametrable;
use nur\mapper\item\Seq2AssocMapper;
/**
* Class Csv2AssocMapper: mapper qui analyse un flux de lignes au format CSV et
* qui produit un flux de tableaux associatifs
*
* NB: cette classe ne supporte pas les flux CSV multi-lignes, contrairement à
* {@link CsvReader}
*
* --autogen-properties-and-methods--
* @method int getSkipLines()
* @method bool|null setParseHeaders(?bool $value)
* @method array|null setHeaders(?array $value)
* @method int setSkipLines(int $value)
* @method string|null setMapEmpty(?string $value)
*/
class Csv2AssocMapper extends AbstractCsvMapper {
use Tparametrable;
function __construct(?iterable $source=null) {
$this->seq2assoc = new Seq2AssocMapper();
parent::__construct($source);
}
const PARAMETRABLE_PARAMS_SCHEMA = [
"parse_headers" => ["?bool", null, "faut-il analyser le premier élément du flux pour calculer la liste des en-têtes en entrée?"],
"headers" => ["?array", null, "liste et ordre des en-têtes en entrée"],
"skip_lines" => ["int", 0, "nombre de lignes à sauter en entrée"],
"map_empty" => ["?string", null, "valeur adoptée pour les chaines vides"],
];
/** @var Seq2AssocMapper */
private $seq2assoc;
function pp_setParseHeaders(?bool $parseHeaders): void {
$this->seq2assoc->setParseKeys($parseHeaders);
}
function pp_setHeaders(?array $headers): void {
$this->seq2assoc->setKeys($headers);
}
/** @var int */
protected $ppSkipLines;
/** @var bool */
protected $shouldMapEmpty = false;
protected $ppMapEmpty = null;
function pp_setMapEmpty($mapEmpty=null): void {
$this->shouldMapEmpty = true;
$this->ppMapEmpty = $mapEmpty;
}
protected function setup(): void {
parent::setup();
$this->seq2assoc->ensureSetup();
}
function _parseLine(): bool {
if ($this->ppSkipLines > 0) {
$this->ppSkipLines--;
return false;
}
return true;
}
/** @var array */
private $headers;
function _checkHeader(array $values): bool {
if ($this->ppMultiSchema && count($values) === 1 && $values[0] === null) {
# ligne vide, changer de schéma
$this->seq2assoc->setKeys(null);
return true;
}
return $this->seq2assoc->_checkKeys($values);
}
function _mapRow(array $values): array {
$row = $this->seq2assoc->_mapValues($values);
foreach ($row as &$value) {
if ($value === "" && $this->shouldMapEmpty) $value = $this->ppMapEmpty;
}; unset($value);
return $row;
}
function mapper($item) {
if (!$this->_parseLine()) return $this->mapToNone();
$values = str_getcsv($item, $this->separator, $this->enclosure, $this->escape);
if ($this->_checkHeader($values)) return $this->mapToNone();
return $this->_mapRow($values);
}
protected function teardown(): void {
parent::teardown();
$this->seq2assoc->close();
}
#############################################################################
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*/[
'getParseHeaders' => 'parse_headers',
'getHeaders' => 'headers',
'getSkipLines' => 'skip_lines',
'getMapEmpty' => 'map_empty',
];
const _AUTO_SETTERS = /*autogen*/[
'setParseHeaders' => 'parse_headers',
'setHeaders' => 'headers',
'setSkipLines' => 'skip_lines',
'setMapEmpty' => 'map_empty',
];
#--autogen-dynamic--
}