I created a partial solution for recursive rendering (see the patch). With this solution circular rendering can be detected, as long as the recursion occurs within this module and in the max. defined number of steps.
It solves the following situations (A, B, C, ... are different entities, => means: refers to):
- A => A
- A => B => A
- A => B => C => A
- A => B => ... H => A
- A => B => C => B
- A => B => C => ... H => C
In all cases the last reference is not shown.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Damien Tournoud’s picture

What's not working with the current recursive protection that we have?

PROMES’s picture

If you create a reference from entity A to B and B also has a reference to A you get an endless loop when you select for both the view-mode: rendered entity. The error message is:
EntityReferenceRecursiveRenderingException: Recursive rendering detected when rendering entity crm_core_contact(100001002). Aborting rendering. in entityreference_field_formatter_view() (line 1270 of /sites/all/modules/contrib/entityreference/entityreference.module).

I need this reference both ways for a website.

Damien Tournoud’s picture

@PROMES: This is a fail safe. If you configure your rendering so that you end up with an infinite loop, of course the rendering is going to fail.

What you need to do is make sure that you don't end up in this situation by properly configuring the view mode and formatter configuration so that it doesn't happen.

PROMES’s picture

@Damien: off course I know that creating a loop can result in an error. But it is so simple to prevent it. And in some (maybe rare) cases it gives you just the result you need.

jyg’s picture

Damien is 100% correct. But his answer was a bit cryptic, at least for me. After I ran into this problem, and did some research, I was able to resolve it in the following way. So here's the long version of Damien's answer:

1. Create a new view mode (You don't have to, for example you could use the teaser. But I think its safer in the long run to create a custom, specific mode. YMMV)

function MYMODULE_entity_info_alter(&$entity_info) {
  $entity_info['node']['view modes']['referred_view_mode'] = array(
    'label' => t('My Referred View Mode),
    'custom settings' => TRUE
  );      
}

2. Configure the EntityReference field within your content type to display in your new view mode, "My Referred View Mode". On the "Manage Display" tab there will be a gear buttons on EntityReference rows which will allow you to specify the view mode for the entities referred to by your field.

3. Up till this point you've probably been managing the display for your default/full view mode (or maybe your teaser). Click on the name of your new view mode in the list of view modes up top. Within this view mode add in the fields you want display within the list of referred entities as display on your main referred node's view. Remember not to add in this very same EntityReference field again, or you'll just be recreate the problem!

I hope this saves someone a few hours.

PROMES’s picture

@jyg: Thanks for this interesting possibility, I didn't know of.
Step 1 is easy - done.
In step 2: at manage display I can select the "rendered entity" and then click on the gear button and select "My Referred View Mode".
In step 3 you say: Click on the name of your new view mode in the list of view modes up top. But in the entity I use (CRM Core contact) the viewmodes are not available. So I don't know how to define the fields.
(of course I changed in your code 'node' into 'crm_core_contact' for the correct entity).

When I try it on a node, I indeed can select the new viewmode. But I only select one (1) predefined field not make a selection of the fields I need. Maybe I should create a reference to the node for every field I wish to show (provided I can select the viewmode in the entity at hand).

How do I show show the fields I need?

kenorb’s picture

Status: Active » Needs review

I had similar problem when adding the product to the cart and the following fatal error appeared on Cart page (/cart):

EntityReferenceRecursiveRenderingException: Recursive rendering detected when rendering entity commerce_product(23). Aborting rendering. in entityreference_field_formatter_view() (line 1263 of contrib/entityreference/entityreference.module).

And the patch solves the problem.

Status: Needs review » Needs work

The last submitted patch, entityreference.patch, failed testing.

Damien Tournoud’s picture

Status: Needs work » Closed (works as designed)

At this point a lot of reasons have been given why this is not really a good idea, and more a symptom than a bug. I'm marking this as "works as designed".

bbinkovitz’s picture

I like this recursion check and I'm adapting it for use in the Views Hybrid module, with credits to @promes.

mpotter’s picture

Version: 7.x-1.1 » 7.x-1.x-dev
Status: Closed (works as designed) » Needs review
FileSize
1.29 KB

Actually, this is a *very* useful patch. Let me illustrate another use case:

We have two content types that contain entityreferences. The user is allowed to reference any other content on the site as "related content". This related content is shown as part of the body of the node (NOTE: We are *actually* using Paragraphs entities that have entityreferences, so the situation in Open Atrium is a bit more complicated).

The point is, we can't control what the user might select as related content. It might not even be a 2-step circular reference. As in the OP, it might be Node A references Node B references Node C references Node A again.

There is no simple way to control this with view modes or by restricting the entity reference itself. There is no way for Node C to know that Node A references B and that B references C. The whole point of the related content is to show the full node, including any related content of the other nodes (Again, we are really using Paragraphs to extend the purpose of the Body field to include "snippets" from other nodes, including any "snippets" that the other nodes define).

This patch fixed our recursion issues perfectly. However, the patch definitely needed a proper title and needed to be re-rolled on the latest dev version. So here it is.

We will be using this patch in Open Atrium. Given that it doesn't seem to have any bad side effects I'd like to reopen the discussion of the patch and mark it for Review. Let's not focus on whether or not there are valid use cases for this (there are!) but focus instead on the code itself. Anything that makes entityreference more robust should be a positive improvement.

mpotter’s picture

Status: Needs review » Needs work

Looks like I need to work on this patch more. It actually causes several of our entityreferences that do *not* have any recursive loops to not show content. I'll post more when I have something working better later today.

mpotter’s picture

I think the built-in recursion is actually going to be ok. The issue seems to be that entity build_content does an unset($entity->content) but it also has a line:

$entity->content += field_attach_view...

So if there is a recursive call to the same entity, the "content" property is unset, and when it returns back up to this line and tries do the += it can't because the content property has been cleared.

I think there is a simple fix to add to entityreference's recursion code to detect an unset($entity->content) and deal with that. Should have a new patch tomorrow. It's going to be *much* simpler than this original patch and will mostly rely on the existing detection.

PROMES’s picture

@mpotter
I am glad you have a good usecase like I have.
I improved the check by using less resources by avoiding creating a new object (with its overhead) in the line: $wrapper = entity_metadata_wrapper($entity_type, $entity);
See issue https://www.drupal.org/node/2333441 for the improved code.

mpotter’s picture

Can you post a patch here for it? As I said above, I'm not sure I'll actually use your patch at all. There was a logic issue with it (adding items to $recursive within the wrong loop) that was preventing non-recursive references from working properly. But as Damien mentioned in #1, I'm not really seeing a problem with the existing recursion protection in entityreference. The actual problem is more of an issue with entity itself and I'm looking at a patch for that.

mpotter’s picture

Here is the related patch in the Entity API module that fixes the problem I was having with entityreference recursion: #2407905: Unsupported operand type when using recursive entity view

I'd be fine with closing this as "works as designed" again since I'm not seeing a real need for a more extensive change to entityreference itself.

PROMES’s picture

Hier is my improved patch.

mansspams’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 17: entityreference_prevent_recursion-2301499-17.patch, failed testing.

nikolas.costa’s picture

Attachment new patch for version entityreference 7.x-1.2

PROMES’s picture

I found a less expensive way to get the id's, not using the wrapper function but entity_extract_ids(). See updated patch.

robertom’s picture

Attached a rerolled patch for entityreference 7.x-1.5