Skip to content

Commit c09b3e8

Browse files
committed
feature Add the possibility by filtering csv values by headers
1 parent 043257f commit c09b3e8

File tree

2 files changed

+59
-3
lines changed

2 files changed

+59
-3
lines changed

src/Symfony/Component/Serializer/Encoder/CsvEncoder.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class CsvEncoder implements EncoderInterface, DecoderInterface
2828
public const ESCAPE_CHAR_KEY = 'csv_escape_char';
2929
public const KEY_SEPARATOR_KEY = 'csv_key_separator';
3030
public const HEADERS_KEY = 'csv_headers';
31+
public const CSV_FILTER_VALUES_BY_HEADERS_KEY = 'csv_filter_values_by_headers';
3132
public const ESCAPE_FORMULAS_KEY = 'csv_escape_formulas';
3233
public const AS_COLLECTION_KEY = 'as_collection';
3334
public const NO_HEADERS_KEY = 'no_headers';
@@ -47,6 +48,7 @@ class CsvEncoder implements EncoderInterface, DecoderInterface
4748
self::HEADERS_KEY => [],
4849
self::KEY_SEPARATOR_KEY => '.',
4950
self::NO_HEADERS_KEY => false,
51+
self::CSV_FILTER_VALUES_BY_HEADERS_KEY => false,
5052
self::AS_COLLECTION_KEY => true,
5153
self::OUTPUT_UTF8_BOM_KEY => false,
5254
];
@@ -86,10 +88,17 @@ public function encode(mixed $data, string $format, array $context = []): string
8688
}
8789
unset($value);
8890

89-
$headers = array_merge(array_values($headers), array_diff($this->extractHeaders($data), $headers));
91+
$noHeaders = $context[self::NO_HEADERS_KEY] ?? $this->defaultContext[self::NO_HEADERS_KEY];
92+
$filterByHeaders = !$noHeaders ? $context[self::CSV_FILTER_VALUES_BY_HEADERS_KEY] ??
93+
$this->defaultContext[self::CSV_FILTER_VALUES_BY_HEADERS_KEY] : false;
94+
95+
$headers = array_merge(
96+
array_values($headers),
97+
$filterByHeaders ? [] : array_diff($this->extractHeaders($data), $headers)
98+
);
9099
$endOfLine = $context[self::END_OF_LINE] ?? $this->defaultContext[self::END_OF_LINE];
91100

92-
if (!($context[self::NO_HEADERS_KEY] ?? $this->defaultContext[self::NO_HEADERS_KEY])) {
101+
if (!($noHeaders)) {
93102
fputcsv($handle, $headers, $delimiter, $enclosure, $escapeChar);
94103
if ("\n" !== $endOfLine && 0 === fseek($handle, -1, \SEEK_CUR)) {
95104
fwrite($handle, $endOfLine);
@@ -98,7 +107,9 @@ public function encode(mixed $data, string $format, array $context = []): string
98107

99108
$headers = array_fill_keys($headers, '');
100109
foreach ($data as $row) {
101-
fputcsv($handle, array_replace($headers, $row), $delimiter, $enclosure, $escapeChar);
110+
$fields = $filterByHeaders ? array_replace($headers, array_intersect_key($row, $headers)) :
111+
array_replace($headers, $row);
112+
fputcsv($handle, $fields, $delimiter, $enclosure, $escapeChar);
102113
if ("\n" !== $endOfLine && 0 === fseek($handle, -1, \SEEK_CUR)) {
103114
fwrite($handle, $endOfLine);
104115
}

src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,51 @@ public function testEncodeCustomHeaders()
245245
$this->assertEquals($csv, $this->encoder->encode($value, 'csv', $context));
246246
}
247247

248+
public function testEncodeCustomHeadersWithFilteringValuesByHeaders()
249+
{
250+
$context = [
251+
CsvEncoder::HEADERS_KEY => [
252+
'c',
253+
'd',
254+
'b',
255+
],
256+
CsvEncoder::CSV_FILTER_VALUES_BY_HEADERS_KEY => true,
257+
];
258+
$value = [
259+
['a' => 'foo', 'b' => 'bar', 'd' => 'hey ho'],
260+
];
261+
$csv = <<<CSV
262+
c,d,b
263+
,"hey ho",bar
264+
265+
CSV;
266+
267+
$this->assertEquals($csv, $this->encoder->encode($value, 'csv', $context));
268+
}
269+
270+
public function testEncodeWithoutHeadersAndWithFilteringValuesByHeadersShouldIgnoreFiltering()
271+
{
272+
$this->assertSame(<<<'CSV'
273+
a,b
274+
c,d
275+
276+
CSV
277+
, $this->encoder->encode([['a', 'b'], ['c', 'd']], 'csv', [
278+
CsvEncoder::NO_HEADERS_KEY => true,
279+
CsvEncoder::CSV_FILTER_VALUES_BY_HEADERS_KEY => true
280+
]));
281+
$encoder = new CsvEncoder([CsvEncoder::NO_HEADERS_KEY => true]);
282+
$this->assertSame(<<<'CSV'
283+
a,b
284+
c,d
285+
286+
CSV
287+
, $encoder->encode([['a', 'b'], ['c', 'd']], 'csv', [
288+
CsvEncoder::NO_HEADERS_KEY => true,
289+
CsvEncoder::CSV_FILTER_VALUES_BY_HEADERS_KEY => true
290+
]));
291+
}
292+
248293
public function testEncodeFormulas()
249294
{
250295
$this->encoder = new CsvEncoder([CsvEncoder::ESCAPE_FORMULAS_KEY => true]);

0 commit comments

Comments
 (0)