This is a follow up to #1846000: Add serializer support for JSON and AJAX.
That issue originally had support using Symfony's XmlEncoder class BUT as this implements NormalizationAwareInterface, Serializer does not normalize the data, the class does. Because of this it's not feasible for us to use this directly for entities.
Quoting from Lin in that issue, as a suggested path forward:
I took a closer look at the XMLEncoder. It turns out NormalizationAwareInterface works differently than I assumed from the name. It actually skips the normalizer and handles all normalization internally. If we want to use any of the functions from the TypedData API, we shouldn't register XmlEncoder as the encoder or inherit from it.
I believe we could use composition to get the desired functionality. We would implement a custom encoder (which would not be NormalizationAware). The data would go through a normalizer to be turned into the proper array structure. Then it would be passed into our custom encoder, which would instantiate an instance of XmlEncoder and shunt all the work off to that.
Comment | File | Size | Author |
---|---|---|---|
#33 | 1854874-33.patch | 6.04 KB | damiankloip |
#33 | interdiff.txt | 1.36 KB | damiankloip |
#26 | 1854874-26.patch | 6.15 KB | alexpott |
#26 | 22-26-interdiff.txt | 3.27 KB | alexpott |
#22 | 1854874-22.patch | 5.73 KB | damiankloip |
Comments
Comment #1
damiankloip CreditAttribution: damiankloip commentedHere is an initial patch for this. I think the idea is right and this would work except adding the serializer as an argument in the container doesn't work atm (it might, I'm just not sure how to get it to). There is a circular dep issue as there are various passes to add normalizers/encoders to the serializer too.
Comment #3
damiankloip CreditAttribution: damiankloip commentedI think this might be better.
Comment #4
damiankloip CreditAttribution: damiankloip commentedDon't need the use statement for SerializerInterface
Comment #5
damiankloip CreditAttribution: damiankloip commentedExample XML string, as returned by the test:
Comment #6
damiankloip CreditAttribution: damiankloip commentedJust updated the docs a little.
Comment #8
damiankloip CreditAttribution: damiankloip commented#6: 1854874-4.patch queued for re-testing.
Comment #10
damiankloip CreditAttribution: damiankloip commentedCome on!
Comment #11
damiankloip CreditAttribution: damiankloip commented#6: 1854874-4.patch queued for re-testing.
Comment #12
dawehnerGood work!
Is it an array or a string :)
Maybe we could inject the base xml encoder in there? Not sure though whether this makes sense.
What about adding a test which take sure that our workaround actually works? You just compare the serialized output,
though we want to be able to use another normalizer.
Comment #13
damiankloip CreditAttribution: damiankloip commentedOk, I changed the $format to be an array, this is then consistent with all our other encoders. Which I think makes sense, even though there is only one format.
Injecting this sounds like a good idea, but would we ever need this? We could change the name to EncoderWrapper or something? Then pass in the XmlEncoder as the base encoder?
I'm not sure what else to test, because this is not about the normalizers. The serlizer deals with that.
Comment #14
dawehnerWhat about casting the value to an array then?
Comment #15
damiankloip CreditAttribution: damiankloip commentedHow about we test serializing the normalized array as well as the entity like this?
Comment #16
dawehnerThis looks perfect as it tests both the serialization and the normalization.!
Comment #17
webchickDamien said it'd be good for Lin to look at this first, so assigning to her.
Comment #18
Anonymous (not verified) CreditAttribution: Anonymous commentedRight now, the tests just check that the XML goes through the correct normalizer and encoder. Instead, it should check whether the expected XML is generated. The normalizer might not generate the array structure required to get the expected XML.
Comment #19
Anonymous (not verified) CreditAttribution: Anonymous commentedComment #20
damiankloip CreditAttribution: damiankloip commentedWe talked about this on IRC briefly; How about this?
Comment #21
Anonymous (not verified) CreditAttribution: Anonymous commentedThis seems a little confusing to me. We create an expected value and then test that it is the expected value. I think it would make more sense to simply use the string as the expected value.
Comment #22
damiankloip CreditAttribution: damiankloip commentedOk, let's get rid of that and so our string is the expected.
Comment #23
Anonymous (not verified) CreditAttribution: Anonymous commentedGreat, I think that makes it clearer that it's doing what we want it to do. As far as I'm concerned, this is back to RTBC.
Comment #24
catchLooks good.
I really wonder about registering individual services for this in core bundle but it's only a couple on there at the moment for this, so won't complain too much atm. Committed/pushed to 8.x.
Comment #25
webchickFor whatever reason, this broke testbot with the errors:
Rolled back 4aaa72526 for now so we can fix it up.
Comment #26
alexpottThe regressions occurred because #1833334: EntityNG: integrate a dynamic property data table handling resulted in a new order of properties in the entity_test_mulrev entity and therefore the resulting xml.
The patch attached makes less assumptions about the order by using the normalised array to sort the xml. Basically we're making up for the fact that there is not PHP equivalent for
json_encode()
for xml. I've also removed some of the assumptions about the entity values to make ir a little but easier to change the test.Comment #27
alexpottLet's test :)
Comment #28
Anonymous (not verified) CreditAttribution: Anonymous commentedI'll wait for the test to run, but the code involved is getting too complicated for a test, IMHO, particularly the multiple array manipulations.
Comment #29
damiankloip CreditAttribution: damiankloip commentedOh dear... :( Good catch Alex. I guess this shows that it was a bit fragile to have the whole string in the test? And these changes DO make it easier to modify down the line. Maybe we can make it easier:
I can see how it is quite confusing, but I quite like this. If we want something more readable, I guess we can just use a foreach here and iterate over the array_keys OR we could just use array_merge (and drop the other two array methods) really, as the normalized values will get overwritten by the expected array values anyway, so we don't need an array of empty values.
I think just implode('', $expected) would be fine here? array_reduce seems OTT here when it's just concatenating strings.
the assertion message haz gone :)
Alex I will let you action this, if you don't have time, let me know and I will re roll.
Comment #30
alexpottGo ahead Damian... Dunno why but array_reduce was on my mind :) doh! Of course implode should be used. And reducing to just a merge makes sense too... Nice one.
I've removed the assertion messages since the default message actually makes debugging easier since it gives us the full values we're actually comparing.
Comment #31
Anonymous (not verified) CreditAttribution: Anonymous commentedHow about we use the base encoder to deserialize and then check that against the normalized array?
Comment #32
damiankloip CreditAttribution: damiankloip commentedHmm, When the Symfony XmlEncoder decodes the xml it won't match the the original normalized data array, as it seems to remove a level of empty arrays (I think). So we could check the keys, but that's not ideal?
Comment #33
damiankloip CreditAttribution: damiankloip commentedOk, here is a new version of the patch from #26, but with some parts simplified. I'm not sure the de-serialization method will work, so for now, this is the way to go I think.
Comment #34
Anonymous (not verified) CreditAttribution: Anonymous commentedWhich values does it remove? Just the ones that are empty to start with? In that case, we could prepare a normalized array to test against that also removes those values.
Comment #35
damiankloip CreditAttribution: damiankloip commentedFor example:
would become...
Comment #37
damiankloip CreditAttribution: damiankloip commented#33: 1854874-33.patch queued for re-testing.
Comment #39
alexpottDrupal\user\Tests\UserAutocompleteTest failed :(
Comment #40
alexpottRetesting
Comment #41
alexpott#33: 1854874-33.patch queued for re-testing.
Comment #43
dawehner#33: 1854874-33.patch queued for re-testing.
Comment #44
Anonymous (not verified) CreditAttribution: Anonymous commentedThe new version of the test looks simple enough to me, RTBC.
Comment #45
Anonymous (not verified) CreditAttribution: Anonymous commentedIf #1894508: Update symfony/serializer gets in before this, this patch will need to be rerolled.
Comment #46
webchickOk, re-committed and pushed to 8.x, since that issue needs a re-roll anyway.