I have an entity reference field that I render in place (Rendered entity formatter). However during the rendering of the referred entity I would like to (programmatically) access data from the referring entity.

How can I do so?

Some remarks:
- Use case: I am rendering a contact webform within a node. I want to set the email to send the contact form to based on the author email of the referring node.
- The references/node_reference/user_reference module adds a referencing_entity property to the entity during rendering.
- If it does not yet exist, it could be as easy as changing these lines:

function entityreference_field_formatter_view() {
  ...
  case 'entityreference_entity_view':
        // Protect ourselves from recursive rendering.
        ...

        $referred_entity = clone $item['entity'];
        $referred_entity->referring_entity = $entity;
        $referred_entity->referring_field = array('name'=> $field['field_name'], 'delta' => $delta);
        unset($referred_entity->content);
        $result[$delta] = entity_view($field['settings']['target_type'], array($item['target_id'] => $referred_entity), $settings['view_mode'], $langcode, FALSE);

        ...
}

If you are interested, I can post a proper patch.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

sagannotcarl’s picture

I am also interested in this fietserwin, I'd love to see your code if you have it working.

Thanks!
Colin

fietserwin’s picture

Status: Active » Needs review
FileSize
1.24 KB

Here's the patch. I hope it will make it into the module itself.

Status: Needs review » Needs work

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

fietserwin’s picture

Status: Needs work » Needs review
FileSize
1.37 KB

Let's try again with a git created patch...

Birk’s picture

I've used this patch(#4) on 2 projects with no problems so far.
But I needed the referring entity type as well, so I added the following line:
$referred_entity->referring_entity_type = $entity_type;

This has given 3 referring_X properties to the entity, it would make sense to gather them in a single referrer property, like so:

$referred_entity->referrer = array(
  'entity' => $entity,
  'entity_type' => $entity_type,
  'field' => array('name'=> $field['field_name'], 'delta' => $delta),
);

This way we wont pollute the entity object with multiple referred_x, and it would be easy to add additional referrer related data. Just a thought.

gmercer’s picture

Version: 7.x-1.0 » 7.x-1.x-dev
Issue summary: View changes
FileSize
1.43 KB

We need to pass the entity type as well, here's a patch for #5. Renamed ->referrer to ->entityreference_referrer to prevent any future naming clashes.

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

To further expand on #6, our use case is this:

We have a content type, faculty. Via an EVA listing, we're listing all nodes of the content type publication, which have a reference to the faculty.

However, when we view the publication, we display the faculty via hook_field_extra_fields and hook_node_view. In that workflow, you load the data you need, add it to $node->content, and the field system determines if it should be shown.

But when rendering the faculty, rendering the publication, and then rendering the faculty again, the unset($entity->content); is affecting the actual node being viewed!

Our only option is to prevent the recursion in hook_node_view, and that can only be done if we know the referring entity.

fietserwin’s picture

#5 and #6 are indeed improvements to my patch from #4.

+1 on RTBC.

Damien Tournoud’s picture

@tim.plunkett: your issue seems different? Everywhere an entity is rendered, it is supposed to be cloned first, so that any rendering in $entity->content doesn't affect the entity from the static cache.

Could you research why it is not happening for you?

tim.plunkett’s picture

+++ b/entityreference.module
+++ b/entityreference.module
@@ -1263,9 +1263,14 @@ function entityreference_field_formatter_view($entity_type, $entity, $field, $in

@@ -1263,9 +1263,14 @@ function entityreference_field_formatter_view($entity_type, $entity, $field, $in
-        $entity = clone $item['entity'];
...
+        $referred_entity = clone $item['entity'];

I can certainly look into it more, but at first glance I think I'm fixing another bug as a side-effect: We're overriding the $entity passed into the function in the first place.

And regardless of my actual problem, I don't want to run my code in hook_node_view() if the referred entity is of a certain bundle. So I need this info anyway.

tim.plunkett’s picture

I'm not sure, but I think my own problems are compounded by the entityreference being inside a field_collection. (Don't judge me!)

That said, this change stands alone as a feature request.

Damien Tournoud’s picture

@tim.plunkett: most likely, somewhere something is not cloning an entity before displaying it. It would be really useful for the community as a whole for you to track this down :)

tim.plunkett’s picture

Yep. Neither node_view() nor node_build_content() clone it.

What would you expect to be the output of this?

function mymodule_node_view($node, $view_mode, $langcode) {
  $node->arbitrary_key = 'some value';
  $node_again = node_load($node->nid);
  debug($node_again->arbitrary_key);
}

I personally would try to not do this. Hence the need for this feature request.

It seems that you would expect this to result in Undefined property: stdClass::$arbitrary_key.
But because the node functions don't clone the object, and because the entity is statically cached by the entity storage, both nodes have the value.

So, accidentally running the same node through node_view will have its ->content unset.

I confirmed this with Berdir and amateescu in IRC.

PROMES’s picture

I created a more general solution where an entity can reference itself, or circular be referenced without problems.
So entity A can reference A or entity A can reference B wich references C which references A. All up to the depth of 20.
In all cases the last reference is not shown.
It is based on the 7x-1.1 version.
Please test if its working in your cases as well.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 14: entityreference-1986070-14.patch, failed testing.

PROMES’s picture

The invalid patch format is always a problem of windows pc's. As far as I know, this should be a valid patch file.

fietserwin’s picture

I can't relate your patch to the feature request at hand. We are not solving a recursion problem here, but solving a problem of having programmatic access to the referring entity.

BTW: if you are trying to solve a recursion problem, I think your code is incorrect. If a refers to b and c (in different fields or delta's) and b refers to c, I think that c will only be rendered once, because the static array is collecting all references during the rendering of 1 page. So, same problem when rendering a list of entities (e.g. a View) of which multiple instances refer to the same entity: rendering a and b on the same page and a and b refer to c.

PROMES’s picture

To #17 fietserwin: you are right. I didn't read carefully enough.
I moved my patch to: https://www.drupal.org/node/2301499

fietserwin’s picture

Status: Needs work » Reviewed & tested by the community

So, patch #6 is back to RTBC.

minorOffense’s picture

Assigned: Unassigned » minorOffense
Status: Reviewed & tested by the community » Needs review

We'll need to look over this before deciding if it should go into entityreference proper. I feel as though just overriding the default handler for your specific cases could suffice.

But like I said, we'll look it over.

fietserwin’s picture

FileSize
734 bytes

Reroll of patch #6 plus that, to be complete, field should consist of name, langcode and delta.

RE #20: I guess there are indeed ways to solve this differently, e.g. overriding the field formatter, as I guess that is the "handler" you refer to. However, IMO, references are almost always 2-way, often not stored as such (to prevent duplication) but certainly populated so on creation. Therefore I think that this feature should be part of this module.

Status: Needs review » Needs work

The last submitted patch, 21: programmatic_access_to-1986070-21.patch, failed testing.

vensires’s picture

@fietserwin could you re-roll the patch against the latest dev?