-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Serializer] Fix denormalization of arrays #19649
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,9 +12,12 @@ | |
namespace Symfony\Component\Serializer\Tests\Normalizer; | ||
|
||
use Doctrine\Common\Annotations\AnnotationReader; | ||
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; | ||
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; | ||
use Symfony\Component\PropertyInfo\PropertyInfoExtractor; | ||
use Symfony\Component\Serializer\Exception\UnexpectedValueException; | ||
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; | ||
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; | ||
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; | ||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; | ||
use Symfony\Component\Serializer\Serializer; | ||
|
@@ -525,13 +528,21 @@ public function testThrowUnexpectedValueException() | |
|
||
public function testDenomalizeRecursive() | ||
{ | ||
$normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor()); | ||
$serializer = new Serializer(array(new DateTimeNormalizer(), $normalizer)); | ||
$extractor = new PropertyInfoExtractor(array(), array(new PhpDocExtractor(), new ReflectionExtractor())); | ||
$normalizer = new ObjectNormalizer(null, null, null, $extractor); | ||
$serializer = new Serializer(array(new ArrayDenormalizer(), new DateTimeNormalizer(), $normalizer)); | ||
|
||
$obj = $serializer->denormalize(array( | ||
'inner' => array('foo' => 'foo', 'bar' => 'bar'), | ||
'date' => '1988/01/21', | ||
'inners' => array(array('foo' => 1), array('foo' => 2)), | ||
), ObjectOuter::class); | ||
|
||
$obj = $serializer->denormalize(array('inner' => array('foo' => 'foo', 'bar' => 'bar'), 'date' => '1988/01/21'), ObjectOuter::class); | ||
$this->assertEquals('foo', $obj->getInner()->foo); | ||
$this->assertEquals('bar', $obj->getInner()->bar); | ||
$this->assertEquals('1988-01-21', $obj->getDate()->format('Y-m-d')); | ||
$this->assertEquals(1, $obj->getInners()[0]->foo); | ||
$this->assertEquals(2, $obj->getInners()[1]->foo); | ||
} | ||
|
||
/** | ||
|
@@ -546,6 +557,19 @@ public function testRejectInvalidType() | |
$serializer->denormalize(array('date' => 'foo'), ObjectOuter::class); | ||
} | ||
|
||
/** | ||
* @expectedException UnexpectedValueException | ||
* @expectedExceptionMessage The type of the key "a" must be "int" ("string" given). | ||
*/ | ||
public function testRejectInvalidKey() | ||
{ | ||
$extractor = new PropertyInfoExtractor(array(), array(new PhpDocExtractor(), new ReflectionExtractor())); | ||
$normalizer = new ObjectNormalizer(null, null, null, $extractor); | ||
$serializer = new Serializer(array(new ArrayDenormalizer(), new DateTimeNormalizer(), $normalizer)); | ||
|
||
$serializer->denormalize(array('inners' => array('a' => array('foo' => 1))), ObjectOuter::class); | ||
} | ||
|
||
public function testExtractAttributesRespectsFormat() | ||
{ | ||
$normalizer = new FormatAndContextAwareNormalizer(); | ||
|
@@ -740,6 +764,11 @@ class ObjectOuter | |
private $inner; | ||
private $date; | ||
|
||
/** | ||
* @var ObjectInner[] | ||
*/ | ||
private $inners; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if we're missing this phpdoc, the serializer won't try to normalize There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there is no type defined (through a PHPDoc or any other way supported by registered extractors), the old behavior (don't check anything) occurs. |
||
|
||
public function getInner() | ||
{ | ||
return $this->inner; | ||
|
@@ -759,6 +788,16 @@ public function getDate() | |
{ | ||
return $this->date; | ||
} | ||
|
||
public function setInners(array $inners) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would also support the case where we have: class ObjectOuter
{
private $inners;
/**
* @param ObjectInner[] $inners
*/
public function setInners(array $inners)
{
$this->inners = $inners;
}
} which is IMO as valid as what you've done and perhaps more in line with Symfony conventions, as you would do: class ObjectOuter
{
private $dummy;
private $inners;
/**
* @param ObjectInner[] $inners
*/
public function __construct(Dummy $dummy, array $inners)
{
$this->dummy = $dummy;
$this->inners = $inners;
}
} instead of: class ObjectOuter
{
private $dummy;
/**
* @var ObjectInner[] $inners
*/
private $inners;
public function __construct(Dummy $dummy, array $inners)
{
$this->dummy = $dummy;
$this->inners = $inners;
}
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is out of scope of this PR. Support for such notations should be added in the PropertyInfo component. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fair enough |
||
{ | ||
$this->inners = $inners; | ||
} | ||
|
||
public function getInners() | ||
{ | ||
return $this->inners; | ||
} | ||
} | ||
|
||
class ObjectInner | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,9 +24,10 @@ | |
"symfony/property-access": "~2.8|~3.0", | ||
"symfony/http-foundation": "~2.8|~3.0", | ||
"symfony/cache": "~3.1", | ||
"symfony/property-info": "~2.8|~3.0", | ||
"symfony/property-info": "~3.1", | ||
"doctrine/annotations": "~1.0", | ||
"doctrine/cache": "~1.0" | ||
"doctrine/cache": "~1.0", | ||
"phpdocumentor/reflection-docblock": "~3.0" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this one? Required by property info? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because I use the Theoretically, it should also work with PropertyInfo 2.8 (it's why I've not enforced So I just required PropertyInfo |
||
}, | ||
"conflict": { | ||
"symfony/property-access": ">=3.0,<3.0.4|>=2.8,<2.8.4" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for the brackets, just a comma
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Brackets are used for the similar exception here https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php#L270
WSYT of standardizing messages with the rest of the code base in another PR?