-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Serializer] Change visibility of Serializer::getNormalizer
and ::getDenormalizer
from private to protected
#52084
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
Hey! Thanks for your PR. You are targeting branch "6.4" but it seems your PR description refers to branch " Cheers! Carsonbot |
0886863
to
cedfa9c
Compare
Let's compromise and make these |
Test failures look unrelated? |
You may be interested in existing API Platform packages allowing to generate JSON Schema and adding support for extra normalization formats to the serializer such as JSON:API, JSON-LD and HAL: https://packagist.org/packages/api-platform/ Maybe can we collaborate on this topic? (We managed to do that without changing the visibility). |
HI @dunglas, thanks so much for your comment and offer to explore this in a broader context. I took a fresh look at API Platform and really like what the project does to solve some really common use cases. I think the Drupal implementation is different enough, though, that I'm not able to follow the pattern you have in I'm sure the api-platform implementation is more complex than just "give me schema for X class's public properties" but in Drupal it's more like "give me the schema for the various normalizers that will be called for its fields, that can't be statically analyzed purely from the class structure." Or perhaps more succinctly, api-platform's schema generation is invoked in a similar way to what we need for Drupal, however when it gets to foreach ($this->propertyNameCollectionFactory->create($inputOrOutputClass, $options) as $propertyName) {
// Uses reflection
$propertyMetadata = $this->propertyMetadataFactory->create($inputOrOutputClass, $propertyName, $options);
...
$this->buildPropertySchema($schema, $definitionName, $normalizedPropertyName, $propertyMetadata, $serializerContext, $format);
...
} we have to do something like (pseudocode) foreach ($entityFieldManager->getFieldsForEntity($entity) as $field) {
// Can't use reflection here.
$schema = $serializer->normalizer->getNormalizer($field->dataClass)->getSchema();
} It would be amazing to be able to re-use some existing code from elsewhere in the PHP ecosystem, however Drupal's ORM (field, database and entity APIs) are home grown so we can't for instance borrow from Doctrine. So in the Drupal pseudocode above, the catch is being able to do |
In any case, this is too late to land this in 6.4 or 7.0 (the feature freeze was 2 weeks ago, so we are only merging PRs that were already in progress at that time and for which we decided to include their review in the initial part of the feature freeze period). |
Side note: wouldn't the suggested Drupal architecture require every normalizer to implement the Drupal interface, forcing to re-implement all core normalizers of Symfony as well ? |
Serializer::getNormalizer
and ::getDenormalizer
Serializer::getNormalizer
and ::getDenormalizer
from private to protected
Thanks @stof for your help and input. Good to know about the schedule. This isn't likely to land in Drupal core for a few months at least - still lots to hash out - so while Drupal 10 is currently on Symfony 6 I don't think it's a huge lift if this component might be required at 7.1.
I'm curious about Kévin's take on my feedback above, however I am pretty confident that api-platform's approach won't work here. To be clear though, I've updated this from my initial thought that it needed to be
Most of Drupal's normalizers are custom, honestly. We have a "Typed Data" API which provides value objects for field properties, and those are (IIRC) 100% covered by entirely custom normalizers. I don't even think we're using any of the core Symfony normalizers at all. But if we were/someone is, the calling code definitely has to check that the retrieved normalizer implements our new |
I'm not convinced yet that exposing the normalizer resolution is the best solution to your problem. Your normalizers could for instance be wrapped (see Can we explore possible alternatives? For instance, your normalizers could react to the Either way, consider taking a look at the extensions API Platform provides for the serializer. This very much sounds like the kind of issue that they've solved already. |
Thanks, @derrabus. It sounds like consensus around changing the visibility on these is not going to materialize, so I appreciate the suggestion of using an alternative I am still struggling to find a real analog to the challenge we're facing in Drupal to API Platform's structure. API Platform is great but as I tried to outline above it seems like our data models are sufficiently different that I haven't yet found a pattern that would translate. You mention extensions to the serializer but I haven't yet found something that fits that description from my analysis of the code. Would you be so kind as to point me to an example that might apply here? |
Hi @bradjones1 you wrote foreach ($entityFieldManager->getFieldsForEntity($entity) as $field) {
// Can't use reflection here.
$schema = $serializer->normalizer->getNormalizer($field->dataClass)->getSchema();
} As you saw in API Platform, we're using Metadata Factories to build our schemas. It's definitely possible to create metadata based on your field manager no? We're not using reflection in most of these. Then you would just rely on the SchemaFactory to create schemas. Could you provide more details about this (but probably through another channel like the Symfony slack, or by mail)? Thanks. |
Hi @soyuka, yes, I'm already refactoring based on the feedback here and the overwhelming consensus that this change won't be accepted. I appreciate everyone's help. Likely will be pursuing an approach where the resolved normalizer will get passed a |
6.4
This changes the visibility of
Serializer::getNormalizer
and::getDenormalizer
topublicprotected. Changing to public was proposed years ago in #24206 and subsequently closed, however the initial reasons for doing so were different and eventually resulted in performance improvements, instead - see #27049 and #27105.That last change, #27105 ("Add
->hasCacheableSupportsMethod()
to CacheableSupportsMethodInterface") actually paved the way for the functionality that I am working on which would depend on these methods beingpublicmore accessible to downstream code.Over at Drupal, we are working on improving our out-of-the-box schema generation capabilities. This has resulted in a new
SchematicNormalizerInterface
which can be implemented by normalizers to express a JSON Schema for the resulting normalization. The method signature for the schema generation is identical to::normalize()
. (We plan to expand this concept to denormalization in the future, e.g. for different specs based on HTTP verb.)Currently,
NormalizerInterface
only allows for normalization, but doesn't provide any visibility into what normalizer is used. We need to be able to take a supported/representative object and ask the normalizer what the resulting schema will be. That's only possible if we can have some visibility into the normalizer to be used.Alternatively, it would be really amazing to perhaps add
SchematicNormalizerInterface
to Symfony, however I couldn't find anything in the issue queue demonstrating any existing demand for this. It would also add a bit of technical debt to the Serializer component that I'm not sure belongs in Symfony. If we did add it here, then we could instead add methods like::getNormalizationSchema()
to the serializer instead of changing the visibility.As it stands, though, here is a PR to do the minimum change required to support our innovation downstream.
@nicolas-grekas closed the original PR for changing visibility citing a desire to generally reduce the public surface area (understandably) but mostly because the underlying performance reasons for doing so were to be handled in a different issue. I haven't seen anything in the prior issues to indicate that this change is bad for any other reasons. I do understand that this might result in some shenanigans by people directly retrieving the normalizer, however I can't really think of a situation in which that's like, a major problem either.