Problem/Motivation
Currently, the "Rest Export" display style provided by the core rest module does not pass any contextual information about the view to the Serializing class. The consequence is that that encoding class cannot dynamically respond to any views configuration whatsoever. This arguably contradicts the intention of the EncoderInterface used by the Serialization API, as the serialize() method already allows for an option $context parameter to be passed--it simply isn't being used at present.
Proposed resolution
Pass the views options array to the serialize() method of the active Serializer.
Example Usage
I've relied on this patch to develop the CSV Serialization module. By simply defining a new Serialization class, I am easily able to provide a View of display type "Rest Export" that displays CSV data.
However, I'm unable to pass any configuration to the Serializer. E.g., I cannot use Views (or anything else for that matter) to configure the delimiter, escape characters, or enclosure characters for the CSV serialization.
In this case, I believe that the simplest way to pass user configurable options to the Serializer from Views is to 1) Use Form API to provide additional options, 2) Pass the entire view style array of options through to the Serializer. \
Remaining tasks
- Get code reviewed
- Merge!
User interface changes
NONE
API changes
NONE
Comment | File | Size | Author |
---|---|---|---|
#60 | interdiff.txt | 1.88 KB | dawehner |
#60 | 2568413-60.patch | 3.34 KB | dawehner |
#58 | interdiff.txt | 1.15 KB | Wim Leers |
#58 | 2568413-58.patch | 3.4 KB | Wim Leers |
#55 | 2568413-55.patch | 3.78 KB | grasmash |
Comments
Comment #2
grasmash CreditAttribution: grasmash at Acquia commentedVery simple one line patch attached.
Comment #3
vijaycs85Looks good. Is there anyway we can test it manually? or possible to write test?
Comment #4
dawehnerDoes $this->options contain information you actually want in there? Aren't those two different kind of options?
Comment #5
grasmash CreditAttribution: grasmash at Acquia commented@dawehner $this->options does contain information that one would want in there. Some examples:
Passing $this->options leaves things nicely flexible, because you could form_alter() the views config form and easily add any option you'd like, whose value would subsequently be passed to a custom defined Serialization class and used to dynamically encode response.
Comment #6
dawehnerWell yeah I just fear that random configuration of one might leak into the serializer and then cause something which was not intended to do so.
Comment #7
klausiI think we should not pass all the options on the top level of the $context array for the serializer. So something like
return $this->serializer->serialize($rows, $content_type, ['views_style_options' => $this->options])
For the test case I think a unit test that asserts that the context is passed to a serializer mock should suffice. Extra points if you use Prophecy for the mocking, see https://www.drupal.org/node/2554745
Comment #8
grasmash CreditAttribution: grasmash at Acquia commented@klausi Alright, I'm going to take a stab at both writing a test and using Prophecy, but it's a little murky to me at the moment.
Comment #9
grasmash CreditAttribution: grasmash at Acquia commented@klausi I think that writing this automated test is a bit more complex than expected.
The proposed testing strategy would require the following:
As noted, the issue with this strategy is that you cannot override a view's serializer, which is derived from injected dependencies. I could go down a fairly serious rabbit hole and try to create a mock view, but the issue of calling execute and render methods on this becomes problematic. On the other hand, I could introduce public getting and setter methods for setting the serializer on a view, but that circumvents dependency injection and seems like a bad idea.
So, I'm at an impasse due to lack of D8 automated testing knowledge. Any guidance would be appreciated.
Comment #10
grasmash CreditAttribution: grasmash at Acquia commentedUpdating patch so that views config is not passed to top level of array.
Comment #11
grasmash CreditAttribution: grasmash at Acquia commentedOops. Attaching patch.
Comment #13
webchickThis is apparently a contrib project blocker (for https://www.drupal.org/project/views_data_export). Tagging as such.
Comment #14
grasmash CreditAttribution: grasmash at Acquia commentedRerolling patch due to unintentional whitespace change, standby.
Comment #15
grasmash CreditAttribution: grasmash at Acquia commentedLet's try this again.
Comment #17
pwolanin CreditAttribution: pwolanin as a volunteer and at Acquia commentedFor consistency with the rest of that method, either use old-style
array()
syntax, or fix the line:Comment #18
grasmash CreditAttribution: grasmash at Acquia commentedUpdated.
Comment #19
pwolanin CreditAttribution: pwolanin as a volunteer and at Acquia commentedHere's a unit test that tries to keep the mocking to the minimum needed, and fixed the syle concern.
Not really very useful, but it's a start for future test writing around this.
Comment #21
dawehnerAh nice, so in this way it at least doesn't conflict with anything else. Thank you!
We could add @coversDefaultClass | @covers
Comment #23
pwolanin CreditAttribution: pwolanin as a volunteer and at Acquia commentedok, fixed the doc.
Comment #24
klausiCan we name the class "ViewsRestSerializerTest" or "RestViewsSerializerTest" to indicate that this is about the Views integration of REST module?
don't use the class name as literal string, use ::class instead. Also elsewhere.
can use willReturn()
Comment #25
dawehnerIt should be moved IMHO to the right
let's move the test to src/Unit/Plugin/views/style/SerializerTest.php to be more parallel to the actual source code.
Comment #26
pwolanin CreditAttribution: pwolanin as a volunteer and at Acquia commentedSince we are testing a rest module class the test should live with rest module
Comment #27
pwolanin CreditAttribution: pwolanin as a volunteer and at Acquia commentedrenamed class to \Drupal\Tests\rest\Unit\RestViewsStyleSerializerTest
fixed other concerns.
Comment #28
dawehnerWell, I disagree :)
In general this test also used the wrong class ...
Comment #29
klausiDo we have a coding standard for this that we have to nest unit tests that deep in plugin folders? Since the test is not a plugin we can avoid those annoying subdirectories.
the name "SerializerTest" in REST module is too generic I would say and makes it harder to find. I know you tried to compensate that with the nested directories, but for such a few number of unit tests that we have in REST module a longer class name makes more sense IMO. Less annoying than 3 additional levels of directories.
can we split this up over multiple lines as we did before? Makes it easier to read.
Anyway, just non-blocking nitpicks.
Comment #31
dawehnerWell, IMHO this is common pratice we apply for 95% of all our unit tests.
This is why we have namespaces ... This naming scheme also helps to quickly switch between test and code class.
Comment #32
damiankloip CreditAttribution: damiankloip commentedFirstly:
Not really. This is a totally optional parameter. I don't think anything is contradicted here. Just as you say, un used.
Do you have a more specific use case here? As having a normalizer or encoder that depends on view configuration could easily break when you are not using it from views.
If we are doing this, which I don't have a problem with, I think we should pass more context, not style options only. Style configuration is arguable one of the least helpful IMO :) If we can fix your case, and others that may potentially arise, that would be good.
Comment #33
pwolanin CreditAttribution: pwolanin as a volunteer and at Acquia commentedComment #34
grasmash CreditAttribution: grasmash at Acquia commentedComment #35
grasmash CreditAttribution: grasmash at Acquia commentedI've added an example use case to the issue summary. There are of course many other examples of possible ways that we could use the $context parameter in serialize().
Comment #36
grasmash CreditAttribution: grasmash at Acquia commentedI'm also not opposed to passing more context (beyond style options) to the serializer. But passing $this->options seems like the logical place to start. These can be easily modified through the UI or through the use of hooks.
Comment #38
pwolanin CreditAttribution: pwolanin as a volunteer and at Acquia commentedComment #40
xjmAs a contrib project blocker, this would be a good issue to consider for RC target triage.
Comment #42
xjmHm that test result is on QA which is now essentially switched off... canceling that run and reuploading the patch.
Comment #43
grasmash CreditAttribution: grasmash at Acquia commented@xjm Are we safe to consider this reviewed and tested by community at this point? The change meets the needs of the contrib module, and the tests appear to pass.
Comment #44
xjmI think #29 through #32 still need to be addressed in full.
Comment #45
grasmash CreditAttribution: grasmash at Acquia commented@xjm Thanks.
Here are comments to address the outstanding issues:
Comment #47
grasmash CreditAttribution: grasmash at Acquia commentedDon't quite understand why this is failing. "PHP Fatal error: Class 'Drupal\Tests\rest\Unit\Plugin\views\style\SerializerTest' not found in /var/www/html/core/scripts/run-tests.sh on line 709".
I'm guessing that I'm making a mistake with namespacing or test naming, but I'm directly mimicking what was previously successful.
Comment #48
grasmash CreditAttribution: grasmash at Acquia commentedPatch from #47 had a mistake. Patch from #45 appears to be correct. Anyone have thoughts on what's going on? I'm guessing that in the last 2 months some change to Drupal core's handling of namespaces or test naming conventions has affected this?
Comment #51
dawehnerYou'd need the following ...
Comment #52
grasmash CreditAttribution: grasmash at Acquia commentedComment #53
damiankloip CreditAttribution: damiankloip commentedYes. I wrote the class originally.. :)
Have you seen views? Displays, styles, rows are all interlinked.
Why not just pass the actual style plugin itself?
Comment #54
dawehnerYeah I kinda agree that it would be better to pass on the style plugin.
Comment #55
grasmash CreditAttribution: grasmash at Acquia commentedOk, I've updated the patch. I'm not familiar with mocking classes, so hopefully the modifications to the test are what we're looking for!
Comment #57
dawehnerThank you @grasmash!
Comment #58
Wim LeersCode makes sense.
PHPUnit error:
Attached reroll is only fixing whitespace nitpicks, not the failures.
Comment #60
dawehnerLet's just fix it.
Comment #61
Wim LeersI did not know about
Argument::that()
. Thanks!Looks good.
Comment #63
catchCommitted/pushed to 8.1.x and cherry-picked to 8.0.x. Thanks!
Comment #65
Wim LeersThanks to this,
csv_serialization
is now unblocked, yay :)