multiSchema = $multiSchema; } /** * @var array liste et ordre des champs en sortie. si cette valeur n'est pas * spécifiée, elle est calculée à partir du premier élément du flux. */ protected $headers; function setHeaders(array $headers): void { $this->headers = $headers; } /** @var bool faut-il afficher les en-têtes en sortie? */ protected $outputHeaders = true; function setOutputHeaders(bool $outputHeaders): void { $this->outputHeaders = $outputHeaders; } /** @var ?array mappings des clés du tableau vers les colonne en sortie */ protected $headerMappings; /** * $headerMappings peut être * - un tableau de la forme [include, add => null, source => dest] * - ou une chaine de la forme "include,=add,source=dest" * source est le nom de la clé dans le tableau en entrée, dest est le nom de * la colonne dans le flux CSV en sortie * * - les éléments 'include' permettent d'inclure le champ spécifié. si aucun * champ include n'est spécifié, *tous* les champs sont inclus (sauf ceux qui * sont exclus, bien entendu) * - les éléments '=add' permettent d'ajouter dans la sortie une colonne avec * une valeur vide * - les éléments 'dest=source' permettent de renommer les champs: le champ * source dans le flux CSV devient le champ dest dans le tableau associatif */ function setHeaderMappings($headerMappings): void { if ($headerMappings !== null && !is_array($headerMappings)) { $mappings = explode(",", strval($headerMappings)); $headerMappings = []; foreach ($mappings as $mapping) { if (($index = strpos($mapping, "=")) !== false) { $source = substr($mapping, 0, $index); $dest = substr($mapping, $index + 1); if ($source && $dest) $headerMappings[$source] = $dest; elseif ($source) $headerMappings[$source] = null; else $headerMappings[$dest] = null; } else { $headerMappings[] = $mapping; } } } $this->headerMappings = $headerMappings; } function checkHeaders(?array $row): array { $skipLine = false; if ($row === null) { $outputHeaders = $this->outputHeaders && $this->headers !== null; return [$skipLine, $outputHeaders, $this->headers]; } $prevHeaders = $this->headers; if ($this->multiSchema) { # vérifier si le schéma a changé $headers = $this->computeHeaders($row); if ($prevHeaders === null) $prevHeaders = $headers; if (self::is_different($prevHeaders, $headers)) { $skipLine = true; $this->outputHeaders = true; } else { $headers = $prevHeaders; } } else { $headers = $prevHeaders; if ($headers === null) $headers = $this->computeHeaders($row); } return [$skipLine, $this->outputHeaders, $headers]; } function resetOutputHeaders(array $headers): void { $this->headers = $headers; $this->outputHeaders = false; } function cookHeaders(array $headers): array { return ut::writer_map_headers($headers, $this->headerMappings); } function cookValues(array $headers, array $row): array { $values = []; foreach ($headers as $header) { $values[$header] = A::get($row, $header); } $values = ut::writer_map_keys($values, $this->headerMappings); return array_values($values); } function getLine(array $values, string $flavour, bool $stripNl=true): string { [$separator, $enclosure, $escape] = flavours::get_params($flavour); $tmpf = fopen("php://memory", "w+b"); fputcsv($tmpf, $values, $separator, $enclosure, $escape); rewind($tmpf); $line = stream_get_contents($tmpf); if ($stripNl) $line = str::strip_nl($line); fclose($tmpf); return $line; } }