-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Allow serializer context configuration #28927
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
src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
Outdated
Show resolved
Hide resolved
32c07e3
to
2d373bd
Compare
Updated to reflect the changes from #28709 |
2d373bd
to
fc79c72
Compare
also see #19456 btw :) |
src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
Outdated
Show resolved
Hide resolved
@dunglas updated, lmk if this isn't what you had in mind. |
606f504
to
dbe12fe
Compare
src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/DependencyInjection/SerializerPass.php
Outdated
Show resolved
Hide resolved
Ping! This is a pretty important feature, right? Because in 4.2, for example, there is no way to set up a circular reference handler globally, except by using the deprecated @soyuka it looks like a few changes were requested - could you make this? Cheers! |
dbe12fe
to
f872a36
Compare
I rebased only for now.
@dunglas any opinion about this? I still have issues with the |
60c9bc8
to
1036834
Compare
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.
Almost done!
@@ -236,6 +236,7 @@ | |||
<xsd:complexType name="serializer"> | |||
<xsd:choice minOccurs="0" maxOccurs="unbounded"> | |||
<xsd:element name="mapping" type="file_mapping" /> | |||
<xsd:element name="default_context" type="metadata" minOccurs="0" maxOccurs="1" /> |
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.
default-context
, for consistency
$this->addDefaultContextParameterBinding($encoders, $container); | ||
} | ||
|
||
private function addDefaultContextParameterBinding($services, $container) |
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.
private function addDefaultContextParameterBinding($services, $container) | |
private function addDefaultContextParameter($services, $container) |
Binding is confusing, let's remove it
fa568f1
to
8ae1e25
Compare
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.
LGTM
->useAttributeAsKey('name') | ||
->defaultValue([]) | ||
->prototype('variable')->end() | ||
->end() |
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.
This doesn't allow for things like the circular_reference_handler
. I mean, you can set it, but there's no way to set this to a service, for example - none of the handler stuff will work. We need to check for the handler options explicitly in FrameworkExtension
and convert them to References. In the docs, I guess we'll need to document these handlers as services that should use the __invoke()
method.
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.
Maybe could be also do something more generic: check if a service corresponding to a given string exists, if it's the case, convert it to a reference. WDYT?
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.
This is a really important one - thanks for the work! But I don't think it's quite done yet - handlers aren't possible, so it's still not really possible to handle the circular reference in the serializer in the framework.
$definition->setArgument('$defaultContext', '%serializer.default_context%'); | ||
} | ||
} | ||
} |
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.
I don't love this level of magic. I'd prefer:
A) Just documenting the parameter and allowing people to wire it up manually
B) Creating a DefaultContext
service that holds the config and passing that around. For the existing classes that are expecting an array, that's fine - we can pass the array to those classes, but make this service available.
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.
I prefer B) because it will work with projects providing extra context options such as API Platform, and doing it manually is tedious.
What we could do:
- Introduce a new
ContextInterface
(that can be extended) - Allow all parameters that currently accept an array to also accept this new interface, and deprecacate passing an array
- Use it both for the "default context" and the context you can pass to methods (it means that this class MUST be safely serializable)
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.
Other better option: create a context builder that returns an array. Then it will be consistent with the builder introduced in HttpClient.
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.
Discussion about this in #30888
@soyuka Can you take into account the last comments from @weaverryan? |
8ae1e25
to
ee29ffa
Compare
if(!$defaultContext instanceof ContextInterface && is_array($defaultContext)){ | ||
$defaultContext = new DefaultContext($defaultContext); | ||
@trigger_error("you must pass an object of type ". ContextInterface::class .", the passage of an array is depreciated", E_USER_DEPRECATED); | ||
} |
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.
@weaverryan @dunglas is this what you had in mind? We (me and @flug) are working actively on this, we changed only one normalizer for now and wanted to check the implementation with you before going forward.
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 it's not. As I've described in the other comments, I think we should keep an array or an iterable here. Using an interface will make the component hard to extend, and it will be a pain to migrate the current API Platform context options to this new mechanism. All other Symfony components use plain arrays for this kind of things, for consistency, and because it's easier to extend, I think we should keep the array but just provide an helper function to build this context instead.
@@ -32,8 +34,12 @@ class ConstraintViolationListNormalizer implements NormalizerInterface, Cacheabl | |||
private $defaultContext; | |||
private $nameConverter; | |||
|
|||
public function __construct($defaultContext = [], NameConverterInterface $nameConverter = null) | |||
public function __construct(/** ContextInterface */ $defaultContext = null, NameConverterInterface $nameConverter = null) |
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.
is null
a good idea ? It does not seems to be allowed before.
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.
It should be an iterable
defaulting to an empty array IMHO
ee29ffa
to
97e8829
Compare
->useAttributeAsKey('name') | ||
->defaultValue([]) | ||
->prototype('variable')->end() | ||
->end() |
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.
Maybe could be also do something more generic: check if a service corresponding to a given string exists, if it's the case, convert it to a reference. WDYT?
<framework:serializer enabled="true" enable-annotations="true" name-converter="serializer.name_converter.camel_case_to_snake_case" circular-reference-handler="my.circular.reference.handler" max-depth-handler="my.max.depth.handler" /> | ||
<framework:serializer enabled="true" enable-annotations="true" name-converter="serializer.name_converter.camel_case_to_snake_case" circular-reference-handler="my.circular.reference.handler" max-depth-handler="my.max.depth.handler"> | ||
<framework:default-context> | ||
<framework:enable_max_depth>true</framework:enable_max_depth> |
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.
Shouldn't this key allow any "array-like" structure? Shouldn't the XSD be updated accordingly?
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
interface ContextInterface |
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.
Do we need this interface? Cannot we use the builder pattern as done in HttpClient (the HttpOptions
helper) instead? This new class should contain a method for every available options for autocompletion, as in HttpClient.
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
class DefaultContext implements ContextInterface |
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.
final
, but IMHO we should get read of this class and use an array
or an iterable
instead.
@@ -32,8 +34,12 @@ class ConstraintViolationListNormalizer implements NormalizerInterface, Cacheabl | |||
private $defaultContext; | |||
private $nameConverter; | |||
|
|||
public function __construct($defaultContext = [], NameConverterInterface $nameConverter = null) | |||
public function __construct(/** ContextInterface */ $defaultContext = null, NameConverterInterface $nameConverter = null) |
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.
It should be an iterable
defaulting to an empty array IMHO
if(!$defaultContext instanceof ContextInterface && is_array($defaultContext)){ | ||
$defaultContext = new DefaultContext($defaultContext); | ||
@trigger_error("you must pass an object of type ". ContextInterface::class .", the passage of an array is depreciated", E_USER_DEPRECATED); | ||
} |
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 it's not. As I've described in the other comments, I think we should keep an array or an iterable here. Using an interface will make the component hard to extend, and it will be a pain to migrate the current API Platform context options to this new mechanism. All other Symfony components use plain arrays for this kind of things, for consistency, and because it's easier to extend, I think we should keep the array but just provide an helper function to build this context instead.
Okay I've give up the Context class, I could add some builder like the
We'd need to choose which of the options we would declare in this |
97e8829
to
b0a7d0e
Compare
We've just moved away from |
… context configuration (soyuka) This PR was merged into the 5.4 branch. Discussion ---------- [FrameworkBundle][Serializer] Allow serializer default context configuration | Q | A | ------------- | --- | Branch? | 5.x | Bug fix? | no | New feature? | yes <!-- don't forget to update src/**/CHANGELOG.md files --> | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | n/a | License | MIT | Doc PR | todo if we go with it <!-- required for new features --> This allow to configure the `context` for normalizer's on a high level: ```yaml serializer: default_context: enable_max_depth: true ``` This feature was asked in api-platform/core#1764 (comment) and I thought it could be in symfony instead. The messenger component has the same configuration. This re-opens #28927 (for discussion). I'm still unsure about the discussion in #28927 (comment) and what solution I should implement. Please let me know if you come to an agreement. Commits ------- 43d1ca5 Allow serializer default context configuration
… context configuration (soyuka) This PR was merged into the 5.4 branch. Discussion ---------- [FrameworkBundle][Serializer] Allow serializer default context configuration | Q | A | ------------- | --- | Branch? | 5.x | Bug fix? | no | New feature? | yes <!-- don't forget to update src/**/CHANGELOG.md files --> | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | n/a | License | MIT | Doc PR | todo if we go with it <!-- required for new features --> This allow to configure the `context` for normalizer's on a high level: ```yaml serializer: default_context: enable_max_depth: true ``` This feature was asked in api-platform/core#1764 (comment) and I thought it could be in symfony instead. The messenger component has the same configuration. This re-opens symfony/symfony#28927 (for discussion). I'm still unsure about the discussion in symfony/symfony#28927 (comment) and what solution I should implement. Please let me know if you come to an agreement. Commits ------- 43d1ca5f86 Allow serializer default context configuration
… context configuration (soyuka) This PR was merged into the 5.4 branch. Discussion ---------- [FrameworkBundle][Serializer] Allow serializer default context configuration | Q | A | ------------- | --- | Branch? | 5.x | Bug fix? | no | New feature? | yes <!-- don't forget to update src/**/CHANGELOG.md files --> | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | n/a | License | MIT | Doc PR | todo if we go with it <!-- required for new features --> This allow to configure the `context` for normalizer's on a high level: ```yaml serializer: default_context: enable_max_depth: true ``` This feature was asked in api-platform/core#1764 (comment) and I thought it could be in symfony instead. The messenger component has the same configuration. This re-opens symfony/symfony#28927 (for discussion). I'm still unsure about the discussion in symfony/symfony#28927 (comment) and what solution I should implement. Please let me know if you come to an agreement. Commits ------- 43d1ca5f86 Allow serializer default context configuration
This allow to configure the
context
for normalizer's on a high level:This feature was asked in api-platform/core#1764 (comment) and I thought it could be in symfony instead. The messenger component has the same configuration.