Entity Reference Referrer – Getting Entity Reference’s Parent/Referrer Entity ID and Type
Out-of-the-box, the Entity Reference module doesn’t provide a way to access the referrer entity’s fields from within the referenced entity. I have two ways of doing this. The first is to patch the entityreference module (not ideal unless this patch went out to the community via proper channels; perhaps I should get on that?). The second is to mimic entityreference’s “Rendered entity” field formatter but modify it to include the referrer information. I recommend the second method for now.
Here’s the result (in this example we have a paragraph item (Paragraph module) that has an Entity Reference field within it called field_p_sstory_item):
Method 1
Patch entityreference.module to include the parent array you see screenshot above
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
diff --git a/entityreference.module b/entityreference.module index bdcb562..a274f1d 100755 --- a/entityreference.module +++ b/entityreference.module @@ -1202,6 +1202,11 @@ function entityreference_field_formatter_prepare_view($entity_type, $entities, $ $has_view_access = (entity_access('view', $field['settings']['target_type'], $target_entities[$item['target_id']]) !== FALSE); $has_update_access = (entity_access('update', $field['settings']['target_type'], $target_entities[$item['target_id']]) !== FALSE); $items[$id][$delta]['access'] = ($has_view_access || $has_update_access); + // Include the parent/referrer entity's information in the array of items + $items[$id][$delta]['referrer'] = array( + 'id' => $id, + 'entity_type' => $entity_type, + ); } // Otherwise, unset the instance value, since the entity does not exist. else { @@ -1264,6 +1269,8 @@ function entityreference_field_formatter_view($entity_type, $entity, $field, $in } $entity = clone $item['entity']; + // Include the parent/referrer entity's information in the entity itself + $entity->referrer = $item['referrer']; unset($entity->content); $result[$delta] = entity_view($field['settings']['target_type'], array($item['target_id'] => $entity), $settings['view_mode'], $langcode, FALSE); |
Method 2
Create your own field formatter to include the parent array you see in the screenshot above
This is a basically a replication of the entityreference_entity_view formatter from entityreference.module, with one small change to include the parent entity’s id and entity_type.
Search for the word “referrer” in the code to see what I’ve added.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
/************************************************************************* * All of the code below mimics the Entity Reference "Rendered entity" * * formatter, but adds the referrer entity ID and type to the referenced * * entity object and to the items array for the entity reference field. * * * * The new formatter (Rendered entity with referrer info) is for backend * * coding benefits only. The output is identical to "Rendered entity". * *************************************************************************/ /** * Implements hook_field_formatter_info(). * * This is nearly identical to entityreference.module. * @see entityreference_field_formatter_info(). */ function mymodule_field_formatter_info() { return array( 'mymodule_er_entity_view_with_referrer' => array( 'label' => t('Rendered entity with referrer info'), 'description' => t('Display the referenced entities rendered by entity_view(), with additional referrer information available for developers.'), 'field types' => array('entityreference'), 'settings' => array( 'view_mode' => 'default', 'links' => TRUE, ), ), ); } /** * Implements hook_field_formatter_settings_form(). * * This is nearly identical to entityreference.module. * @see entityreference_field_formatter_settings_form(). */ function mymodule_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) { $display = $instance['display'][$view_mode]; $settings = $display['settings']; if ($display['type'] == 'mymodule_er_entity_view_with_referrer') { $entity_info = entity_get_info($field['settings']['target_type']); $options = array('default' => t('Default')); if (!empty($entity_info['view modes'])) { foreach ($entity_info['view modes'] as $view_mode => $view_mode_settings) { $options[$view_mode] = $view_mode_settings['label']; } } $element['view_mode'] = array( '#type' => 'select', '#options' => $options, '#title' => t('View mode'), '#default_value' => $settings['view_mode'], '#access' => count($options) > 1, ); $element['links'] = array( '#type' => 'checkbox', '#title' => t('Show links'), '#default_value' => $settings['links'], ); } return $element; } /** * Implements hook_field_formatter_settings_summary(). * * This is nearly identical to entityreference.module. * @see entityreference_field_formatter_settings_summary(). */ function mymodule_field_formatter_settings_summary($field, $instance, $view_mode) { $display = $instance['display'][$view_mode]; $settings = $display['settings']; $summary = array(); if ($display['type'] == 'mymodule_er_entity_view_with_referrer') { $entity_info = entity_get_info($field['settings']['target_type']); $view_mode_label = $settings['view_mode'] == 'default' ? t('Default') : $settings['view_mode']; if (isset($entity_info['view modes'][$settings['view_mode']]['label'])) { $view_mode_label = $entity_info['view modes'][$settings['view_mode']]['label']; } $summary[] = t('Rendered as @mode', array('@mode' => $view_mode_label)); $summary[] = !empty($settings['links']) ? t('Display links') : t('Do not display links'); } return implode('<br />', $summary); } /** * Implements hook_field_formatter_prepare_view(). * * This is nearly identical to entityreference.module. * @see entityreference_field_formatter_prepare_view(). */ function mymodule_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) { $target_ids = array(); // Collect every possible entity attached to any of the entities. foreach ($entities as $id => $entity) { foreach ($items[$id] as $delta => $item) { if (isset($item['target_id'])) { $target_ids[] = $item['target_id']; } } } if ($target_ids) { $target_entities = entity_load($field['settings']['target_type'], $target_ids); } else { $target_entities = array(); } // Iterate through the fieldable entities again to attach the loaded data. foreach ($entities as $id => $entity) { $rekey = FALSE; foreach ($items[$id] as $delta => $item) { // Check whether the referenced entity could be loaded. if (isset($target_entities[$item['target_id']])) { // Replace the instance value with the term data. $items[$id][$delta]['entity'] = $target_entities[$item['target_id']]; // Check whether the user has access to the referenced entity. $has_view_access = (entity_access('view', $field['settings']['target_type'], $target_entities[$item['target_id']]) !== FALSE); $has_update_access = (entity_access('update', $field['settings']['target_type'], $target_entities[$item['target_id']]) !== FALSE); $items[$id][$delta]['access'] = ($has_view_access || $has_update_access); // Include the parent/referrer entity's information in the array of items $items[$id][$delta]['referrer'] = array( 'id' => $id, 'entity_type' => $entity_type, ); } // Otherwise, unset the instance value, since the entity does not exist. else { unset($items[$id][$delta]); $rekey = TRUE; } } if ($rekey) { // Rekey the items array. $items[$id] = array_values($items[$id]); } } } /** * Implements hook_field_formatter_view(). * * This is nearly identical to entityreference.module. * @see entityreference_field_formatter_settings_summary(). */ function mymodule_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) { $result = array(); $settings = $display['settings']; // Rebuild the items list to contain only those with access. foreach ($items as $key => $item) { if (empty($item['access'])) { unset($items[$key]); } } switch ($display['type']) { case 'mymodule_er_entity_view_with_referrer': foreach ($items as $delta => $item) { // Protect ourselves from recursive rendering. static $depth = 0; $depth++; if ($depth > 20) { throw new EntityReferenceRecursiveRenderingException(t('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $entity_type, '@entity_id' => $item['target_id']))); } $entity = clone $item['entity']; $entity->referrer = $item['referrer']; unset($entity->content); $result[$delta] = entity_view($field['settings']['target_type'], array($item['target_id'] => $entity), $settings['view_mode'], $langcode, FALSE); if (empty($settings['links']) && isset($result[$delta][$field['settings']['target_type']][$item['target_id']]['links'])) { $result[$delta][$field['settings']['target_type']][$item['target_id']]['links']['#access'] = FALSE; } $depth = 0; } break; } return $result; } |
Usage
Now that you have the entity’s referrer you need to do something with it. Perhaps you’re trying to include a field from the referrer entity in the referenced entity. Here’s one way to do this using Display Suite.
Full Content view mode for the paragraph:
Callout single large view mode for the news_item (story) node:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/** * Implements hook_ds_fields_info(). */ function mymodule_ds_fields_info($entity_type) { $fields = array(); $fields['node']['parent_paragraph_heading'] = array( 'title' => t('Parent paragraph heading (mymodule.module)'), 'field_type' => DS_FIELD_TYPE_FUNCTION, 'function' => 'mymodule_ds_field_parent_paragraph_heading', 'ui_limit' => array('news_item|*'), ); if (isset($fields[$entity_type])) { return array($entity_type => $fields[$entity_type]); } return array(); } /** * Callback for the parent_paragraph_heading DS field * * Returns the heading field value from the paragraph that referenced this entity * * This will only work if the entity reference field is being rendered as "Rendered entity with referrer info" */ function mymodule_ds_field_parent_paragraph_heading($field) { if (empty($field['entity']->referrer)) { return ''; } // Return the heading field from the parent/referrer paragraph $wrapper = entity_metadata_wrapper($field['entity']->referrer['entity_type'], $field['entity']->referrer['id']); if (!empty($wrapper->field_p_sstory_heading)) { return $wrapper->field_p_sstory_heading->value(); } return ''; } |