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);
}
/**
* 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.
*/
function entityreference_prepopulate_field_default_value($entity_type, $entity, $field, $instance, $langcode) {
Amitai Burstein
committed
if (module_exists('og') && og_is_group_audience_field($instance['field_name'])) {
return entityreference_prepopulate_og_field_default_value($entity_type, $entity, $field, $instance, $langcode);
}
if ($items = entityreference_prepopulate_get_values($field, $instance)) {
Amitai Burstein
committed
/**
* Default value callback for Organic groups; Filter results by field-mode.
*/
function entityreference_prepopulate_og_field_default_value($entity_type, $entity, $field, $instance, $langcode) {
if (empty($instance['field_mode'])) {
Amitai Burstein
committed
return array();
Amitai Burstein
committed
}
if ($items = entityreference_prepopulate_get_values($field, $instance)) {
Amitai Burstein
committed
// Filter out the items that don't match the field-mode.
$gids = array();
foreach ($items as $item) {
$gids[] = $item['target_id'];
}
if (!$valid_ids = entityreference_get_selection_handler($field, $instance, $entity_type, $entity)->validateReferencableEntities($gids)) {
return;
}
$valid_items = array();
foreach ($valid_ids as $valid_id) {
$valid_items[] = array('target_id' => $valid_id);
}
return $valid_items;
}
}
/**
* 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.
if ($values = entityreference_prepopulate_get_values($field, $instance)) {
$form_state['entityreference_prepopulate'][$instance['entity_type']][$instance['bundle']][$field['field_name']] = $values;
}
if ($values || ($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;
}
$items = entityreference_prepopulate_get_values($field, $instance);
Amitai Burstein
committed
if (empty($items) && $settings['fallback'] == 'hide') {
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/**
* Wrapper function to get context (e.g. from URL or OG-context).
*
* @param $field
* The field info array.
* @param $instance
* The instance info array.
* @param $flat_array.
* TRUE if the group IDs should be sent as a simple array. FALSE, if we
* need to build array suited for field API's $items value.
*/
function entityreference_prepopulate_get_values($field, $instance, $flat_array = FALSE) {
$settings = $instance['settings']['behaviors']['prepopulate'];
if (!empty($settings['og_context']) && module_exists('og_context')) {
return entityreference_prepopulate_get_values_from_og_context($field, $instance, $flat_array);
}
return entityreference_prepopulate_get_values_from_url($field, $instance, $flat_array);
}
function entityreference_prepopulate_get_values_from_og_context($field, $instance, $flat_array = FALSE) {
$field_name = $field['field_name'];
if (!og_is_group_audience_field($field_name) || !$og_context = og_context()) {
return;
}
if ($og_context['group_type'] != $field['settings']['target_type']) {
// Context is of invalid group-type.
return;
}
$items = array();
$items[] = !$flat_array ? array('target_id' => $og_context['gid']) : $og_context['gid'];
return $items;
}
/**
* Get values for prepopulating fields, via URL.
*
* @param $field
* The field info array.
* @param $instance
* The instance info array.
Amitaibu
committed
* @param $flat_array.
* TRUE if the group IDs should be sent as a simple array. FALSE, if we
* need to build array suited for field API's $items value.
*
* @see
* entityreference_prepopulate_get_values()
Amitaibu
committed
function entityreference_prepopulate_get_values_from_url($field, $instance, $flat_array = FALSE) {
$cache = &drupal_static(__FUNCTION__, array());
$field_name = $field['field_name'];
Amitaibu
committed
$identifier = $instance['entity_type'] . ':' . $instance['bundle'] . ':' . $field_name . ':' . $flat_array;
if (isset($cache[$identifier])) {
return $cache[$identifier];
}
// Do nothing when prepopulate is disabled for this field.
if (!$instance['settings']['behaviors']['prepopulate']['status']) {
Amitai Burstein
committed
$cache[$identifier] = FALSE;
// Get the value from the URL if possible.
if (!empty($_GET[$field_name]) && is_string($_GET[$field_name])) {
Amitai Burstein
committed
$ids = explode(',', $_GET[$field_name]);
}
else {
// Try to get the form out of cache.
$form_build_id = isset($_GET['form_build_id']) ? $_GET['form_build_id'] : isset($_POST['form_build_id']) ? $_POST['form_build_id'] : NULL;
$form_state = array();
$form = form_get_cache($form_build_id, $form_state);
// If successful, get the value from the form_state.
if (isset($form_state['entityreference_prepopulate'][$instance['entity_type']][$instance['bundle']][$field_name])) {
$ids = $form_state['entityreference_prepopulate'][$instance['entity_type']][$instance['bundle']][$field_name];
}
// If not, do nothing and return.
else {
$cache[$identifier] = FALSE;
return;
}
a.ross
committed
}
// Check if the IDs are valid, and filter out the invalid ones.
$handler = entityreference_get_selection_handler($field, $instance);
if (!$ids = $handler->validateReferencableEntities($ids)) {
a.ross
committed
$cache[$identifier] = FALSE;
Amitaibu
committed
// Check access to the provided entities.
$target_type = $field['settings']['target_type'];
entity_load($target_type, $ids);
$items = array();
foreach ($ids as $id) {
$entity = entity_load_single($target_type, $id);
if (entity_access('view', $target_type, $entity)) {
Amitaibu
committed
$items[] = !$flat_array ? array('target_id' => $id) : $id;
/**
* 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.
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
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;
}