Skip to content

Commit

Permalink
Merge branch '3.4' into 4.3
Browse files Browse the repository at this point in the history
* 3.4:
  Sync Twig templateExists behaviors
  Fix the :only-of-type pseudo class selector
  [Serializer] Add CsvEncoder tests for PHP 7.4
  Copy phpunit.xsd to a predictable path
  [Security/Http] fix parsing X509 emailAddress
  [Serializer] fix denormalization of string-arrays with only one element #33731
  [Cache] fix known tag versions ttl check
  • Loading branch information
nicolas-grekas committed Oct 2, 2019
2 parents 2335353 + 14e29c5 commit 1d4242f
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 22 deletions.
6 changes: 5 additions & 1 deletion Encoder/CsvEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,12 @@ class CsvEncoder implements EncoderInterface, DecoderInterface
/**
* @param array $defaultContext
*/
public function __construct($defaultContext = [], string $enclosure = '"', string $escapeChar = '\\', string $keySeparator = '.', bool $escapeFormulas = false)
public function __construct($defaultContext = [], string $enclosure = '"', string $escapeChar = '', string $keySeparator = '.', bool $escapeFormulas = false)
{
if ('' === $escapeChar && \PHP_VERSION_ID < 70400) {
$escapeChar = '\\';
}

if (!\is_array($defaultContext)) {
@trigger_error('Passing configuration options directly to the constructor is deprecated since Symfony 4.2, use the default context instead.', E_USER_DEPRECATED);

Expand Down
16 changes: 9 additions & 7 deletions Normalizer/AbstractObjectNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -397,16 +397,18 @@ private function validateAndDenormalize(string $currentClass, string $attribute,
return null;
}

if ($type->isCollection() && null !== ($collectionValueType = $type->getCollectionValueType()) && Type::BUILTIN_TYPE_OBJECT === $collectionValueType->getBuiltinType()) {
$collectionValueType = $type->isCollection() ? $type->getCollectionValueType() : null;

// Fix a collection that contains the only one element
// This is special to xml format only
if ('xml' === $format && null !== $collectionValueType && (!\is_array($data) || !\is_int(key($data)))) {
$data = [$data];
}

if (null !== $collectionValueType && Type::BUILTIN_TYPE_OBJECT === $collectionValueType->getBuiltinType()) {
$builtinType = Type::BUILTIN_TYPE_OBJECT;
$class = $collectionValueType->getClassName().'[]';

// Fix a collection that contains the only one element
// This is special to xml format only
if ('xml' === $format && !\is_int(key($data))) {
$data = [$data];
}

if (null !== $collectionKeyType = $type->getCollectionKeyType()) {
$context['key_type'] = $collectionKeyType;
}
Expand Down
44 changes: 40 additions & 4 deletions Tests/Encoder/CsvEncoderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,51 @@ public function testTrueFalseValues()
'int' => 2,
'false' => false,
'true' => true,
'int_one' => 1,
'string_one' => '1',
];

// Check that true and false are appropriately handled
$this->assertEquals(<<<'CSV'
string,int,false,true
foo,2,0,1
$this->assertSame($csv = <<<'CSV'
string,int,false,true,int_one,string_one
foo,2,0,1,1,1

CSV
, $this->encoder->encode($data, 'csv'));

$this->assertSame([
'string' => 'foo',
'int' => '2',
'false' => '0',
'true' => '1',
'int_one' => '1',
'string_one' => '1',
], $this->encoder->decode($csv, 'csv'));
}

/**
* @requires PHP 7.4
*/
public function testDoubleQuotesAndSlashes()
{
$this->assertSame($csv = <<<'CSV'
0,1,2,3,4,5
,"""","foo""","\""",\,foo\

CSV
, $this->encoder->encode($data, 'csv'));
, $this->encoder->encode($data = ['', '"', 'foo"', '\\"', '\\', 'foo\\'], 'csv'));

$this->assertSame($data, $this->encoder->decode($csv, 'csv'));
}

/**
* @requires PHP 7.4
*/
public function testSingleSlash()
{
$this->assertSame($csv = "0\n\\\n", $this->encoder->encode($data = ['\\'], 'csv'));
$this->assertSame($data, $this->encoder->decode($csv, 'csv'));
$this->assertSame($data, $this->encoder->decode(trim($csv), 'csv'));
}

public function testSupportEncoding()
Expand Down
64 changes: 54 additions & 10 deletions Tests/Normalizer/AbstractObjectNormalizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,54 @@ private function getDenormalizerForDummyCollection()
$extractor = $this->getMockBuilder(PhpDocExtractor::class)->getMock();
$extractor->method('getTypes')
->will($this->onConsecutiveCalls(
[
new Type(
'array',
false,
null,
true,
new Type('int'),
new Type('object', false, DummyChild::class)
),
],
[new Type('array', false, null, true, new Type('int'), new Type('object', false, DummyChild::class))],
null
));

$denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor);
$arrayDenormalizer = new ArrayDenormalizerDummy();
$serializer = new SerializerCollectionDummy([$arrayDenormalizer, $denormalizer]);
$arrayDenormalizer->setSerializer($serializer);
$denormalizer->setSerializer($serializer);

return $denormalizer;
}

public function testDenormalizeStringCollectionDecodedFromXmlWithOneChild()
{
$denormalizer = $this->getDenormalizerForStringCollection();

// if an xml-node can have children which should be deserialized as string[]
// and only one child exists
$stringCollection = $denormalizer->denormalize(['children' => 'foo'], StringCollection::class, 'xml');

$this->assertInstanceOf(StringCollection::class, $stringCollection);
$this->assertIsArray($stringCollection->children);
$this->assertCount(1, $stringCollection->children);
$this->assertEquals('foo', $stringCollection->children[0]);
}

public function testDenormalizeStringCollectionDecodedFromXmlWithTwoChildren()
{
$denormalizer = $this->getDenormalizerForStringCollection();

// if an xml-node can have children which should be deserialized as string[]
// and only one child exists
$stringCollection = $denormalizer->denormalize(['children' => ['foo', 'bar']], StringCollection::class, 'xml');

$this->assertInstanceOf(StringCollection::class, $stringCollection);
$this->assertIsArray($stringCollection->children);
$this->assertCount(2, $stringCollection->children);
$this->assertEquals('foo', $stringCollection->children[0]);
$this->assertEquals('bar', $stringCollection->children[1]);
}

private function getDenormalizerForStringCollection()
{
$extractor = $this->getMockBuilder(PhpDocExtractor::class)->getMock();
$extractor->method('getTypes')
->will($this->onConsecutiveCalls(
[new Type('array', false, null, true, new Type('int'), new Type('string'))],
null
));

Expand Down Expand Up @@ -258,6 +296,12 @@ protected function setAttributeValue($object, $attribute, $value, $format = null
}
}

class StringCollection
{
/** @var string[] */
public $children;
}

class DummyCollection
{
/** @var DummyChild[] */
Expand Down

0 comments on commit 1d4242f

Please sign in to comment.