Mercurial > hg > isophonics-drupal-site
diff vendor/symfony/serializer/Encoder/CsvEncoder.php @ 14:1fec387a4317
Update Drupal core to 8.5.2 via Composer
author | Chris Cannam |
---|---|
date | Mon, 23 Apr 2018 09:46:53 +0100 |
parents | 4c8ae668cc8c |
children | 129ea1e6d783 |
line wrap: on
line diff
--- a/vendor/symfony/serializer/Encoder/CsvEncoder.php Mon Apr 23 09:33:26 2018 +0100 +++ b/vendor/symfony/serializer/Encoder/CsvEncoder.php Mon Apr 23 09:46:53 2018 +0100 @@ -17,10 +17,16 @@ * Encodes CSV data. * * @author Kévin Dunglas <dunglas@gmail.com> + * @author Oliver Hoff <oliver@hofff.com> */ class CsvEncoder implements EncoderInterface, DecoderInterface { const FORMAT = 'csv'; + const DELIMITER_KEY = 'csv_delimiter'; + const ENCLOSURE_KEY = 'csv_enclosure'; + const ESCAPE_CHAR_KEY = 'csv_escape_char'; + const KEY_SEPARATOR_KEY = 'csv_key_separator'; + const HEADERS_KEY = 'csv_headers'; private $delimiter; private $enclosure; @@ -65,19 +71,22 @@ } } - $headers = null; - foreach ($data as $value) { - $result = array(); - $this->flatten($value, $result); + list($delimiter, $enclosure, $escapeChar, $keySeparator, $headers) = $this->getCsvOptions($context); - if (null === $headers) { - $headers = array_keys($result); - fputcsv($handle, $headers, $this->delimiter, $this->enclosure, $this->escapeChar); - } elseif (array_keys($result) !== $headers) { - throw new InvalidArgumentException('To use the CSV encoder, each line in the data array must have the same structure. You may want to use a custom normalizer class to normalize the data format before passing it to the CSV encoder.'); - } + foreach ($data as &$value) { + $flattened = array(); + $this->flatten($value, $flattened, $keySeparator); + $value = $flattened; + } + unset($value); - fputcsv($handle, $result, $this->delimiter, $this->enclosure, $this->escapeChar); + $headers = array_merge(array_values($headers), array_diff($this->extractHeaders($data), $headers)); + + fputcsv($handle, $headers, $delimiter, $enclosure, $escapeChar); + + $headers = array_fill_keys($headers, ''); + foreach ($data as $row) { + fputcsv($handle, array_replace($headers, $row), $delimiter, $enclosure, $escapeChar); } rewind($handle); @@ -106,16 +115,21 @@ $headers = null; $nbHeaders = 0; + $headerCount = array(); $result = array(); - while (false !== ($cols = fgetcsv($handle, 0, $this->delimiter, $this->enclosure, $this->escapeChar))) { + list($delimiter, $enclosure, $escapeChar, $keySeparator) = $this->getCsvOptions($context); + + while (false !== ($cols = fgetcsv($handle, 0, $delimiter, $enclosure, $escapeChar))) { $nbCols = count($cols); if (null === $headers) { $nbHeaders = $nbCols; foreach ($cols as $col) { - $headers[] = explode($this->keySeparator, $col); + $header = explode($keySeparator, $col); + $headers[] = $header; + $headerCount[] = count($header); } continue; @@ -123,7 +137,7 @@ $item = array(); for ($i = 0; ($i < $nbCols) && ($i < $nbHeaders); ++$i) { - $depth = count($headers[$i]); + $depth = $headerCount[$i]; $arr = &$item; for ($j = 0; $j < $depth; ++$j) { // Handle nested arrays @@ -166,16 +180,68 @@ * * @param array $array * @param array $result + * @param string $keySeparator * @param string $parentKey */ - private function flatten(array $array, array &$result, $parentKey = '') + private function flatten(array $array, array &$result, $keySeparator, $parentKey = '') { foreach ($array as $key => $value) { if (is_array($value)) { - $this->flatten($value, $result, $parentKey.$key.$this->keySeparator); + $this->flatten($value, $result, $keySeparator, $parentKey.$key.$keySeparator); } else { $result[$parentKey.$key] = $value; } } } + + private function getCsvOptions(array $context) + { + $delimiter = isset($context[self::DELIMITER_KEY]) ? $context[self::DELIMITER_KEY] : $this->delimiter; + $enclosure = isset($context[self::ENCLOSURE_KEY]) ? $context[self::ENCLOSURE_KEY] : $this->enclosure; + $escapeChar = isset($context[self::ESCAPE_CHAR_KEY]) ? $context[self::ESCAPE_CHAR_KEY] : $this->escapeChar; + $keySeparator = isset($context[self::KEY_SEPARATOR_KEY]) ? $context[self::KEY_SEPARATOR_KEY] : $this->keySeparator; + $headers = isset($context[self::HEADERS_KEY]) ? $context[self::HEADERS_KEY] : array(); + + if (!is_array($headers)) { + throw new InvalidArgumentException(sprintf('The "%s" context variable must be an array or null, given "%s".', self::HEADERS_KEY, gettype($headers))); + } + + return array($delimiter, $enclosure, $escapeChar, $keySeparator, $headers); + } + + /** + * @return string[] + */ + private function extractHeaders(array $data) + { + $headers = array(); + $flippedHeaders = array(); + + foreach ($data as $row) { + $previousHeader = null; + + foreach ($row as $header => $_) { + if (isset($flippedHeaders[$header])) { + $previousHeader = $header; + continue; + } + + if (null === $previousHeader) { + $n = count($headers); + } else { + $n = $flippedHeaders[$previousHeader] + 1; + + for ($j = count($headers); $j > $n; --$j) { + ++$flippedHeaders[$headers[$j] = $headers[$j - 1]]; + } + } + + $headers[$n] = $header; + $flippedHeaders[$header] = $n; + $previousHeader = $header; + } + } + + return $headers; + } }