Skip to content

[Serializer][Translation] Deprecate passing a non-empty CSV escape char #57827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions UPGRADE-7.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ Security
* Add `$token` argument to `UserCheckerInterface::checkPostAuth()`
* Deprecate argument `$secret` of `RememberMeToken` and `RememberMeAuthenticator`

Serializer
----------

* Deprecate the `csv_escape_char` context option of `CsvEncoder` and the `CsvEncoder::ESCAPE_CHAR_KEY` constant
* Deprecate `CsvEncoderContextBuilder::withEscapeChar()` method

String
------

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

Translation
-----------

* Deprecate passing an escape character to `CsvFileLoader::setCsvControl()`

Yaml
----

Expand Down
6 changes: 6 additions & 0 deletions src/Symfony/Component/Serializer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
CHANGELOG
=========

7.2
---

* Deprecate the `csv_escape_char` context option of `CsvEncoder` and the `CsvEncoder::ESCAPE_CHAR_KEY` constant
* Deprecate `CsvEncoderContextBuilder::withEscapeChar()` method

7.1
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,14 @@ public function withEnclosure(?string $enclosure): static
*
* Must be empty or a single character.
*
* @deprecated since Symfony 7.2, to be removed in 8.0
*
* @throws InvalidArgumentException
*/
public function withEscapeChar(?string $escapeChar): static
{
trigger_deprecation('symfony/serializer', '7.2', 'The "%s" method is deprecated. It will be removed in 8.0.', __METHOD__);

if (null !== $escapeChar && \strlen($escapeChar) > 1) {
throw new InvalidArgumentException(\sprintf('The "%s" escape character must be empty or a single character.', $escapeChar));
}
Expand Down
7 changes: 7 additions & 0 deletions src/Symfony/Component/Serializer/Encoder/CsvEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ class CsvEncoder implements EncoderInterface, DecoderInterface
public const FORMAT = 'csv';
public const DELIMITER_KEY = 'csv_delimiter';
public const ENCLOSURE_KEY = 'csv_enclosure';
/**
* @deprecated since Symfony 7.2, to be removed in 8.0
*/
public const ESCAPE_CHAR_KEY = 'csv_escape_char';
public const KEY_SEPARATOR_KEY = 'csv_key_separator';
public const HEADERS_KEY = 'csv_headers';
Expand Down Expand Up @@ -53,6 +56,10 @@ class CsvEncoder implements EncoderInterface, DecoderInterface

public function __construct(array $defaultContext = [])
{
if (\array_key_exists(self::ESCAPE_CHAR_KEY, $defaultContext)) {
trigger_deprecation('symfony/serializer', '7.2', 'Setting the "csv_escape_char" option is deprecated. The option will be removed in 8.0.');
}

$this->defaultContext = array_merge($this->defaultContext, $defaultContext);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\Serializer\Tests\Context\Encoder;

use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
use Symfony\Component\Serializer\Context\Encoder\CsvEncoderContextBuilder;
use Symfony\Component\Serializer\Encoder\CsvEncoder;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
Expand All @@ -21,6 +22,8 @@
*/
class CsvEncoderContextBuilderTest extends TestCase
{
use ExpectDeprecationTrait;

private CsvEncoderContextBuilder $contextBuilder;

protected function setUp(): void
Expand All @@ -38,7 +41,6 @@ public function testWithers(array $values)
$context = $this->contextBuilder
->withDelimiter($values[CsvEncoder::DELIMITER_KEY])
->withEnclosure($values[CsvEncoder::ENCLOSURE_KEY])
->withEscapeChar($values[CsvEncoder::ESCAPE_CHAR_KEY])
->withKeySeparator($values[CsvEncoder::KEY_SEPARATOR_KEY])
->withHeaders($values[CsvEncoder::HEADERS_KEY])
->withEscapedFormulas($values[CsvEncoder::ESCAPE_FORMULAS_KEY])
Expand All @@ -59,7 +61,6 @@ public static function withersDataProvider(): iterable
yield 'With values' => [[
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => '"',
CsvEncoder::ESCAPE_CHAR_KEY => '\\',
CsvEncoder::KEY_SEPARATOR_KEY => '_',
CsvEncoder::HEADERS_KEY => ['h1', 'h2'],
CsvEncoder::ESCAPE_FORMULAS_KEY => true,
Expand All @@ -72,7 +73,6 @@ public static function withersDataProvider(): iterable
yield 'With null values' => [[
CsvEncoder::DELIMITER_KEY => null,
CsvEncoder::ENCLOSURE_KEY => null,
CsvEncoder::ESCAPE_CHAR_KEY => null,
CsvEncoder::KEY_SEPARATOR_KEY => null,
CsvEncoder::HEADERS_KEY => null,
CsvEncoder::ESCAPE_FORMULAS_KEY => null,
Expand All @@ -88,7 +88,6 @@ public function testWithersWithoutValue()
$context = $this->contextBuilder
->withDelimiter(null)
->withEnclosure(null)
->withEscapeChar(null)
->withKeySeparator(null)
->withHeaders(null)
->withEscapedFormulas(null)
Expand All @@ -101,7 +100,6 @@ public function testWithersWithoutValue()
$this->assertSame([
CsvEncoder::DELIMITER_KEY => null,
CsvEncoder::ENCLOSURE_KEY => null,
CsvEncoder::ESCAPE_CHAR_KEY => null,
CsvEncoder::KEY_SEPARATOR_KEY => null,
CsvEncoder::HEADERS_KEY => null,
CsvEncoder::ESCAPE_FORMULAS_KEY => null,
Expand All @@ -124,9 +122,25 @@ public function testCannotSetMultipleBytesAsEnclosure()
$this->contextBuilder->withEnclosure('ọ');
}

/**
* @group legacy
*/
public function testCannotSetMultipleBytesAsEscapeChar()
{
$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.');

$this->expectException(InvalidArgumentException::class);
$this->contextBuilder->withEscapeChar('ọ');
}

/**
* @group legacy
*/
public function testWithEscapeCharIsDeprecated()
{
$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.');
$context = $this->contextBuilder->withEscapeChar('\\');

$this->assertSame(['csv_escape_char' => '\\'], $context->toArray());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\Serializer\Tests\Encoder;

use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
use Symfony\Component\Serializer\Encoder\CsvEncoder;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;

Expand All @@ -20,6 +21,8 @@
*/
class CsvEncoderTest extends TestCase
{
use ExpectDeprecationTrait;

private CsvEncoder $encoder;

protected function setUp(): void
Expand Down Expand Up @@ -149,7 +152,6 @@ public function testEncodeCustomSettings()
$this->encoder = new CsvEncoder([
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
CsvEncoder::ESCAPE_CHAR_KEY => \PHP_VERSION_ID < 70400 ? '|' : '',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
]);

Expand All @@ -175,7 +177,6 @@ public function testEncodeCustomSettingsPassedInContext()
, $this->encoder->encode($value, 'csv', [
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
CsvEncoder::ESCAPE_CHAR_KEY => \PHP_VERSION_ID < 70400 ? '|' : '',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
]));
}
Expand All @@ -185,7 +186,6 @@ public function testEncodeCustomSettingsPassedInConstructor()
$encoder = new CsvEncoder([
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
CsvEncoder::ESCAPE_CHAR_KEY => \PHP_VERSION_ID < 70400 ? '|' : '',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
]);
$value = ['a' => 'he\'llo', 'c' => ['d' => 'foo']];
Expand Down Expand Up @@ -574,7 +574,6 @@ public function testDecodeCustomSettings()
$this->encoder = new CsvEncoder([
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
CsvEncoder::ESCAPE_CHAR_KEY => \PHP_VERSION_ID < 70400 ? '|' : '',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
]);

Expand All @@ -596,7 +595,6 @@ public function testDecodeCustomSettingsPassedInContext()
, 'csv', [
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
CsvEncoder::ESCAPE_CHAR_KEY => \PHP_VERSION_ID < 70400 ? '|' : '',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
]));
}
Expand All @@ -606,7 +604,6 @@ public function testDecodeCustomSettingsPassedInConstructor()
$encoder = new CsvEncoder([
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
CsvEncoder::ESCAPE_CHAR_KEY => \PHP_VERSION_ID < 70400 ? '|' : '',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
CsvEncoder::AS_COLLECTION_KEY => true, // Can be removed in 5.0
]);
Expand Down Expand Up @@ -710,4 +707,26 @@ public function testEndOfLinePassedInConstructor()
$encoder = new CsvEncoder([CsvEncoder::END_OF_LINE => "\r\n"]);
$this->assertSame("foo,bar\r\nhello,test\r\n", $encoder->encode($value, 'csv'));
}

/**
* @group legacy
*/
public function testPassingNonEmptyEscapeCharIsDeprecated()
{
$this->expectDeprecation('Since symfony/serializer 7.2: Setting the "csv_escape_char" option is deprecated. The option will be removed in 8.0.');
$encoder = new CsvEncoder(['csv_escape_char' => '@']);

$this->assertSame(
[[
'A, B@"' => 'D',
'C' => 'E',
]],
$encoder->decode(<<<'CSV'
"A, B@"", "C"
"D", "E"
CSV,
'csv'
)
);
}
}
1 change: 1 addition & 0 deletions src/Symfony/Component/Translation/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ CHANGELOG
---

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

7.1
---
Expand Down
7 changes: 7 additions & 0 deletions src/Symfony/Component/Translation/Loader/CsvFileLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ class CsvFileLoader extends FileLoader
{
private string $delimiter = ';';
private string $enclosure = '"';
/**
* @deprecated since Symfony 7.2, to be removed in 8.0
*/
private string $escape = '';

protected function loadResource(string $resource): array
Expand Down Expand Up @@ -57,6 +60,10 @@ public function setCsvControl(string $delimiter = ';', string $enclosure = '"',
{
$this->delimiter = $delimiter;
$this->enclosure = $enclosure;
if ('' !== $escape) {
trigger_deprecation('symfony/translation', '7.2', 'The "escape" parameter of the "%s" method is deprecated. It will be removed in 8.0.', __METHOD__);
}

$this->escape = $escape;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
namespace Symfony\Component\Translation\Tests\Loader;

use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Translation\Exception\InvalidResourceException;
use Symfony\Component\Translation\Exception\NotFoundResourceException;
use Symfony\Component\Translation\Loader\CsvFileLoader;

class CsvFileLoaderTest extends TestCase
{
use ExpectDeprecationTrait;

public function testLoad()
{
$loader = new CsvFileLoader();
Expand Down Expand Up @@ -54,4 +57,15 @@ public function testLoadNonLocalResource()

(new CsvFileLoader())->load('http://example.com/resources.csv', 'en', 'domain1');
}

/**
* @group legacy
*/
public function testEscapeCharInCsvControlIsDeprecated()
{
$loader = new CsvFileLoader();

$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.');
$loader->setCsvControl(';', '"', '\\');
}
}
3 changes: 2 additions & 1 deletion src/Symfony/Component/Translation/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"require": {
"php": ">=8.2",
"symfony/polyfill-mbstring": "~1.0",
"symfony/translation-contracts": "^2.5|^3.0"
"symfony/translation-contracts": "^2.5|^3.0",
"symfony/deprecation-contracts": "^2.5|^3"
},
"require-dev": {
"nikic/php-parser": "^4.18|^5.0",
Expand Down
Loading