145 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			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--
 | |
| }
 |