From 8bb37a95b20021d35f7c3e81f1bcb9546763c885 Mon Sep 17 00:00:00 2001 From: Leandro Diniz Date: Fri, 2 Dec 2022 20:28:54 -0300 Subject: [PATCH] feature Add the possibility by filtering csv values by headers --- .../Serializer/Encoder/CsvEncoder.php | 17 +++++-- .../Tests/Encoder/CsvEncoderTest.php | 45 +++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php index 6706a229cedda..6a5f1578030c4 100644 --- a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php @@ -28,6 +28,7 @@ class CsvEncoder implements EncoderInterface, DecoderInterface public const ESCAPE_CHAR_KEY = 'csv_escape_char'; public const KEY_SEPARATOR_KEY = 'csv_key_separator'; public const HEADERS_KEY = 'csv_headers'; + public const CSV_FILTER_VALUES_BY_HEADERS_KEY = 'csv_filter_values_by_headers'; public const ESCAPE_FORMULAS_KEY = 'csv_escape_formulas'; public const AS_COLLECTION_KEY = 'as_collection'; public const NO_HEADERS_KEY = 'no_headers'; @@ -47,6 +48,7 @@ class CsvEncoder implements EncoderInterface, DecoderInterface self::HEADERS_KEY => [], self::KEY_SEPARATOR_KEY => '.', self::NO_HEADERS_KEY => false, + self::CSV_FILTER_VALUES_BY_HEADERS_KEY => false, self::AS_COLLECTION_KEY => true, self::OUTPUT_UTF8_BOM_KEY => false, ]; @@ -86,10 +88,17 @@ public function encode(mixed $data, string $format, array $context = []): string } unset($value); - $headers = array_merge(array_values($headers), array_diff($this->extractHeaders($data), $headers)); + $noHeaders = $context[self::NO_HEADERS_KEY] ?? $this->defaultContext[self::NO_HEADERS_KEY]; + $filterByHeaders = !$noHeaders ? $context[self::CSV_FILTER_VALUES_BY_HEADERS_KEY] ?? + $this->defaultContext[self::CSV_FILTER_VALUES_BY_HEADERS_KEY] : false; + + $headers = array_merge( + array_values($headers), + $filterByHeaders ? [] : array_diff($this->extractHeaders($data), $headers) + ); $endOfLine = $context[self::END_OF_LINE] ?? $this->defaultContext[self::END_OF_LINE]; - if (!($context[self::NO_HEADERS_KEY] ?? $this->defaultContext[self::NO_HEADERS_KEY])) { + if (!$noHeaders) { fputcsv($handle, $headers, $delimiter, $enclosure, $escapeChar); if ("\n" !== $endOfLine && 0 === fseek($handle, -1, \SEEK_CUR)) { fwrite($handle, $endOfLine); @@ -98,7 +107,9 @@ public function encode(mixed $data, string $format, array $context = []): string $headers = array_fill_keys($headers, ''); foreach ($data as $row) { - fputcsv($handle, array_replace($headers, $row), $delimiter, $enclosure, $escapeChar); + $fields = $filterByHeaders ? array_replace($headers, array_intersect_key($row, $headers)) : + array_replace($headers, $row); + fputcsv($handle, $fields, $delimiter, $enclosure, $escapeChar); if ("\n" !== $endOfLine && 0 === fseek($handle, -1, \SEEK_CUR)) { fwrite($handle, $endOfLine); } diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php index 77a7758e368ad..6de70ed45eb18 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php @@ -245,6 +245,51 @@ public function testEncodeCustomHeaders() $this->assertEquals($csv, $this->encoder->encode($value, 'csv', $context)); } + public function testEncodeCustomHeadersWithFilteringValuesByHeaders() + { + $context = [ + CsvEncoder::HEADERS_KEY => [ + 'c', + 'd', + 'b', + ], + CsvEncoder::CSV_FILTER_VALUES_BY_HEADERS_KEY => true, + ]; + $value = [ + ['a' => 'foo', 'b' => 'bar', 'd' => 'hey ho'], + ]; + $csv = <<assertEquals($csv, $this->encoder->encode($value, 'csv', $context)); + } + + public function testEncodeWithoutHeadersAndWithFilteringValuesByHeadersShouldIgnoreFiltering() + { + $this->assertSame(<<<'CSV' +a,b +c,d + +CSV + , $this->encoder->encode([['a', 'b'], ['c', 'd']], 'csv', [ + CsvEncoder::NO_HEADERS_KEY => true, + CsvEncoder::CSV_FILTER_VALUES_BY_HEADERS_KEY => true, + ])); + $encoder = new CsvEncoder([CsvEncoder::NO_HEADERS_KEY => true]); + $this->assertSame(<<<'CSV' +a,b +c,d + +CSV + , $encoder->encode([['a', 'b'], ['c', 'd']], 'csv', [ + CsvEncoder::NO_HEADERS_KEY => true, + CsvEncoder::CSV_FILTER_VALUES_BY_HEADERS_KEY => true, + ])); + } + public function testEncodeFormulas() { $this->encoder = new CsvEncoder([CsvEncoder::ESCAPE_FORMULAS_KEY => true]);