entity_embed.display.inc in Entity Embed 7.3
Same filename and directory in other branches
Display functions.
File
includes/entity_embed.display.incView source
<?php
/**
* @file
* Display functions.
*/
/**
* Renders an embedded entity.
*
* @param $entity_type
* The type of entity, i.e. 'node', 'user'.
* @param $entity
* The entity to be rendered.
* @param array $context
* (optional) Array of context values, corresponding to the attributes on
* the embed HTML tag.
*
* @return string
* The HTML of the entity rendered with the Entity Embed Display plugin.
*/
function entity_embed_render_entity($entity_type, $entity, array $context = array()) {
// Support the deprecated view-mode data attribute.
if (isset($context['data-view-mode']) && !isset($context['data-entity-embed-display']) && !isset($context['data-entity-embed-settings'])) {
$context['data-entity-embed-display'] = 'entityreference:entityreference_entity_view';
$context['data-entity-embed-settings'] = array(
'view_mode' => $context['data-view-mode'],
);
}
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
// Merge in default attributes.
$context += array(
'data-entity-id' => $id,
'data-entity-type' => $entity_type,
'data-entity-embed-display' => 'entityreference:entityreference_entity_view',
'data-entity-embed-settings' => array(),
);
// The default Entity Embed Display plugin has been deprecated by the
// rendered entity field formatter.
if ($context['data-entity-embed-display'] === 'default') {
$context['data-entity-embed-display'] = 'entityreference:entityreference_entity_view';
}
// Allow modules to alter the entity prior to embed rendering.
drupal_alter(array(
"{$context['data-entity-type']}_embed_context",
'entity_embed_context',
), $context, $entity);
// Build and render the Entity Embed Display plugin, allowing modules to
// alter the result before rendering.
$build = render_entity_embed_display_plugin($entity_type, $entity, $context['data-entity-embed-display'], $context['data-entity-embed-settings'], $context);
// Maintain data-align if it is there.
if (isset($context['data-align'])) {
$build['#attributes']['data-align'] = $context['data-align'];
}
elseif (isset($context['class'])) {
$build['#attributes']['class'][] = $context['class'];
}
// Maintain data-caption if it is there.
if (isset($context['data-caption'])) {
$build['#attributes']['data-caption'] = $context['data-caption'];
}
// @todo Should this hook get invoked if $build is an empty array?
drupal_alter(array(
"{$context['data-entity-type']}_embed",
'entity_embed',
), $build, $entity, $context);
$entity_output = drupal_render($build);
return $entity_output;
}
/**
* Renders an entity using an Entity Embed Display plugin.
*
* @param $entity_type
* The type of entity, i.e. 'node', 'user'.
* @param $entity
* The entity to be rendered.
* @param string $plugin_id
* The Entity Embed Display plugin ID.
* @param array $plugin_configuration
* (optional) Array of plugin configuration values.
* @param array $context
* (optional) Array of additional context values, usually the embed HTML
* tag's attributes.
*
* @return array
* A render array for the Entity Embed Display plugin.
*/
function render_entity_embed_display_plugin($entity_type, $entity, $plugin_id, array $plugin_configuration = array(), array $context = array()) {
// Check if the display plugin is accessible.
if (!entity_access('view', $entity_type, $entity)) {
return array();
}
// Split the formatter into separate parts.
$formatter_parts = explode(':', $plugin_id);
$formatter_module = $formatter_parts[0];
$formatter_type = $formatter_parts[1];
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
$field_formatter_info = field_info_formatter_types($formatter_type);
// With the File Entity module enabled, file entities require some special
// handling. Unlike standard field formatters which specify a list of
// compatible entity types and will work with any entity as long as it is the
// correct type, file formatters may only support files with specific MIME
// types.
if ($entity_type == 'file' && module_exists('file_entity')) {
if (isset($field_formatter_info['file formatter']['mime types'])) {
if (!file_entity_match_mimetypes($field_formatter_info['file formatter']['mime types'], $entity->filemime)) {
$file_type = file_type_load($entity->type);
// Inform the user that the file they are trying to embed cannot be
// displayed using the selected formatter.
return array(
'#markup' => '<p>' . t('The %type file %filename is unable to be displayed as %formatter. Please select a different formatter.', array(
'%type' => $file_type->label,
'%filename' => $entity->filename,
'%formatter' => $field_formatter_info['label'],
)) . '</p>',
);
}
}
}
if (isset($field_formatter_info['module'])) {
// Set $display['type'] and $display['settings'] to what
// hook_field_formatter_*() expects.
$display['type'] = $formatter_type;
$display['settings'] = $plugin_configuration += field_info_formatter_settings($formatter_type);
// Use default settings if no settings are available.
// Set $items to what the field formatter expects. See hook_field_load(),
// and note that, here, $entity is already a fully loaded entity.
$items = entity_embed_field_get_items($entity_type, $id, $field_formatter_info['module']);
// Invoke hook_field_formatter_prepare_view() and
// hook_field_formatter_view(). Note that we are reusing field formatter
// functions, but we are not displaying a Field API field, so we set
// $field and $instance accordingly, and do not invoke
// hook_field_prepare_view(). This assumes that the formatter functions do
// not rely on $field or $instance. A module that implements formatter
// functions that rely on $field or $instance (and therefore, can only be
// used for real fields) can add support for being used on the pseudo-field
// by adding in any missing information using the entity_embed_field_info
// hooks.
$field = entity_embed_field_info_field($entity_type, $field_formatter_info['module']);
$instance = entity_embed_field_info_instance($formatter_type, $plugin_configuration);
if (($function = $field_formatter_info['module'] . '_field_formatter_prepare_view') && function_exists($function)) {
// hook_field_formatter_prepare_view() alters $items by reference.
$grouped_items = array(
$id => &$items,
);
$function($entity_type, array(
$id => $entity,
), $field, array(
$id => $instance,
), $context['data-langcode'], $grouped_items, array(
$id => $display,
));
}
if (($function = $field_formatter_info['module'] . '_field_formatter_view') && function_exists($function)) {
$element = $function($entity_type, $entity, $field, $instance, $context['data-langcode'], $items, $display);
// We passed the entity as $items[0], so return the corresponding element.
if (isset($element[0])) {
return $element[0];
}
}
}
}
/**
* Get the possible field types that an entity might be displayed inside of.
*
* @param string $entity_type
* The type of entity that might be displayed.
*
* @return
* An array of field types that might display the passed entity type.
*/
function entity_embed_get_entity_field_types($entity_type) {
$field_types = array();
// All entity types, by definition, can be displayed as entityreference.
$field_types[] = 'entityreference';
// Support for nodes.
if ('node' == $entity_type) {
$field_types[] = 'node_reference';
}
// Support for users.
if ('user' == $entity_type) {
$field_types[] = 'user_reference';
}
// Support for taxonomy.
if ('taxonomy_term' == $entity_type) {
$field_types[] = 'taxonomy_term_reference';
}
// Support for files.
if ('file' == $entity_type) {
$field_types[] = 'image';
$field_types[] = 'file';
}
// Support for any other entity_types.
$additional_field_types = module_invoke_all('entity_embed_field_types', $entity_type);
$field_types = array_merge($field_types, $additional_field_types);
return $field_types;
}
/**
* Helper function to get all the field formatters that we can use to display
* entity types.
*
* @param $entity_type
* The type of entity, i.e. 'node', 'user'.
* @param $entity
* (optional) The entity to be rendered. This is used to perform special
* checks/processing for unruly modules.
*
* @return array
*/
function entity_embed_get_entity_field_formatters($entity_type, $entity = NULL) {
$formatters = field_info_formatter_types();
$field_types = entity_embed_get_entity_field_types($entity_type);
$entity_formatters = array();
foreach ($formatters as $formatter => $info) {
// Files require special handling.
if ($entity_type == 'file') {
// Files behave differently depending on whether the File Entity module is
// available.
if (module_exists('file_entity')) {
// With the File Entity module enabled, file entities require some
// special handling. Unlike standard field formatters which specify a
// list of compatible entity types and will work with any entity as long
// as it is the correct type, file formatters may only support files
// with specific MIME types.
if (isset($entity) && isset($info['file formatter']['mime types']) && isset($entity->filemime)) {
if (!file_entity_match_mimetypes($info['file formatter']['mime types'], $entity->filemime)) {
// Skip the incompatible formatter.
continue;
}
}
}
else {
// The 'Rendered entity' formatter can not be used for files unless the
// File Entity module is available.
if ($formatter == 'entityreference_entity_view') {
// Skip the incompatible formatter.
continue;
}
}
}
// With the File Image Formatters module enabled, image field formatters
// will appear twice.
if ($info['module'] == 'file_image_formatters' && module_exists('file_image_formatters')) {
// Skip the duplicate formatter.
continue;
}
foreach ($info['field types'] as $field_type) {
if (in_array($field_type, $field_types)) {
$entity_formatters[$info['module'] . ':' . $formatter] = $info['label'];
break;
}
}
}
return $entity_formatters;
}
/**
* @file
* Helper functions for Entity Embed involving field formatters.
*
* All of these functions are by definition hacky, because we're trying to use
* a couple of hook in ways they were not intended to be used: displaying
* arbitrary entities. The hooks are:
* - hook_field_formatter_settings_form()
* - hook_field_formatter_view()
*/
/**
* Our own field-less and entity-less version of field_get_items().
*
* @param string $entity_type
* The entity type of the entity we are trying to embed.
*
* @param int $entity_id
* The entity id of the entity we are trying to embed.
*
* @param string $module
* The module that implements the field formatter we are going to use.
*
* In our version of field_get_items() we don't care at all about the field
* or the entity that it is attached to. All we want is the output of the
* formatter. So the point of this is return an $items array in the format
* expected by the passed module's particular implementation of
* hook_field_formatter_view().
*
* Ideally this would be a simple hook letting other modules do the work, but
* we will hard-code support for the major players here.
*/
function entity_embed_field_get_items($entity_type, $entity_id, $module) {
// Whatever module is involved, we're almost definitely going to need the
// entity loaded and an access check.
$entity = entity_load_single($entity_type, $entity_id);
$access = entity_access('view', $entity_type, $entity);
$item = array(
'access' => $access,
);
// Support the entityreference module.
if ('entityreference' == $module) {
$item += array(
'entity' => $entity,
'target_id' => $entity_id,
);
}
elseif ('taxonomy' == $module) {
$item += array(
'tid' => $entity_id,
'name' => entity_label($entity_type, $entity_id),
'taxonomy_term' => $entity,
);
}
elseif ('file' == $module || 'image' == $module) {
// The file and image modules just expect an array version of the object.
$item += (array) $entity;
}
elseif ('user_reference' == $module) {
$item += array(
'uid' => $entity_id,
'user' => $entity,
);
}
elseif ('node_reference' == $module) {
$item += array(
'nid' => $entity_id,
'node' => $entity,
);
}
elseif ('file_entity' == $module) {
// In general the file_entity module expects items to be
// file objects, but in array form, similar to core image/file.
$item += (array) $entity;
}
else {
$contrib_items = module_invoke_all('entity_embed_field_get_items', $entity_type, $entity_id, $module);
// Make sure we only get 1 item.
if (!empty($contrib_items)) {
$item += array_pop($contrib_items);
}
}
return array(
$item,
);
}
/**
* Our own field-less entity-less version of field_get_display().
*
* @param $formatter_type
* A formatter type name.
*
* @param int $settings
* Optional array of settings to pass in. If omitted, the formatter's default
* settings will be returned.
*
* @return
* An array containing 'type' and 'settings'.
*
* In our version of field_get_display() we don't care at all about the field
* or the entity/bundle that it is attached to. All we want is a display
* array that will help us hack our way through hook_field_formatter_view() and
* hook_field_formatter_settings_form(). This mainly means making sure the
* 'settings' and 'type' elements are there and populated appropriately.
*
* Luckily this can be the same regardless of formatter/module, so we don't
* need to hard-code module support or invoke any hooks.
*/
function entity_embed_field_get_display($formatter_type, $settings = array()) {
// If settings is empty, we need to get defaults.
if (empty($settings)) {
$formatter_info = field_info_formatter_types($formatter_type);
if (!empty($formatter_info['settings'])) {
$settings = $formatter_info['settings'];
}
}
return array(
'type' => $formatter_type,
'settings' => $settings,
);
}
/**
* Our own field-less version of field_info_field().
*
* @param string $entity_type
* The entity type of the entity we are trying to embed.
*
* @param string $module
* The module that implements the field formatter we are going to use.
*
* In our version of field_info_field() we don't care at all about the field
* itself. All we want is the field info array in a format that lets us hack
* into hook_field_formatter_view() and hook_field_formatter_settings_form().
* The problem is that each module may expect something different in this array.
*
* Ideally this would be a simple hook letting other modules do the work, but
* we will hard-code support for the major players here.
*/
function entity_embed_field_info_field($entity_type, $module) {
$field = array();
$field['field_name'] = '_entity_embed';
// Support the entityreference module.
if ('entityreference' == $module) {
$field['settings'] = field_info_field_settings('entityreference');
$field['settings']['target_type'] = $entity_type;
}
elseif ('user_reference' == $module) {
$field['settings'] = field_info_field_settings('user_reference');
}
elseif ('node_reference' == $module) {
$field['settings'] = field_info_field_settings('node_reference');
}
elseif ('taxonomy' == $module) {
$field['settings'] = field_info_field_settings('taxonomy_term_reference');
}
elseif ('file' == $module || 'file_entity' == $module) {
$field['settings'] = field_info_field_settings('file');
}
elseif ('image' == $module) {
$field['settings'] = field_info_field_settings('image');
}
else {
$field = module_invoke_all('entity_embed_field_info_field', $entity_type, $module);
}
return $field;
}
/**
* Our own field-less entity-less version of field_info_instance().
*
* @param $formatter_type
* A formatter type name.
*
* @param int $settings
* Optional array of settings to pass in. If omitted, the formatter's default
* settings will be returned.
*
* In our version of field_info_instance() we don't care at all about the field
* itself. All we want is the field instance array in a format that lets us hack
* into hook_field_formatter_view() and hook_field_formatter_settings_form().
* The problem is that each module may expect something different in this array.
*
* This is mainly a wrapper around entity_embed_field_get_display().
*/
function entity_embed_field_info_instance($formatter_type, $settings = array()) {
return array(
'display' => array(
'default' => entity_embed_field_get_display($formatter_type, $settings),
),
);
}
/**
* Our own field-less entity-less version of field_info_formatter_settings().
*
* @param $entity_type
* The type of entity, i.e. 'node', 'user'.
* @param $entity
* The entity to be rendered.
* @param $formatter_type
* A formatter type name.
* @param int $settings
* Optional array of settings to pass in. If omitted, the formatter's default
* settings will be returned.
* @param $form
* A form array().
* @param $form_state
* A form state array.
*
* In our version of field_info_formatter_settings() we don't care at all about
* the field itself. All we want is the field info array in a format that lets
* us hack hook_field_formatter_settings_form().
*/
function entity_embed_field_info_formatter_settings($entity_type, $entity, $formatter_type, $settings = array(), $form, $form_state) {
$formatter_settings = array();
$field_formatter_info = field_info_formatter_types($formatter_type);
// Invoke hook_field_formatter_settings_form(). We are reusing field
// formatter functions, but we are not working with a Field API field,
// so set $field accordingly. Unfortunately, the API is for $settings to
// be transferred via the $instance parameter, so we must mock it.
if (isset($field_formatter_info['module']) && ($function = $field_formatter_info['module'] . '_field_formatter_settings_form') && function_exists($function)) {
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
$field = entity_embed_field_info_field($entity_type, $field_formatter_info['module']);
$view_mode = 'default';
$mock_instance = array(
'display' => array(
$view_mode => array(
'type' => $formatter_type,
'settings' => $settings + field_info_formatter_settings($formatter_type),
),
),
'entity_type' => $entity_type,
'bundle' => $bundle,
);
$formatter_settings += $function($field, $mock_instance, $view_mode, $form, $form_state);
}
return $formatter_settings;
}
Functions
Name | Description |
---|---|
entity_embed_field_get_display | Our own field-less entity-less version of field_get_display(). |
entity_embed_field_get_items | Our own field-less and entity-less version of field_get_items(). |
entity_embed_field_info_field | Our own field-less version of field_info_field(). |
entity_embed_field_info_formatter_settings | Our own field-less entity-less version of field_info_formatter_settings(). |
entity_embed_field_info_instance | Our own field-less entity-less version of field_info_instance(). |
entity_embed_get_entity_field_formatters | Helper function to get all the field formatters that we can use to display entity types. |
entity_embed_get_entity_field_types | Get the possible field types that an entity might be displayed inside of. |
entity_embed_render_entity | Renders an embedded entity. |
render_entity_embed_display_plugin | Renders an entity using an Entity Embed Display plugin. |