From 10a76aac1591bd018e1b07ce2fbfbaa64426a0a0 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Wed, 26 Apr 2017 14:03:39 +0200 Subject: [PATCH] [Serializer] Allow to pass csv encoder options in context --- .../Serializer/Encoder/CsvEncoder.php | 33 +++++++++++++++---- .../Tests/Encoder/CsvEncoderTest.php | 32 ++++++++++++++++++ 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php index f30d08f941da7..cdbe0eb44e659 100644 --- a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php @@ -21,6 +21,10 @@ 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'; private $delimiter; private $enclosure; @@ -65,19 +69,21 @@ public function encode($data, $format, array $context = array()) } } + list($delimiter, $enclosure, $escapeChar, $keySeparator) = $this->getCsvOptions($context); + $headers = null; foreach ($data as $value) { $result = array(); - $this->flatten($value, $result); + $this->flatten($value, $result, $keySeparator); if (null === $headers) { $headers = array_keys($result); - fputcsv($handle, $headers, $this->delimiter, $this->enclosure, $this->escapeChar); + fputcsv($handle, $headers, $delimiter, $enclosure, $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.'); } - fputcsv($handle, $result, $this->delimiter, $this->enclosure, $this->escapeChar); + fputcsv($handle, $result, $delimiter, $enclosure, $escapeChar); } rewind($handle); @@ -108,14 +114,16 @@ public function decode($data, $format, array $context = array()) $nbHeaders = 0; $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); + $headers[] = explode($keySeparator, $col); } continue; @@ -166,16 +174,27 @@ public function supportsDecoding($format) * * @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; + + return array($delimiter, $enclosure, $escapeChar, $keySeparator); + } } diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php index e4663ce8dddd4..61cbc03ee6d26 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php @@ -112,6 +112,23 @@ public function testEncodeCustomSettings() , $this->encoder->encode($value, 'csv')); } + public function testEncodeCustomSettingsPassedInContext() + { + $value = array('a' => 'he\'llo', 'c' => array('d' => 'foo')); + + $this->assertSame(<<<'CSV' +a;c-d +'he''llo';foo + +CSV + , $this->encoder->encode($value, 'csv', array( + CsvEncoder::DELIMITER_KEY => ';', + CsvEncoder::ENCLOSURE_KEY => "'", + CsvEncoder::ESCAPE_CHAR_KEY => '|', + CsvEncoder::KEY_SEPARATOR_KEY => '-', + ))); + } + public function testEncodeEmptyArray() { $this->assertEquals("\n\n", $this->encoder->encode(array(), 'csv')); @@ -207,6 +224,21 @@ public function testDecodeCustomSettings() , 'csv')); } + public function testDecodeCustomSettingsPassedInContext() + { + $expected = array('a' => 'hell\'o', 'bar' => array('baz' => 'b')); + $this->assertEquals($expected, $this->encoder->decode(<<<'CSV' +a;bar-baz +'hell''o';b;c +CSV + , 'csv', array( + CsvEncoder::DELIMITER_KEY => ';', + CsvEncoder::ENCLOSURE_KEY => "'", + CsvEncoder::ESCAPE_CHAR_KEY => '|', + CsvEncoder::KEY_SEPARATOR_KEY => '-', + ))); + } + public function testDecodeMalformedCollection() { $expected = array(