When trying to add a "dynamic field" where the source is a field defined by hook_field_extra_fields(), DS goes into infinite recursion when viewing the content.
Here's STR:
1) Install D7 + ds_ui + quiz (or any other module that defines fields with hook_field_extra_fields)
2) Enable DS on the content type (Quiz) as usual
3) Add a dynamic field of type node
4) Select a field defined by hook_field_extra_fields (example: Take quiz button) & add to display. Make sure both the original field and the new (duplicate) field are set to be visible.
5) View content
It looks like the call to node_view to render extra fields from ctools is causing the node to be re-rendered, which is then causing DS to follow suit. Not sure if it's a ctools or DS issue.
Here's the stack trace:
http://pastebin.com/rgvt9VY3
Comment | File | Size | Author |
---|---|---|---|
#8 | ds-2216661-8-ds_get_field_settings.patch | 1.84 KB | donquixote |
#6 | ds-2216661-6-ds_get_field_settings.patch | 1.28 KB | donquixote |
#1 | 2216661-infinite-recursion-with-extra-fields.patch | 848 bytes | djdevin |
Comments
Comment #1
djdevinTo fix this I prevented ds_field_attach_view_alter from running more than once on a given entity. Not sure if this is the right way to do it, but it worked for us.
Comment #2
djdevinComment #3
aspilicious CreditAttribution: aspilicious commentedThis doesn't prevent other things to run twice...
I'm not sure I really like the idea.
Hmmm
Comment #4
djdevinI don't like it either but I don't know of a better way to fix it. I think it's covering for a bigger problem about why it is getting called twice. Would it ever have to run twice for the same entity? Why would it need to alter something that was already altered...it's supposed to run once, but because
node_view -> ds_get_field_value -> ds_render_ctools_field -> ctools render -> content render(node_view) -> back to ds_get_field_value...
It ends up going into a loop.
Comment #5
donquixote CreditAttribution: donquixote commentedI ran into a different version of this problem.
One cycle of the infinite recursion on 7.x-2.6:
This is a dynamic field called "related products", which is filled with a views_content views display pane.
The "related products" should only show up when the main product is in view mode "full". The related products should then be displayed in view mode "grid item".
The "grid item" view mode does not have the "related products" field in any visible region, but ds_field_attach_view_alter() still calls ds_get_field_value() for every related product, and every related to the related product, etc.
So, the recursion unfolds before DS can determine that it doesn't need to show the dynamic field.
My suggestion would be to only evaluate the fields that are actually displayed on the page.
Comment #6
donquixote CreditAttribution: donquixote commentedI think the problem is in ds_get_field_settings().
This function attempts to filter out fields that are not visible in the current view mode.
But it fails to do so if the current view mode contains no dynamic fields at all. In this case, it returns the dynamic fields of the default view mode instead, which is wrong.
Attached is a patch which should fix this.
It also cleans up the clustered ternary operator in the end, but this is not really required to fix this.
Comment #7
donquixote CreditAttribution: donquixote commentedOh, I am wrong.
We need to look into the layout settings, to see if the view mode has a custom layout.. Even if this is not configured with Display suite.
Comment #8
donquixote CreditAttribution: donquixote commentedActually we just need one change.
The rest in the patch is cosmetics.
Comment #9
aspilicious CreditAttribution: aspilicious commentedThis changes the behaviour to NOT perform a fallback... That's like a big change, this probably will break a lot of things.
Comment #10
djdevinThe original STR still applies and fails on any field that is provided by field_extra_fields...I did move that code block below the killswitch just in case and it still fixes the recursion.
We've been using this in production for a year with many different configurations without any consequences, so it hasn't broken anything in normal use for us. I still don't think my patch is ideal, but we haven't been able to find a better way. I haven't had a chance to try the other patches here yet.
Comment #11
aspilicious CreditAttribution: aspilicious commentedHmm and what happens when you render the exact same entity twice on the same page
Comment #12
donquixote CreditAttribution: donquixote as a volunteer commentedWhat would be a case where the fallback is intended and legitimate?
It does make sense if the entire view mode has no dedicated configuration, and uses the default configuration instead.
In this case,
ds_get_layout()
will already return the default layout.And then,
ds_get_field_settings($entity_type, $bundle, $layout['view_mode'])
will already get the field settings for the default layout.But, if ds_get_layout() returns a dedicated layout for the given view mode, we also need the dedicated field settings, even if this is empty.
Comment #13
donquixote CreditAttribution: donquixote as a volunteer commentedThis said, I am not sure if this is really the same issue as reported by djdevin.
Maybe we should continue in #2653034: View mode without fields inherits from default view mode..
Comment #14
donquixote CreditAttribution: donquixote as a volunteer commentedOn second thought:
I am convinced that the current behavior is wrong. And likely has measurable performance implications on existing sites.
However, there might be code out there that relies on this kind of misbehavior.
What can we do? An opt-in fix? A major version bump? Or just have people fix their code?
Comment #15
donquixote CreditAttribution: donquixote as a volunteer commentedWe are still using the patch from #8.
I still think the logic of my previous comments is correct.
For each view mode, one of the following cases applies:
-> use settings from "default" for everything.
This is the problematic case.
The "ds_field_settings" contains settings for display suite custom fields, and nothing else.
This means, the last case occurs any time a view mode does not use ds custom fields.
In this case, ds will load the custom field settings for "default" view mode, even though the current view mode has custom configuration for other things like layout and regular fields.
This usually has no visible effects. The ds custom field settings for "default" are loaded and processed, but not displayed. This means silent waste of resources, but nothing else.
However it can cause a recursion, depending what custom fields are configured for default view mode.
With the patch from #8, ds will not load the custom field settings from "default".
So, would this cause any problems?
Possibly for case 2 above?
In this case,
$layout['view_mode']
in ds_field_attach_view_alter() will already be 'default', because ds_get_layout() already applies the default.So I do not expect any negative effect or BC break.
(uppercase for emphasis, no shouting intended)
Comment #16
donquixote CreditAttribution: donquixote as a volunteer commentedBtw a workaround is to clear all custom field settings from default view mode, and activate the "full" view mode instead.
On this project I had not done this because I was not aware that commerce_product has a "full" view mode. It is labeled "Admin display". We are using it in combination with commerce_product_page.
So one can avoid this kind of problem.
But this does not change that the current behavior is incorrect.
Comment #17
donquixote CreditAttribution: donquixote as a volunteer commentedA brief label for this problem would be:
ds custom field settings from "default" leak into other view modes
Comment #18
donquixote CreditAttribution: donquixote as a volunteer commentedOn the site I am currently working on, we have a number of paragraphs and taxonomy_term bundles with ds custom field settings in "default" view mode. I think this is quite common, and would be a lot of effort to avoid.
So we will continue to use the patch from #8.