entityreference_prepopulate.module in Entityreference prepopulate 7
Prepopulate entity reference values from URL.
File
entityreference_prepopulate.moduleView source
<?php
/**
* @file
* Prepopulate entity reference values from URL.
*/
/**
* Implements hook_ctools_plugin_directory().
*/
function entityreference_prepopulate_ctools_plugin_directory($module, $plugin) {
if ($module == 'entityreference' || $module == 'ctools') {
return 'plugins/' . $plugin;
}
}
/**
* Implements hook_theme().
*/
function entityreference_prepopulate_theme() {
return array(
'entityreference_prepopulate_providers_table' => array(
'render element' => 'form',
),
);
}
/**
* Implements hook_field_create_instance().
*
* Add "default value function" setting to the field instance.
* We have to do it from this hook, as we don't have another chance of setting
* this option via the hook_field_info().
*/
function entityreference_prepopulate_field_create_instance($instance) {
if (empty($instance['settings']['behaviors']['prepopulate']['status'])) {
return;
}
$instance['default_value_function'] = 'entityreference_prepopulate_field_default_value';
field_update_instance($instance);
}
/**
* Implements hook_field_update_instance().
*/
function entityreference_prepopulate_field_update_instance($instance, $prior_instance) {
if (empty($instance['settings']['behaviors']['prepopulate'])) {
return;
}
if (isset($prior_instance['settings']['behaviors']['prepopulate']['status']) && $instance['settings']['behaviors']['prepopulate']['status'] == $prior_instance['settings']['behaviors']['prepopulate']['status']) {
// Nothing changed.
return;
}
$instance['default_value_function'] = !empty($instance['settings']['behaviors']['prepopulate']['status']) ? 'entityreference_prepopulate_field_default_value' : '';
field_update_instance($instance);
}
/**
* Implements hook_field_attach_form().
*/
function entityreference_prepopulate_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
list($id, , $bundle) = entity_extract_ids($entity_type, $entity);
// Check if there is a field that needs to be prepopulated attached to the
// given entity.
$found = FALSE;
foreach (field_info_instances($entity_type, $bundle) as $instance) {
if (!empty($instance['settings']['behaviors']['prepopulate']['status'])) {
$found = TRUE;
break;
}
}
if (!$found) {
return;
}
foreach (element_children($form_state['field']) as $field_name) {
foreach ($form_state['field'][$field_name] as $lang => $value) {
$instance = $value['instance'];
if (empty($instance['settings']['behaviors']['prepopulate']['status'])) {
continue;
}
$settings = $instance['settings']['behaviors']['prepopulate'];
$field = $value['field'];
// Store prepopulated values in the form state to make them persistent,
// in case the form is rebuilt by AJAX requests.
$field_name = $field['field_name'];
if ($ids = entityreference_prepopulate_get_values($field, $instance)) {
$form_state['entityreference_prepopulate'][$instance['entity_type']][$instance['bundle']][$field_name] = $ids;
}
if (!empty($settings['skip_perm']) && user_access($settings['skip_perm']) || $id && empty($settings['action_on_edit'])) {
// User has access to skip the action, or the entity is already
// saved, but "Apply action on edit", is disabled.
continue;
}
if ($ids || $id && !empty($settings['action_on_edit'])) {
// New entity with prepopulate values, or an existing entity,
// we might need to disable/ hide the group-audience field.
if ($settings['action'] == 'disable') {
$form[$field_name][$lang]['#disabled'] = TRUE;
}
elseif ($settings['action'] == 'hide' && !$id) {
// For new entities we don't hide the field via hook_field_access(),
// as the default value won't be set. We use hook_field_access() only
// on existing ones.
$form[$field_name]['#access'] = FALSE;
}
}
elseif (in_array($settings['fallback'], array(
'form_error',
'redirect',
'hide',
))) {
$message = t('Field @label must be populated via URL.', array(
'@label' => $instance['label'],
));
if ($settings['fallback'] == 'form_error') {
form_error($form, $message);
}
elseif ($settings['fallback'] == 'redirect') {
drupal_set_message($message, 'notice');
drupal_goto();
}
elseif ($settings['fallback'] == 'hide') {
$form[$field_name]['#access'] = FALSE;
}
}
}
}
}
/**
* Implements hook_field_access().
*/
function entityreference_prepopulate_field_access($op, $field, $entity_type, $entity, $account) {
if ($op != 'edit' || $field['type'] != 'entityreference') {
return;
}
if (empty($entity)) {
// $entity might be NULL, so return early.
// @see field_access().
return;
}
list($id, , $bundle) = entity_extract_ids($entity_type, $entity);
$instance = field_info_instance($entity_type, $field['field_name'], $bundle);
if (empty($instance['settings']['behaviors']['prepopulate']['status'])) {
return;
}
$settings = $instance['settings']['behaviors']['prepopulate'];
if (!empty($settings['skip_perm']) && user_access($settings['skip_perm'])) {
return;
}
if ($id && empty($entity->is_new)) {
// The field need to be hidden when editing the entity.
return $settings['action'] == 'hide' && !empty($settings['action_on_edit']) ? FALSE : NULL;
}
if ($settings['action'] == 'hide') {
// If entity is already saved and not just inserted, deny access, otherwise
// ignore.
return $id && empty($entity->is_new) ? FALSE : NULL;
}
$ids = entityreference_prepopulate_get_values($field, $instance);
if (!$ids && $settings['fallback'] == 'hide') {
return FALSE;
}
}
/**
* Field default value callback.
*
* Set the default from the URL context. This works even if the widget is
* not shown, e.g. due to restricted field access.
*
* @todo Check field cardinality.
*/
function entityreference_prepopulate_field_default_value($entity_type, $entity, $field, $instance, $langcode) {
$items = array();
if ($ids = entityreference_prepopulate_get_values($field, $instance)) {
$items = array();
foreach ($ids as $id) {
$items[] = array(
'target_id' => $id,
);
}
}
return $items;
}
/**
* Wrapper function to get context (e.g. from URL or OG-context).
*
* @param $entity_type
* The entity type the entity.
* @param $entity
* The entity object that is being checked.
* @param $field
* The field info array.
* @param $instance
* The instance info array.
* @param $validate
* Determine if access validation should be performed. Defaults to TRUE.
*
* @return
* Array of IDs a user may view.
*/
function entityreference_prepopulate_get_values($field, $instance, $validate = TRUE) {
if (!$instance['settings']['behaviors']['prepopulate']['status']) {
// Do nothing when prepopulate is disabled for this field.
return;
}
$field_name = $field['field_name'];
$cache =& drupal_static(__FUNCTION__, array());
$identifier = array(
$instance['entity_type'],
$instance['bundle'],
$field_name,
$validate,
);
$is_audience_field = module_exists('og') && og_is_group_audience_field($field_name);
// Add field mode to ID if the audience field has one.
if ($is_audience_field && !empty($instance['field_mode'])) {
$identifier[] = $instance['field_mode'];
}
$identifier = implode(':', $identifier);
if (isset($cache[$identifier])) {
return $cache[$identifier];
}
if ($is_audience_field && empty($instance['field_mode'])) {
// Group audience field, but no field-mode provided.
// So we iterate over the "default" and possibly "admin" field-modes,
// and return those values together.
$ids = array();
$field_modes = !user_access('administer group') ? array(
'default',
) : array(
'default',
'admin',
);
foreach ($field_modes as $field_mode) {
$instance['field_mode'] = $field_mode;
if ($og_ids = entityreference_prepopulate_get_values($field, $instance)) {
$ids = array_merge($ids, $og_ids);
}
}
// Cache and return the values.
return $cache[$identifier] = $ids;
}
$cache[$identifier] = $ids = array();
// Check if we have cached values.
if (!($ids = entityreference_prepopulate_get_values_from_cache($field, $instance))) {
// Get the providers.
$enabled_providers = !empty($instance['settings']['behaviors']['prepopulate']['providers']) ? array_filter($instance['settings']['behaviors']['prepopulate']['providers']) : array();
if (!$enabled_providers) {
// If the instance isn't updated yet, we assume the URL provider is enabled.
$enabled_providers += array(
'url' => TRUE,
);
}
// For backwards compatibility with version 1.4, we check the "og_context"
// property.
if (!empty($instance['settings']['behaviors']['prepopulate']['og_context'])) {
$enabled_providers += array(
'og_context' => TRUE,
);
}
$providers = entityreference_prepopulate_providers_info();
foreach (array_keys($enabled_providers) as $name) {
if (empty($providers[$name]) || !empty($providers[$name]['disabled'])) {
// Provider doesn't exist any more or is disabled.
continue;
}
$provider = $providers[$name];
$function = $provider['callback'];
if ($ids = $function($field, $instance)) {
// We found values, so we can break.
break;
}
}
}
if (!$ids || !$validate) {
// No IDs found, or no validation is needed.
$cache[$identifier] = $ids;
return $ids;
}
$handler = entityreference_get_selection_handler($field, $instance);
if (!($valid_ids = $handler
->validateReferencableEntities($ids))) {
$cache[$identifier] = FALSE;
return;
}
// Only include valid ids.
$ids = array_intersect($ids, $valid_ids);
// Check access to the provided entities.
$target_type = $field['settings']['target_type'];
entity_load($target_type, $ids);
foreach ($ids as $delta => $id) {
$entity = entity_load_single($target_type, $id);
if (!$entity || !entity_access('view', $target_type, $entity)) {
unset($ids[$delta]);
}
}
$cache[$identifier] = $ids;
return $ids;
}
/**
* Get the values from the cached form.
*
* @param $field
* The field info array.
* @param $instance
* The instance info array.
*
* @see
* entityreference_prepopulate_get_values()
*/
function entityreference_prepopulate_get_values_from_cache($field, $instance) {
// Try to get the form out of cache.
if (!($form_build_id = isset($_GET['form_build_id']) ? $_GET['form_build_id'] : isset($_POST['form_build_id']) ? $_POST['form_build_id'] : NULL)) {
return;
}
$field_name = $field['field_name'];
$form_state = array();
form_get_cache($form_build_id, $form_state);
// If successful, get the value from the form_state.
return isset($form_state['entityreference_prepopulate'][$instance['entity_type']][$instance['bundle']][$field_name]) ? $form_state['entityreference_prepopulate'][$instance['entity_type']][$instance['bundle']][$field_name] : FALSE;
}
/**
* Get values for prepopulating fields via URL.
*
* @param $field
* The field info array.
* @param $instance
* The instance info array.
*
* @see
* entityreference_prepopulate_get_values()
*/
function entityreference_prepopulate_get_values_from_url($field, $instance) {
$settings = $instance['settings']['behaviors']['prepopulate'];
$field_identifier = empty($settings['identifier']) ? $field['field_name'] : $settings['identifier'];
if (!empty($_GET[$field_identifier]) && is_string($_GET[$field_identifier])) {
return explode(',', $_GET[$field_identifier]);
}
}
/**
* Get values for prepopulating fields OG-context.
*
* @param $field
* The field info array.
* @param $instance
* The instance info array.
*
* @see
* entityreference_prepopulate_get_values()
*/
function entityreference_prepopulate_get_values_from_og_context($field, $instance) {
$field_name = $field['field_name'];
if (!module_exists('og_context') || !($og_context = og_context())) {
return;
}
if ($og_context['group_type'] != $field['settings']['target_type']) {
// Context is of invalid group-type.
return;
}
return array(
$og_context['gid'],
);
}
/**
* Return a form element with crafted links to create nodes for a group.
*
* @param $entity_type
* The entity type of the referenced entity.
* @param $entity_id
* The entity ID of the referenced entity.
* @param $destination
* Optional; The destination after a node is created. Defaults to the
* destination passed in the URL if exists, otherwise back to the current
* page.
* @param $types
* Optional; An array of type names. Restrict the created links to the given
* types.
*/
function entityreference_prepopulate_create_node_links($entity_type, $entity_id, $field_name, $destination = NULL, $types = NULL) {
$wrapper = entity_metadata_wrapper($entity_type, $entity_id);
$field = field_info_field($field_name);
$entity = entity_load_single($entity_type, $entity_id);
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
$types = isset($types) ? $types : array_keys(node_type_get_types());
$names = array();
foreach ($types as $type_name) {
if ($field['settings']['target_type'] != $entity_type) {
// The entity type isn't referenced by the field.
continue;
}
if (!empty($field['settings']['handler_settings']['target_bundles']) && !in_array($bundle, $field['settings']['handler_settings']['target_bundles'])) {
// The entity bundle isn't referenced by the field.
continue;
}
$instance = field_info_instance('node', $field_name, $type_name);
if (empty($instance['settings']['behaviors']['prepopulate']['status'])) {
// The field doesn't exist on the node type, or doesn't have prepopulate
// enabled.
continue;
}
if (!node_access('create', $type_name)) {
continue;
}
$names[$type_name] = node_type_get_name($type_name);
}
if (empty($names)) {
return;
}
// Sort names.
asort($names);
// Build links.
$options = array(
'query' => array(
$field_name => $entity_id,
) + drupal_get_destination(),
);
$items = array();
foreach ($names as $type => $name) {
$items[] = array(
'data' => l($name, 'node/add/' . str_replace('_', '-', $type), $options),
);
}
$element = array();
$element['entityreference_prepopulate'] = array(
'#theme' => 'item_list',
'#items' => $items,
);
return $element;
}
/**
* Return array of providers.
*/
function entityreference_prepopulate_providers_info() {
$description = t('Determine if values that should be prepopulated should "listen" to the OG-context.');
if ($disabled = !module_exists('og_context')) {
$description .= '<br / >' . t('Organic groups integration: Enable OG-context module.');
}
$providers = array(
'url' => array(
'title' => t('URL'),
'description' => t('Prepopulate from URL'),
'callback' => 'entityreference_prepopulate_get_values_from_url',
),
'og_context' => array(
'title' => t('OG Context'),
'description' => $description,
'disabled' => $disabled,
'callback' => 'entityreference_prepopulate_get_values_from_og_context',
),
);
$providers = array_merge($providers, module_invoke_all('entityreference_prepopulate_providers_info'));
// Allow other module to change the providers list.
drupal_alter('entityreference_prepopulate_providers_info', $providers);
return $providers;
}