8000 [Serializer] Argument objects by theofidry · Pull Request #19277 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Serializer] Argument objects #19277

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 14 commits into from
Jul 11, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Add tests
  • Loading branch information
theofidry committed Jul 3, 2016
commit e99a90b9e98e6abe26feea4baacb295efc688fe3
Original file line number Diff line number Diff line change
Expand Up @@ -281,12 +281,13 @@ protected function getConstructor(array &$data, $class, array &$context, \Reflec
* @param array $context
* @param \ReflectionClass $reflectionClass
* @param array|bool $allowedAttributes
* @param string|null $format
*
* @return object
*
* @throws RuntimeException
*/
protected function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes)
protected function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes, $format = null)
Copy link
Member
@dunglas dunglas Jul 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I realized that this is a BC break... It should be removed. But it's annoying because some normalizers may depend of the format (normalizers of API Platform for instance).

An alternative approach:

  • Rename this method instantiateComplexObject (with the new parameter, it can be movec before $context for consistency)
  • Add back instantiateObject with the current signature and call instantiateComplexObject inside it with format as null
  • Deprecate instantiateObject

WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do

{
if (
isset($context[static::OBJECT_TO_POPULATE]) &&
Expand Down Expand Up @@ -320,12 +321,13 @@ protected function instantiateObject(array &$data, $class, array &$context, \Ref
}
} elseif ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) {
$parameterData = $data[$key];
if (null !== $constructogrParameter->getClass()) {
if (null !== $constructorParameter->getClass()) {
Copy link
Contributor
@GuilhemN GuilhemN Jul 5, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReflectionParameter::getType() should be used when available imo and exceptions catched in case the type hinted class doesn't exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally find it easier to check check if the class is null or not in this case

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree but the type hint may be on a class not loadable. In this case, the exception thrown should be catched and the default value applied.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you elaborate? On which scenario may it happen? Not that I'm not trusting you, but if that's the case I would like to add a test for it :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case you use a type hint with a class from a third party library which is not loaded because you don't need it for example.
And the advantage of getType() is that it doesn't need to load the class, so would work anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, fair enough will change that then

$parameterData = $this->serializer->denormalize($parameterData, $constructorParameter->getClass()->getName(), null, $context);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add $format as a new optional paremeter for instantiateObject and pass it to the serializer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot this comment, it would be a BC break: Add argument with a default value No

Copy link
Contributor Author
@theofidry theofidry Jul 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dunglas I'm doing a denormalize but the normalizer is... SerializerAware, not NormalizerAware. This works because of the way the serializer is setup but it's violating the interfaces. What should we do about it? Calling deserialize() even though it will be more expensive?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also calling deserialize() will fail if you are using a serializer without any encoder, which might be the case when you are dealing with arrays and php objects, i.e. are not taking any JSON/XML input. Not likely in a regular app, but can happen in libraries.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe can you add a instanceof NormalizerInterface check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cant' we make the normalizer NormalizerAware instead and deprecate it's SerializerAware?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better. But it should be done in another PR.

}

// Don't run set for a parameter passed to the constructor
$params[] = $parameterData;
unset($data[$key]);
} elseif ($constructorParameter->isDefaultValueAvailable()) {
$params[] = $constructorParameter->getDefaultValue();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public function denormalize($data, $class, $format = null, array $context = arra
$normalizedData = $this->prepareForDenormalization($data);

$reflectionClass = new \ReflectionClass($class);
$object = $this->instantiateObject($normalizedData, $class, $context, $reflectionClass, $allowedAttributes);
$object = $this->instantiateObject($normalizedData, $class, $context, $reflectionClass, $allowedAttributes, $format);

foreach ($normalizedData as $attribute => $value) {
if ($this->nameConverter) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up B69D @@ -157,6 +157,24 @@ public function testConstructorWithObjectDenormalize()
$this->assertEquals('bar', $obj->bar);
}

public function testConstructorWithObjectTypeHintDenormalize()
{
$data = [
'id' => 10,
'inner' => [
'foo' => 'oof',
'bar' => 'rab',
],
];

$obj = $this->normalizer->denormalize($data, DummyWithConstructorObject::class);
$this->assertInstanceOf(DummyWithConstructorObject::class, $obj);
$this->assertEquals(10, $obj->getId);
$this->assertInstanceOf(ObjectInner::class, $obj->getInner());
$this->assertEquals('foo', $obj->getInner()->foo);
$this->assertEquals('bar', $obj->getInner()->bar);
}

public function testGroupsNormalize()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
Expand Down Expand Up @@ -782,3 +800,25 @@ protected function isAllowedAttribute($classOrObject, $attribute, $format = null
return false;
}
}

class DummyWithConstructorObject
{
private $id;
private $inner;

public function __construct($id, ObjectInner $inner)
{
$this->id = $id;
$this->inner = $inner;
}

public function getId()
{
return $this->id;
}

public function getInner()
{
return $this->inner;
}
}
0