Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Serializer] add method for preparing constructor argument #28263

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

Conversation

komik966
Copy link

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets n/a
License MIT
Doc PR todo

When we denormalize objects which classes have constructor, it becomes useful to add custom logic for creating constructor arguments from decoded data. E. g. constructor parameter is type hinted as class, but decoded data (coming from rest api) is IRI string.

Current implemetation of Symfony\Component\Serializer\Normalizer\AbstractNormalizer::instantiateObject forces us to think about other aspects of instantiating object (e.g. discriminators, context) when overriding it.

Related discussions: api-platform/core#1749, api-platform/core#2178

Copy link
Contributor

@sroze sroze left a comment

Choose a reason for hiding this comment

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

I'm not fond of inheritance-based extension points but that's mostly how it is done in the Serializer component so far so 👍 for me.

$parameterData = $data[$key];
if (null === $parameterData && $constructorParameter->allowsNull()) {
// Don't run set for a parameter passed to the constructor
unset($data[$key]);
Copy link
Contributor

Choose a reason for hiding this comment

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

The &$data argument makes little sense to me (especially given the name of the method). Can you move unset($data[$key]) in the caller instead and directly pass $parameterData?

Copy link
Author

Choose a reason for hiding this comment

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

Good point. Fixed. Maybe w can do similar with $key parameter? It's only used in exception message. Unless it's important to show normalized constructor parameter name, we can use $constructorParameter->name.

@komik966
Copy link
Author

komik966 commented Aug 26, 2018

@sroze For me composition also would be better. I was thinking about introducing new InstantiatorInterface, but this may generate BC break / deprecations.

@komik966 komik966 force-pushed the serializer-extract-create-constructor-argument branch from 366dd26 to bc24d62 Compare August 26, 2018 14:18
@dunglas
Copy link
Member

dunglas commented Aug 26, 2018

👍 to move this in a dedicated class. It should be doable without BC break (initialize the new class in the constructor if not provided).

@komik966
Copy link
Author

komik966 commented Aug 26, 2018

When we introduce InstantiatorInterface::instantiateObject then we should deprecate \Symfony\Component\Serializer\Normalizer\AbstractNormalizer::instantiateObject and deprecate dependency to NameConverterInterface in \Symfony\Component\Serializer\Normalizer\AbstractNormalizer::__construct - name converter will be injected in implementation of InstantiatorInterface

Second option is to create ConstructorArgumentFactoryInterface, then we will move only algorithm of creating constructor arguments (not instantiating entire object). In this case we have no deprecations, but I'm not sure if it isn't too small functionality for separate class.

What are your thoughts?

@komik966 komik966 force-pushed the serializer-extract-create-constructor-argument branch from bc24d62 to 6d471cf Compare August 28, 2018 04:50
@dunglas
Copy link
Member

dunglas commented Aug 28, 2018

I'm for option 1, it will be more flexible, and I want to break the serializer in smaller classes since a long time.

@komik966 komik966 force-pushed the serializer-extract-create-constructor-argument branch from 6d471cf to d8905e2 Compare August 29, 2018 06:53
@komik966
Copy link
Author

Ok, I'll prepare changes with this approach.

@komik966 komik966 force-pushed the serializer-extract-create-constructor-argument branch from d8905e2 to 7b77f35 Compare September 1, 2018 07:52
@komik966 komik966 force-pushed the serializer-extract-create-constructor-argument branch from 7b77f35 to 2c37a8b Compare September 23, 2018 10:03
@fabpot
Copy link
Member

fabpot commented Oct 10, 2018

@dunglas The code has changed since your last review. Can you check it again please?

@dunglas
Copy link
Member

dunglas commented Oct 10, 2018

@fbourigault would you mind to take a look, as it is related with #28775

@fbourigault
Copy link
Contributor

What about introducing some ObjectInstanciator actor to handle the whole instantiateObject stuff ?
If designed with the problem this PR is trying to solve, we could have a better extension point and continue the split of the ObjectNormalizer/AbstractObjectNormalizer/AbstractNormalizer into smaller classes.
This fit more in plans exposed by @dunglas in #19374 (comment).

@komik966
Copy link
Author

I tried something similar (komik966@d734f32) but ended with lot of deprecations.

@komik966
Copy link
Author

I noticed that this code:

protected function createConstructorArgument($parameterData, string $key, \ReflectionParameter $constructorParameter, array &$context, string $format = null)
has similar logic to:
private function validateAndDenormalize(string $currentClass, string $attribute, $data, ?string $format, array $context)

Should we treat creating arguments for constructor differently than for other methods (setters)?

* @param array $context
* @param string|null $format
*
* @return mixed value of constructor parameter - an argument
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure the docblock lines above provide enough value to be kept, I'd personally suggest to remove them.

return null;
}
try {
if (null !== $constructorParameter->getClass()) {
Copy link
Member

Choose a reason for hiding this comment

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

looks like this could be turned to

if (null === $constructorParameter->getClass()) {
    return $parameterData;
}

and allow unindenting the block currently inside the "if"?

@fabpot
Copy link
Member

fabpot commented Aug 6, 2019

What's the status here?

@dunglas
Copy link
Member

dunglas commented Jan 15, 2020

@komik966 do you think it is worth it to finish this PR? If yes, could you rebase and fix the remaining comments please?

@dunglas
Copy link
Member

dunglas commented Jan 15, 2020

Status: Needs Work

@komik966
Copy link
Author

I hasn't followed what's happening in serializer and api-platform for one year. So it's safer to abandon this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants