Uh oh!
There was an error while loading. Please reload this page.
Do not try do retrieve object in ItemNormalizer $context['resource_class'] is not defined - #2326
Conversation
teohhanhui
commented
Nov 13, 2018
I'm not sure I understand the problem here. The |
teohhanhui
commented
Nov 13, 2018
It's even explicitly set here: core/src/Serializer/AbstractItemNormalizer.php Lines 125 to 127 in 516c9c7 |
lyrixx
commented
Nov 13, 2018
I guess you can simply try to decode some data with an but basically this condition evaluate to core/src/Serializer/ItemNormalizer.php Line 35 in 516c9c7 so it jumps in updateObjectToPopulate, an InvalidArgumentException exception is thrown, and finally this line breaks everything:core/src/Serializer/ItemNormalizer.php Line 52 in 516c9c7 Did I miss something? |
soyuka
commented
Nov 14, 2018
Can't you give a context? What's your use case? |
lyrixx
commented
Nov 14, 2018
@soyuka sure, it's already explained in the PR description. |
dunglas
commented
Nov 14, 2018
Normalizers must work even if no context is provided. The fix looks good to me. Would you mind adding an unit test to prevent regressions @lyrixx? |
lyrixx
commented
Nov 14, 2018
@dunglas Sure 👍 I will have to clone the projet locally then 😂 |
| { | ||
| // Avoid issues with proxies if we populated the object | ||
| if (isset($data['id']) && !isset($context[self::OBJECT_TO_POPULATE])) { | ||
| if (isset($data['id']) && !isset($context[self::OBJECT_TO_POPULATE]) && isset($context['resource_class'])) { |
There was a problem hiding this comment.
Or maybe that a better fix would be to resolve this value if not provided by calling ResourceClassResolver::getResourceClass()? Something like $context['resource_class'] ?? $this->resourceClassResolver($data) in updateObjectToPopulate()?
There was a problem hiding this comment.
I disagree. If it's not provided, it means we are outside the nominal api platform workflow.
We should not guess
There was a problem hiding this comment.
We could expect from a denormalizer that it updates relations by default, isn't it?
There was a problem hiding this comment.
You lost me. Sorry. If we set $context['resource_class'], the code will still raise an exception. Here I don't want to fetch something via the iriConverter.
dunglas
commented
Nov 14, 2018
Or you can just run |
@dunglas I made the initial patch on github ;) But don't worry, I know how to update a patch |
teohhanhui
commented
Nov 14, 2018
As I've already mentioned, the @dunglas I agree we should set |
lyrixx
commented
Nov 14, 2018
@teohhanhui Heuuuuu, I don't get it 1.crearte a new
Since API Platform modify the default serialization, you can not say:
|
lyrixx
commented
Nov 14, 2018
I have added an unit test |
Can you open a PR with a failing Behat test? Because
Need more context. Is it inside an API Platform operation? Are you doing it through a data provider? |
Sure, it's quite simple: lyrixx/test@085fe66 To make things crystal clear: we use the same object for the "public" API and for Elasticsearch storage |
teohhanhui
commented
Nov 14, 2018
If you declare a class as an API Resource, it's normal that our
In your case, you just want to use Symfony's default |
lyrixx
commented
Nov 14, 2018
@teohhanhui Yes. And other Normalizers that could live in my application. |
teohhanhui
commented
Nov 14, 2018
Please bear with us in trying to figure out the best way to go about it. So far I'm not convinced that it should be done this way. I'm inclined more towards @dunglas' suggestion of setting As for your specific use case:
|
lyrixx
commented
Nov 14, 2018
I did not choose to use it, it's build in with API Platform. |
teohhanhui
commented
Nov 14, 2018
Okay, I think I get it now. And it should be a supported use case, yes. The question is how? 🤔 |
teohhanhui
commented
Nov 14, 2018
@lyrixx A possible workaround could be to pass a custom |
lyrixx
commented
Nov 14, 2018
In my code, or in ApiPlatform ? |
teohhanhui
commented
Nov 14, 2018
In your code. 😄 |
lyrixx
commented
Nov 14, 2018
For now I used a very simple workaround $this->serializer->denormalize($logResult['_source'], Log::class, 'json', [
'object_to_populate' => $log = newLog(),
'groups' => ['elasticsearch'],
]); |
dunglas
commented
Nov 14, 2018
The patch is good enough for now, it doesn't break anything, and prevent an error that must be handled anyway. Could you just rebase against 2.3 please? (because it's a bug fix) |
teohhanhui
commented
Nov 15, 2018
@dunglas I think it's the wrong fix. As we've discussed, |
soyuka
commented
Nov 15, 2018
Maybe something like this? This patch also feels wrong to me, on the other hand it doesn't harm so I'm mitigated :p. |
dunglas
commented
Nov 18, 2018
Can we merge this until we find a better fix @api-platform/core-team? Having a hard failure is worst... |
soyuka
commented
Nov 19, 2018
If we log something because it's not normal as I suggested (#2326 (comment)) I'm 👍 to merge. |
…ass'] is not defined We store some document in Elasticsearch and we hydrate them with the Serializer. But the `ItemNormalizer` raise an error because the `resource_class` is not defined.
lyrixx
commented
Nov 20, 2018
I added a log line |
teohhanhui
left a comment
There was a problem hiding this comment.
Still think it's the wrong fix. The correct fix should be to set $context['resource_class'] when it's missing.
Ok, Let's try what you suggest to prove it does not work: If I set
Legit, so I will have to implement a At some point you said:
Well:
You also said:
So your suggestion, in order to not merge this PR, is that I need to duplicate all my model class to get one form API Platform, and another one for ES <-> PHP, and a layer that will my map my two model ? I'm sorry, but you are making things really difficult. You ask for things, I did them, then you refused it again. It's really not king. Thus, I will tell you what is the real fix could be: 1/ Update Symfony with: interface NormalizerInterface
{
- public function supportsNormalization($data, $format = null);+ public function supportsNormalization($data, $format = null, array $context = array());
}2/ update |
No. I recognize that your use case is a valid one and it's unfortunate that it's not working at the moment (but you have found workarounds). What I'm saying is that it's bad for us to have such workarounds in our code. |
It's already supported in Symfony: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Serializer/Normalizer/ContextAwareNormalizerInterface.php#L26
I don't agree with this one, it's totally valid to use API Platform to serialize in JSON-LD outside of an API context (in a worker, to send data to a Kafka, an Elastic...).
This specific problem can be fixed like this: https://api-platform.com/docs/core/data-providers/#injecting-the-serializer-in-an-code-classlanguage-textitemdataprovidercode It's a hack, and the good solution would be to use a specific Serializer instance in API Platform (not the same one than the default serializer of Symfony). It would be cleaner, but it requires some more work in SF (creating a factory to build properly configured serializer services). I'll do it when I'll have some free time. In the meantime, I in favor of merging @lyrixx patch. We should never throw an unhandled PHP error, it's not robust code... |
Agree. But this patch is not doing the right thing. Setting |
lyrixx
commented
Nov 22, 2018
About the point 3, I'm not talking about a DIC circular reference, |
joelwurtz
commented
Nov 30, 2018
@teohhanhui I don't understand in your solution how can someone deserialize something that must not use ApiPlatform, our process is very simple: Fetch Data From Elastisearch -> Deserialize it (we don't want API Platform here, it's just a stupid object) -> Do Some Work -> Serialize It (with api platform) With what your are proposing the only solution would be to use another Serializer, I would be fine with that if API Platform did not replace the one from Symfony. In our use case we have installed API Platform after doing the deserialization with Elasticsearch, and changing a lot of our code and DIC for that may be painful for some users. IMO A viable solution would be to change the way API Platform is injected :
|
dunglas
commented
Dec 20, 2018
@dunglas#2399 Functionally it works but this is a major waste of resource:
As I said many time, I really thing this patch is correct, and we should not try to goes through API Platform Normalizer at all cost. There are legitimate case where we don't want IRI stuff. Here is one example. And again, I know we could create another serializer + normalizers but it's really boring to have to put many lines of services configuration in my project, where a simple if could solve everything. On some "page" of our application, we retrieve 100 objects. So there will be 100 Exception + 100 |
dunglas
commented
Dec 20, 2018
Let's merge |
dunglas
commented
Dec 20, 2018
Thanks @lyrixx |
lyrixx
commented
Dec 20, 2018
Thanks you |
We store some document in Elasticsearch and we hydrate them with the Serializer.
But the
ItemNormalizerraise an error because theresource_classis not defined.