Skip to content

Commit 1f58925

Browse files
[Serializer][Translation] Deprecate passing a non-empty CSV escape char
1 parent b2e4eac commit 1f58925

File tree

10 files changed

+96
-12
lines changed

10 files changed

+96
-12
lines changed

UPGRADE-7.2.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ Security
4040
* Add `$token` argument to `UserCheckerInterface::checkPostAuth()`
4141
* Deprecate argument `$secret` of `RememberMeToken` and `RememberMeAuthenticator`
4242

43+
Serializer
44+
----------
45+
46+
* Deprecate the `csv_escape_char` context option of `CsvEncoder` and the `CsvEncoder::ESCAPE_CHAR_KEY` constant
47+
* Deprecate `CsvEncoderContextBuilder::withEscapeChar()` method
48+
4349
String
4450
------
4551

@@ -48,6 +54,11 @@ String
4854
* `TruncateMode::WordAfter` is equivalent to `false` value ;
4955
* `TruncateMode::WordBefore` is a new mode that will cut the sentence on the last word before the limit is reached.
5056

57+
Translation
58+
-----------
59+
60+
* Deprecate passing an escape character to `CsvFileLoader::setCsvControl()`
61+
5162
Yaml
5263
----
5364

src/Symfony/Component/Serializer/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
CHANGELOG
22
=========
33

4+
7.2
5+
---
6+
7+
* Deprecate the `csv_escape_char` context option of `CsvEncoder` and the `CsvEncoder::ESCAPE_CHAR_KEY` constant
8+
* Deprecate `CsvEncoderContextBuilder::withEscapeChar()` method
9+
410
7.1
511
---
612

