Newer
Older
<?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_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);
}
/**
*/
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);
if (!empty($form_state['triggering_element']['#ajax'])) {
// We are inside AJAX, so values can't be taken from URL at the
// moment.
Amitaibu
committed
// 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'];
if ((!empty($settings['skip_perm']) && user_access($settings['skip_perm'])) || ($id && empty($settings['action_on_edit']))) {
Amir Arbel
committed
// User has access to skip the action, or the entity is already
// saved, but "Apply action on edit", is disabled.
continue;
}
$field = $value['field'];
Amitai Burstein
committed
// Store prepopulated values in the form state to make them persistent,
// in case the form is rebuilt by AJAX requests.
Amitai Burstein
committed
if ($ids = entityreference_prepopulate_get_values($field, $instance)) {
$form_state['entityreference_prepopulate'][$instance['entity_type']][$instance['bundle']][$field['field_name']] = $ids;
Amitai Burstein
committed
}
Amitai Burstein
committed
if ($ids || ($id && !empty($settings['action_on_edit']))) {
Amir Arbel
committed
// New entity with prepopualte 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;
}
Amitai Burstein
committed
elseif ($settings['action'] == 'hide') {
// We don't hide the field via hook_field_access(), as the
// default value won't be set.
Amitai Burstein
committed
}
Amitai Burstein
committed
elseif (in_array($settings['fallback'], array('form_error', 'redirect'))) {
$message = t('Field @label must be populated via URL.', array('@label' => $instance['label']));
Amitai Burstein
committed
if ($settings['fallback'] == 'form_error') {
form_error($form, $message);
}
elseif ($settings['fallback'] == 'redirect') {
drupal_set_message($message, 'notice');
drupal_goto();
}
}
}
}
}
/**
* 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);
if ($id) {
// Entity is already saved.
return;
}
$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;
}
Amitai Burstein
committed
$ids = entityreference_prepopulate_get_values($field, $instance);
Amitai Burstein
committed
if (!$ids && $settings['fallback'] == 'hide') {
Amitai Burstein
committed
/**
* 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).
*
Amitai Burstein
committed
* @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.
Amitai Burstein
committed
* @param $validate
* Determine if access validation should be performed. Defaults to TRUE.
*
* @return
* Array of IDs a user may view.
Amitai Burstein
committed
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'];
Amitai Burstein
committed
$cache = &drupal_static(__FUNCTION__, array());
$identifier = array(
$instance['entity_type'],
$instance['bundle'],
$field_name,
$validate,
);
if (module_exists('og') && og_is_group_audience_field($field_name)) {
// Group audience field, but no field-mode provided.
$identifier[] = !empty($instance['field_mode']) ? $instance['field_mode'] : FALSE;
Amitai Burstein
committed
$identifier = implode(':', $identifier);
Amitai Burstein
committed
if (isset($cache[$identifier])) {
return $cache[$identifier];
}
Amitai Burstein
committed
$cache[$identifier] = $ids = array();
// Check if we have cached values.
if (!$ids) {
$ids = entityreference_prepopulate_get_values_from_cache($field, $instance);
Amitai Burstein
committed
// Check if we have OG-context integration.
if (!$ids) {
$ids = entityreference_prepopulate_get_values_from_og_context($field, $instance);
}
// Check if there are values in the URL.
if (!$ids) {
$ids = entityreference_prepopulate_get_values_from_url($field, $instance);
}
if (!$ids || !$validate) {
// No IDs found, or no validation is needed.
$cache[$identifier] = $ids;
return $ids;
}
$handler = entityreference_get_selection_handler($field, $instance);
if (!$ids = $handler->validateReferencableEntities($ids)) {
$cache[$identifier] = FALSE;
return;
}
Amitai Burstein
committed
// 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;
Amitai Burstein
committed
* Get the values from the cached form.
*
* @param $field
* The field info array.
* @param $instance
* The instance info array.
*
* @see
* entityreference_prepopulate_get_values()
Amitai Burstein
committed
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) {
Amitai Burstein
committed
$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) {
$field_name = $field['field_name'];
if (!empty($_GET[$field_name]) && is_string($_GET[$field_name])) {
Amitai Burstein
committed
return explode(',', $_GET[$field_name]);
a.ross
committed
}
Amitai Burstein
committed
}
a.ross
committed
Amitai Burstein
committed
/**
* 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'];
Amitai Burstein
committed
Amitai Burstein
committed
if (!module_exists('og_context') || !og_is_group_audience_field($field_name) || !$og_context = og_context()) {
return;
Amitai Burstein
committed
if ($og_context['group_type'] != $field['settings']['target_type']) {
// Context is of invalid group-type.
return;
}
return array($og_context['gid']);
Amitai Burstein
committed
/**
* 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);
Amitaibu
committed
$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) {
Amitaibu
committed
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.
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
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;
}