src/Symfony/Component/Serializer/Context/Encoder/CsvEncoderContextBuilder.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,14 @@ public function withEnclosure(?string $enclosure): static
6262
*
6363
* Must be empty or a single character.
6464
*
65+
* @deprecated since Symfony 7.2, to be removed in 8.0
66+
*
6567
* @throws InvalidArgumentException
6668
*/
6769
public function withEscapeChar(?string $escapeChar): static
6870
{
71+
trigger_deprecation('symfony/serializer', '7.2', 'The "%s" method is deprecated. It will be removed in 8.0.', __METHOD__);
72+
6973
if (null !== $escapeChar && \strlen($escapeChar) > 1) {
7074
throw new InvalidArgumentException(\sprintf('The "%s" escape character must be empty or a single character.', $escapeChar));
7175
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ class CsvEncoder implements EncoderInterface, DecoderInterface
2525
public const FORMAT = 'csv';
2626
public const DELIMITER_KEY = 'csv_delimiter';
2727
public const ENCLOSURE_KEY = 'csv_enclosure';
28+
/**
29+
* @deprecated since Symfony 7.2, to be removed in 8.0
30+
*/
2831
public const ESCAPE_CHAR_KEY = 'csv_escape_char';
2932
public const KEY_SEPARATOR_KEY = 'csv_key_separator';
3033
public const HEADERS_KEY = 'csv_headers';
@@ -53,6 +56,10 @@ class CsvEncoder implements EncoderInterface, DecoderInterface
5356

5457
public function __construct(array $defaultContext = [])
5558
{
59+
if (\array_key_exists(self::ESCAPE_CHAR_KEY, $defaultContext)) {
60+
trigger_deprecation('symfony/serializer', '7.2', 'Setting the "csv_escape_char" option is deprecated. The option will be removed in 8.0.');
61+
}
62+
5663
$this->defaultContext = array_merge($this->defaultContext, $defaultContext);
5764
}
5865

src/Symfony/Component/Serializer/Tests/Context/Encoder/CsvEncoderContextBuilderTest.php

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Serializer\Tests\Context\Encoder;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
1516
use Symfony\Component\Serializer\Context\Encoder\CsvEncoderContextBuilder;
1617
use Symfony\Component\Serializer\Encoder\CsvEncoder;
1718
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
@@ -21,6 +22,8 @@
2122
*/
2223
class CsvEncoderContextBuilderTest extends TestCase
2324
{
25+
use ExpectDeprecationTrait;
26+
2427
private CsvEncoderContextBuilder $contextBuilder;
2528

2629
protected function setUp(): void
@@ -38,7 +41,6 @@ public function testWithers(array $values)
3841
$context = $this->contextBuilder
3942
->withDelimiter($values[CsvEncoder::DELIMITER_KEY])
4043
->withEnclosure($values[CsvEncoder::ENCLOSURE_KEY])
41-
->withEscapeChar($values[CsvEncoder::ESCAPE_CHAR_KEY])
4244
->withKeySeparator($values[CsvEncoder::KEY_SEPARATOR_KEY])
4345
->withHeaders($values[CsvEncoder::HEADERS_KEY])
4446
->withEscapedFormulas($values[CsvEncoder::ESCAPE_FORMULAS_KEY])
@@ -59,7 +61,6 @@ public static function withersDataProvider(): iterable
5961
yield 'With values' => [[
6062
CsvEncoder::DELIMITER_KEY => ';',
6163
CsvEncoder::ENCLOSURE_KEY => '"',
62-
CsvEncoder::ESCAPE_CHAR_KEY => '\\',
6364
CsvEncoder::KEY_SEPARATOR_KEY => '_',
6465
CsvEncoder::HEADERS_KEY => ['h1', 'h2'],
6566
CsvEncoder::ESCAPE_FORMULAS_KEY => true,
@@ -72,7 +73,6 @@ public static function withersDataProvider(): iterable
7273
yield 'With null values' => [[
7374
CsvEncoder::DELIMITER_KEY => null,
7475
CsvEncoder::ENCLOSURE_KEY => null,
75-
CsvEncoder::ESCAPE_CHAR_KEY => null,
7676
CsvEncoder::KEY_SEPARATOR_KEY => null,
7777
CsvEncoder::HEADERS_KEY => null,
7878
CsvEncoder::ESCAPE_FORMULAS_KEY => null,
@@ -88,7 +88,6 @@ public function testWithersWithoutValue()
8888
$context = $this->contextBuilder
8989
->withDelimiter(null)
9090
->withEnclosure(null)
91-
->withEscapeChar(null)
9291
->withKeySeparator(null)
9392
->withHeaders(null)
9493
->withEscapedFormulas(null)
@@ -101,7 +100,6 @@ public function testWithersWithoutValue()
101100
$this->assertSame([
102101
CsvEncoder::DELIMITER_KEY => null,
103102
CsvEncoder::ENCLOSURE_KEY => null,
104-
CsvEncoder::ESCAPE_CHAR_KEY => null,
105103
CsvEncoder::KEY_SEPARATOR_KEY => null,
106104
CsvEncoder::HEADERS_KEY => null,
107105
CsvEncoder::ESCAPE_FORMULAS_KEY => null,
@@ -124,9 +122,25 @@ public function testCannotSetMultipleBytesAsEnclosure()
124122
$this->contextBuilder->withEnclosure('');
125123
}
126124

125+
/**
126+
* @group legacy
127+
*/
127128
public function testCannotSetMultipleBytesAsEscapeChar()
128129
{
130+
$this->expectDeprecation('Since symfony/serializer 7.2: The "Symfony\Component\Serializer\Context\Encoder\CsvEncoderContextBuilder::withEscapeChar" method is deprecated. It will be removed in 8.0.');
131+
129132
$this->expectException(InvalidArgumentException::class);
130133
$this->contextBuilder->withEscapeChar('');
131134
}
135+
136+
/**
137+
* @group legacy
138+
*/
139+
public function testWithEscapeCharIsDeprecated()
140+
{
141+
$this->expectDeprecation('Since symfony/serializer 7.2: The "Symfony\Component\Serializer\Context\Encoder\CsvEncoderContextBuilder::withEscapeChar" method is deprecated. It will be removed in 8.0.');
142+
$context = $this->contextBuilder->withEscapeChar('\\');
143+
144+
$this->assertSame(['csv_escape_char' => '\\'], $context->toArray());
145+
}
132146
}

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

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Serializer\Tests\Encoder;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
1516
use Symfony\Component\Serializer\Encoder\CsvEncoder;
1617
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
1718

@@ -20,6 +21,8 @@
2021
*/
2122
class CsvEncoderTest extends TestCase
2223
{
24+
use ExpectDeprecationTrait;
25+
2326
private CsvEncoder $encoder;
2427

2528
protected function setUp(): void
@@ -149,7 +152,6 @@ public function testEncodeCustomSettings()
149152
$this->encoder = new CsvEncoder([
150153
CsvEncoder::DELIMITER_KEY => ';',
151154
CsvEncoder::ENCLOSURE_KEY => "'",
152-
CsvEncoder::ESCAPE_CHAR_KEY => \PHP_VERSION_ID < 70400 ? '|' : '',
153155
CsvEncoder::KEY_SEPARATOR_KEY => '-',
154156
]);
155157

@@ -175,7 +177,6 @@ public function testEncodeCustomSettingsPassedInContext()
175177
, $this->encoder->encode($value, 'csv', [
176178
CsvEncoder::DELIMITER_KEY => ';',
177179
CsvEncoder::ENCLOSURE_KEY => "'",
178-
CsvEncoder::ESCAPE_CHAR_KEY => \PHP_VERSION_ID < 70400 ? '|' : '',
179180
CsvEncoder::KEY_SEPARATOR_KEY => '-',
180181
]));
181182
}
@@ -185,7 +186,6 @@ public function testEncodeCustomSettingsPassedInConstructor()
185186
$encoder = new CsvEncoder([
186187
CsvEncoder::DELIMITER_KEY => ';',
187188
CsvEncoder::ENCLOSURE_KEY => "'",
188-
CsvEncoder::ESCAPE_CHAR_KEY => \PHP_VERSION_ID < 70400 ? '|' : '',
189189
CsvEncoder::KEY_SEPARATOR_KEY => '-',
190190
]);
191191
$value = ['a' => 'he\'llo', 'c' => ['d' => 'foo']];
@@ -574,7 +574,6 @@ public function testDecodeCustomSettings()
574574
$this->encoder = new CsvEncoder([
575575
CsvEncoder::DELIMITER_KEY => ';',
576576
CsvEncoder::ENCLOSURE_KEY => "'",
577-
CsvEncoder::ESCAPE_CHAR_KEY => \PHP_VERSION_ID < 70400 ? '|' : '',
578577
CsvEncoder::KEY_SEPARATOR_KEY => '-',
579578
]);
580579

@@ -596,7 +595,6 @@ public function testDecodeCustomSettingsPassedInContext()
596595
, 'csv', [
597596
CsvEncoder::DELIMITER_KEY => ';',
598597
CsvEncoder::ENCLOSURE_KEY => "'",
599-
CsvEncoder::ESCAPE_CHAR_KEY => \PHP_VERSION_ID < 70400 ? '|' : '',
600598
CsvEncoder::KEY_SEPARATOR_KEY => '-',
601599
]));
602600
}
@@ -606,7 +604,6 @@ public function testDecodeCustomSettingsPassedInConstructor()
606604
$encoder = new CsvEncoder([
607605
CsvEncoder::DELIMITER_KEY => ';',
608606
CsvEncoder::ENCLOSURE_KEY => "'",
609-
CsvEncoder::ESCAPE_CHAR_KEY => \PHP_VERSION_ID < 70400 ? '|' : '',
610607
CsvEncoder::KEY_SEPARATOR_KEY => '-',
611608
CsvEncoder::AS_COLLECTION_KEY => true, // Can be removed in 5.0
612609
]);
@@ -710,4 +707,26 @@ public function testEndOfLinePassedInConstructor()
710707
$encoder = new CsvEncoder([CsvEncoder::END_OF_LINE => "\r\n"]);
711708
$this->assertSame("foo,bar\r\nhello,test\r\n", $encoder->encode($value, 'csv'));
712709
}
710+
711+
/**
712+
* @group legacy
713+
*/
714+
public function testPassingNonEmptyEscapeCharIsDeprecated()
715+
{
716+
$this->expectDeprecation('Since symfony/serializer 7.2: Setting the "csv_escape_char" option is deprecated. The option will be removed in 8.0.');
717+
$encoder = new CsvEncoder(['csv_escape_char' => '@']);
718+
719+
$this->assertSame(
720+
[[
721+
'A, B@"' => 'D',
722+
'C' => 'E',
723+
]],
724+
$encoder->decode(<<<'CSV'
725+
"A, B@"", "C"
726+
"D", "E"
727+
CSV,
728+
'csv'
729+
)
730+
);
731+
}
713732
}

src/Symfony/Component/Translation/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Add `lint:translations` command
8+
* Deprecate passing an escape character to `CsvFileLoader::setCsvControl()`
89

910
7.1
1011
---

src/Symfony/Component/Translation/Loader/CsvFileLoader.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ class CsvFileLoader extends FileLoader
2222
{
2323
private string $delimiter = ';';
2424
private string $enclosure = '"';
25+
/**
26+
* @deprecated since Symfony 7.2, to be removed in 8.0
27+
*/
2528
private string $escape = '';
2629

2730
protected function loadResource(string $resource): array
@@ -57,6 +60,10 @@ public function setCsvControl(string $delimiter = ';', string $enclosure = '"',
5760
{
5861
$this->delimiter = $delimiter;
5962
$this->enclosure = $enclosure;
63+
if ('' !== $escape) {
64+
trigger_deprecation('symfony/translation', '7.2', 'The "escape" parameter of the "%s" method is deprecated. It will be removed in 8.0.', __METHOD__);
65+
}
66+
6067
$this->escape = $escape;
6168
}
6269
}

src/Symfony/Component/Translation/Tests/Loader/CsvFileLoaderTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@
1212
namespace Symfony\Component\Translation\Tests\Loader;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
1516
use Symfony\Component\Config\Resource\FileResource;
1617
use Symfony\Component\Translation\Exception\InvalidResourceException;
1718
use Symfony\Component\Translation\Exception\NotFoundResourceException;
1819
use Symfony\Component\Translation\Loader\CsvFileLoader;
1920

2021
class CsvFileLoaderTest extends TestCase
2122
{
23+
use ExpectDeprecationTrait;
24+
2225
public function testLoad()
2326
{
2427
$loader = new CsvFileLoader();
@@ -54,4 +57,15 @@ public function testLoadNonLocalResource()
5457

5558
(new CsvFileLoader())->load('http://example.com/resources.csv', 'en', 'domain1');
5659
}
60+
61+
/**
62+
* @group legacy
63+
*/
64+
public function testEscapeCharInCsvControlIsDeprecated()
65+
{
66+
$loader = new CsvFileLoader();
67+
68+
$this->expectDeprecation('Since symfony/translation 7.2: The "escape" parameter of the "Symfony\Component\Translation\Loader\CsvFileLoader::setCsvControl" method is deprecated. It will be removed in 8.0.');
69+
$loader->setCsvControl(';', '"', '\\');
70+
}
5771
}

src/Symfony/Component/Translation/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"require": {
1919
"php": ">=8.2",
2020
"symfony/polyfill-mbstring": "~1.0",
21-
"symfony/translation-contracts": "^2.5|^3.0"
21+
"symfony/translation-contracts": "^2.5|^3.0",
22+
"symfony/deprecation-contracts": "^2.5|^3"
2223
},
2324
"require-dev": {
2425
"nikic/php-parser": "^4.18|^5.0",

0 commit comments

Comments
 (0)