Projet

Général

Profil

Paste
Télécharger (48,1 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / entityreference / entityreference.module @ 59ae487e

1 85ad3d82 Assos Assos
<?php
2
3 b1ab1c0c Assos Assos
/**
4
 * @file
5
 * Entityreference primary module file.
6
 */
7
8 85ad3d82 Assos Assos
/**
9
 * Implements hook_ctools_plugin_directory().
10
 */
11
function entityreference_ctools_plugin_directory($module, $plugin) {
12
  if ($module == 'entityreference') {
13
    return 'plugins/' . $plugin;
14
  }
15
}
16
17
/**
18
 * Implements hook_init().
19
 */
20
function entityreference_init() {
21
  // Include feeds.module integration.
22
  if (module_exists('feeds')) {
23
    module_load_include('inc', 'entityreference', 'entityreference.feeds');
24
  }
25
}
26
27
/**
28
 * Implements hook_ctools_plugin_type().
29
 */
30
function entityreference_ctools_plugin_type() {
31
  $plugins['selection'] = array(
32
    'classes' => array('class'),
33
  );
34
  $plugins['behavior'] = array(
35
    'classes' => array('class'),
36
    'process' => 'entityreference_behavior_plugin_process',
37
  );
38
  return $plugins;
39
}
40
41
/**
42
 * CTools callback; Process the behavoir plugins.
43
 */
44
function entityreference_behavior_plugin_process(&$plugin, $info) {
45
  $plugin += array(
46
    'description' => '',
47
    'behavior type' => 'field',
48
    'access callback' => FALSE,
49
    'force enabled' => FALSE,
50
  );
51
}
52
53
/**
54
 * Implements hook_field_info().
55
 */
56
function entityreference_field_info() {
57
  $field_info['entityreference'] = array(
58
    'label' => t('Entity Reference'),
59
    'description' => t('This field reference another entity.'),
60
    'settings' => array(
61
      // Default to the core target entity type node.
62
      'target_type' => 'node',
63
      // The handler for this field.
64
      'handler' => 'base',
65
      // The handler settings.
66
      'handler_settings' => array(),
67
    ),
68
    'instance_settings' => array(),
69
    'default_widget' => 'entityreference_autocomplete',
70
    'default_formatter' => 'entityreference_label',
71
    'property_callbacks' => array('entityreference_field_property_callback'),
72
  );
73
  return $field_info;
74
}
75
76
/**
77
 * Implements hook_flush_caches().
78
 */
79
function entityreference_flush_caches() {
80
  // Because of the intricacies of the info hooks, we are forced to keep a
81
  // separate list of the base tables of each entities, so that we can use
82
  // it in entityreference_field_schema() without calling entity_get_info().
83
  // See http://drupal.org/node/1416558 for details.
84
  $base_tables = array();
85
  foreach (entity_get_info() as $entity_type => $entity_info) {
86
    if (!empty($entity_info['base table']) && !empty($entity_info['entity keys']['id'])) {
87
      $base_tables[$entity_type] = array($entity_info['base table'], $entity_info['entity keys']['id']);
88
    }
89
  }
90
  // We are using a variable because cache is going to be cleared right after
91
  // hook_flush_caches() is finished.
92
  variable_set('entityreference:base-tables', $base_tables);
93
}
94
95 b1ab1c0c Assos Assos
/**
96
 * Implements hook_theme().
97
 */
98
function entityreference_theme($existing, $type, $theme, $path) {
99
  return array(
100
    'entityreference_label' => array(
101
      'variables' => array('label' => NULL, 'item' => NULL, 'settings' => NULL, 'uri' => NULL),
102
    ),
103
    'entityreference_entity_id' => array(
104
      'variables' => array('item' => NULL, 'settings' => NULL),
105
    ),
106
  );
107
}
108
109 85ad3d82 Assos Assos
/**
110
 * Implements hook_menu().
111
 */
112
function entityreference_menu() {
113
  $items = array();
114
115
  $items['entityreference/autocomplete/single/%/%/%'] = array(
116
    'title' => 'Entity Reference Autocomplete',
117
    'page callback' => 'entityreference_autocomplete_callback',
118
    'page arguments' => array(2, 3, 4, 5),
119
    'access callback' => 'entityreference_autocomplete_access_callback',
120
    'access arguments' => array(2, 3, 4, 5),
121
    'type' => MENU_CALLBACK,
122
  );
123
  $items['entityreference/autocomplete/tags/%/%/%'] = array(
124
    'title' => 'Entity Reference Autocomplete',
125
    'page callback' => 'entityreference_autocomplete_callback',
126
    'page arguments' => array(2, 3, 4, 5),
127
    'access callback' => 'entityreference_autocomplete_access_callback',
128
    'access arguments' => array(2, 3, 4, 5),
129
    'type' => MENU_CALLBACK,
130
  );
131
132
  return $items;
133
}
134
135
/**
136
 * Implements hook_field_is_empty().
137
 */
138
function entityreference_field_is_empty($item, $field) {
139
  $empty = !isset($item['target_id']) || !is_numeric($item['target_id']);
140
141
  // Invoke the behaviors to allow them to override the empty status.
142
  foreach (entityreference_get_behavior_handlers($field) as $handler) {
143
    $handler->is_empty_alter($empty, $item, $field);
144
  }
145
  return $empty;
146
}
147
148
/**
149
 * Get the behavior handlers for a given entityreference field.
150
 */
151
function entityreference_get_behavior_handlers($field, $instance = NULL) {
152
  $object_cache = drupal_static(__FUNCTION__);
153
  $identifier = $field['field_name'];
154
  if (!empty($instance)) {
155
    $identifier .= ':' . $instance['entity_type'] . ':' . $instance['bundle'];
156
  }
157
158
  if (!isset($object_cache[$identifier])) {
159
    $object_cache[$identifier] = array();
160
161
    // Merge in defaults.
162
    $field['settings'] += array('behaviors' => array());
163
164
    $object_cache[$field['field_name']] = array();
165
    $behaviors = !empty($field['settings']['handler_settings']['behaviors']) ? $field['settings']['handler_settings']['behaviors'] : array();
166
    if (!empty($instance['settings']['behaviors'])) {
167
      $behaviors = array_merge($behaviors, $instance['settings']['behaviors']);
168
    }
169
    foreach ($behaviors as $behavior => $settings) {
170
      if (empty($settings['status'])) {
171
        // Behavior is not enabled.
172
        continue;
173
      }
174
175
      $object_cache[$identifier][] = _entityreference_get_behavior_handler($behavior);
176
    }
177
  }
178
179
  return $object_cache[$identifier];
180
}
181
182
/**
183
 * Get the behavior handler for a given entityreference field and instance.
184
 *
185 b1ab1c0c Assos Assos
 * @param $behavior
186 85ad3d82 Assos Assos
 *   The behavior handler name.
187
 */
188
function _entityreference_get_behavior_handler($behavior) {
189
  $object_cache = drupal_static(__FUNCTION__);
190
191
  if (!isset($object_cache[$behavior])) {
192
    ctools_include('plugins');
193
    $class = ctools_plugin_load_class('entityreference', 'behavior', $behavior, 'class');
194
195
    $class = class_exists($class) ? $class : 'EntityReference_BehaviorHandler_Broken';
196
    $object_cache[$behavior] = new $class($behavior);
197
  }
198
199
  return $object_cache[$behavior];
200
}
201
202
/**
203
 * Get the selection handler for a given entityreference field.
204
 */
205
function entityreference_get_selection_handler($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
206
  ctools_include('plugins');
207
  $handler = $field['settings']['handler'];
208
  $class = ctools_plugin_load_class('entityreference', 'selection', $handler, 'class');
209
210
  if (class_exists($class)) {
211
    return call_user_func(array($class, 'getInstance'), $field, $instance, $entity_type, $entity);
212
  }
213
  else {
214
    return EntityReference_SelectionHandler_Broken::getInstance($field, $instance, $entity_type, $entity);
215
  }
216
}
217
218
/**
219
 * Implements hook_field_load().
220
 */
221
function entityreference_field_load($entity_type, $entities, $field, $instances, $langcode, &$items) {
222
  // Invoke the behaviors.
223
  foreach (entityreference_get_behavior_handlers($field) as $handler) {
224
    $handler->load($entity_type, $entities, $field, $instances, $langcode, $items);
225
  }
226
}
227
228
/**
229
 * Implements hook_field_validate().
230
 */
231
function entityreference_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
232
  $ids = array();
233
  foreach ($items as $delta => $item) {
234
    if (!entityreference_field_is_empty($item, $field) && $item['target_id'] !== NULL) {
235
      $ids[$item['target_id']] = $delta;
236
    }
237
  }
238
239
  if ($ids) {
240
    $valid_ids = entityreference_get_selection_handler($field, $instance, $entity_type, $entity)->validateReferencableEntities(array_keys($ids));
241
242 56aebcb7 Assos Assos
    if (!empty($valid_ids)) {
243
      $invalid_entities = array_diff_key($ids, array_flip($valid_ids));
244
      if ($invalid_entities) {
245
        foreach ($invalid_entities as $id => $delta) {
246
          $errors[$field['field_name']][$langcode][$delta][] = array(
247
            'error' => 'entityreference_invalid_entity',
248
            'message' => t('The referenced entity (@type: @id) is invalid.', array('@type' => $field['settings']['target_type'], '@id' => $id)),
249
          );
250
        }
251 85ad3d82 Assos Assos
      }
252
    }
253
  }
254
255
  // Invoke the behaviors.
256
  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
257
    $handler->validate($entity_type, $entity, $field, $instance, $langcode, $items, $errors);
258
  }
259
}
260
261
/**
262
 * Implements hook_field_presave().
263
 *
264
 * Adds the target type to the field data structure when saving.
265
 */
266
function entityreference_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
267
  // Invoke the behaviors.
268
  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
269
    $handler->presave($entity_type, $entity, $field, $instance, $langcode, $items);
270
  }
271
}
272
273
/**
274
 * Implements hook_field_insert().
275
 */
276
function entityreference_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
277
  // Invoke the behaviors.
278
  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
279
    $handler->insert($entity_type, $entity, $field, $instance, $langcode, $items);
280
  }
281
}
282
283
/**
284
 * Implements hook_field_attach_insert().
285
 *
286
 * Emulates a post-insert hook.
287
 */
288
function entityreference_field_attach_insert($entity_type, $entity) {
289
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
290
  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
291
    $field = field_info_field($field_name);
292
    if ($field['type'] == 'entityreference') {
293
      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
294
        $handler->postInsert($entity_type, $entity, $field, $instance);
295
      }
296
    }
297
  }
298
}
299
300
/**
301
 * Implements hook_field_update().
302
 */
303
function entityreference_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
304
  // Invoke the behaviors.
305
  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
306
    $handler->update($entity_type, $entity, $field, $instance, $langcode, $items);
307
  }
308
}
309
310
/**
311
 * Implements hook_field_attach_update().
312
 *
313
 * Emulates a post-update hook.
314
 */
315
function entityreference_field_attach_update($entity_type, $entity) {
316
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
317
  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
318
    $field = field_info_field($field_name);
319
    if ($field['type'] == 'entityreference') {
320
      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
321
        $handler->postUpdate($entity_type, $entity, $field, $instance);
322
      }
323
    }
324
  }
325
}
326
327
/**
328
 * Implements hook_field_delete().
329
 */
330
function entityreference_field_delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
331
  // Invoke the behaviors.
332
  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
333
    $handler->delete($entity_type, $entity, $field, $instance, $langcode, $items);
334
  }
335
}
336
337
/**
338
 * Implements hook_field_attach_delete().
339
 *
340
 * Emulates a post-delete hook.
341
 */
342
function entityreference_field_attach_delete($entity_type, $entity) {
343
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
344
  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
345
    $field = field_info_field($field_name);
346
    if ($field['type'] == 'entityreference') {
347
      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
348
        $handler->postDelete($entity_type, $entity, $field, $instance);
349
      }
350
    }
351
  }
352
}
353
354
/**
355
 * Implements hook_entity_insert().
356
 */
357
function entityreference_entity_insert($entity, $entity_type) {
358
  entityreference_entity_crud($entity, $entity_type, 'entityPostInsert');
359
}
360
361
/**
362
 * Implements hook_entity_update().
363
 */
364
function entityreference_entity_update($entity, $entity_type) {
365
  entityreference_entity_crud($entity, $entity_type, 'entityPostUpdate');
366
}
367
368
/**
369
 * Implements hook_entity_delete().
370
 */
371
function entityreference_entity_delete($entity, $entity_type) {
372
  entityreference_entity_crud($entity, $entity_type, 'entityPostDelete');
373
}
374
375
/**
376
 * Invoke a behavior based on entity CRUD.
377
 *
378
 * @param $entity
379
 *   The entity object.
380
 * @param $entity_type
381
 *   The entity type.
382
 * @param $method_name
383
 *   The method to invoke.
384
 */
385
function entityreference_entity_crud($entity, $entity_type, $method_name) {
386
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
387
  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
388
    $field = field_info_field($field_name);
389
    if ($field['type'] == 'entityreference') {
390
      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
391
        $handler->{$method_name}($entity_type, $entity, $field, $instance);
392
      }
393
    }
394
  }
395
}
396
397
/**
398
 * Implements hook_field_settings_form().
399
 */
400
function entityreference_field_settings_form($field, $instance, $has_data) {
401
  // The field settings infrastructure is not AJAX enabled by default,
402
  // because it doesn't pass over the $form_state.
403
  // Build the whole form into a #process in which we actually have access
404
  // to the form state.
405
  $form = array(
406
    '#type' => 'container',
407
    '#attached' => array(
408
      'css' => array(drupal_get_path('module', 'entityreference') . '/entityreference.admin.css'),
409
    ),
410
    '#process' => array(
411
      '_entityreference_field_settings_process',
412
      '_entityreference_field_settings_ajax_process',
413
    ),
414
    '#element_validate' => array('_entityreference_field_settings_validate'),
415
    '#field' => $field,
416
    '#instance' => $instance,
417
    '#has_data' => $has_data,
418
  );
419
  return $form;
420
}
421
422 b1ab1c0c Assos Assos
/**
423
 * Callback for custom element processing.
424
 */
425 85ad3d82 Assos Assos
function _entityreference_field_settings_process($form, $form_state) {
426
  $field = isset($form_state['entityreference']['field']) ? $form_state['entityreference']['field'] : $form['#field'];
427
  $instance = isset($form_state['entityreference']['instance']) ? $form_state['entityreference']['instance'] : $form['#instance'];
428
  $has_data = $form['#has_data'];
429
430
  $settings = $field['settings'];
431
  $settings += array('handler' => 'base');
432
433
  // Select the target entity type.
434
  $entity_type_options = array();
435
  foreach (entity_get_info() as $entity_type => $entity_info) {
436
    $entity_type_options[$entity_type] = $entity_info['label'];
437
  }
438
439
  $form['target_type'] = array(
440
    '#type' => 'select',
441
    '#title' => t('Target type'),
442
    '#options' => $entity_type_options,
443
    '#default_value' => $field['settings']['target_type'],
444
    '#required' => TRUE,
445
    '#description' => t('The entity type that can be referenced through this field.'),
446
    '#disabled' => $has_data,
447
    '#size' => 1,
448
    '#ajax' => TRUE,
449
    '#limit_validation_errors' => array(),
450
  );
451
452
  ctools_include('plugins');
453
  $handlers = ctools_get_plugins('entityreference', 'selection');
454
  uasort($handlers, 'ctools_plugin_sort');
455
  $handlers_options = array();
456
  foreach ($handlers as $handler => $handler_info) {
457
    $handlers_options[$handler] = check_plain($handler_info['title']);
458
  }
459
460
  $form['handler'] = array(
461
    '#type' => 'fieldset',
462
    '#title' => t('Entity selection'),
463
    '#tree' => TRUE,
464
    '#process' => array('_entityreference_form_process_merge_parent'),
465
  );
466
467
  $form['handler']['handler'] = array(
468
    '#type' => 'select',
469
    '#title' => t('Mode'),
470
    '#options' => $handlers_options,
471
    '#default_value' => $settings['handler'],
472
    '#required' => TRUE,
473
    '#ajax' => TRUE,
474
    '#limit_validation_errors' => array(),
475
  );
476
  $form['handler_submit'] = array(
477
    '#type' => 'submit',
478
    '#value' => t('Change handler'),
479
    '#limit_validation_errors' => array(),
480
    '#attributes' => array(
481
      'class' => array('js-hide'),
482
    ),
483
    '#submit' => array('entityreference_settings_ajax_submit'),
484
  );
485
486
  $form['handler']['handler_settings'] = array(
487
    '#type' => 'container',
488
    '#attributes' => array('class' => array('entityreference-settings')),
489
  );
490
491
  $handler = entityreference_get_selection_handler($field, $instance);
492
  $form['handler']['handler_settings'] += $handler->settingsForm($field, $instance);
493
494
  _entityreference_get_behavior_elements($form, $field, $instance, 'field');
495
  if (!empty($form['behaviors'])) {
496
    $form['behaviors'] += array(
497
      '#type' => 'fieldset',
498
      '#title' => t('Additional behaviors'),
499
      '#parents' => array_merge($form['#parents'], array('handler_settings', 'behaviors')),
500
    );
501
  }
502
503
  return $form;
504
}
505
506 b1ab1c0c Assos Assos
/**
507
 * Custom callback for ajax processing.
508
 */
509 85ad3d82 Assos Assos
function _entityreference_field_settings_ajax_process($form, $form_state) {
510
  _entityreference_field_settings_ajax_process_element($form, $form);
511
  return $form;
512
}
513
514 b1ab1c0c Assos Assos
/**
515
 * Helper function for custom ajax processing.
516
 */
517 85ad3d82 Assos Assos
function _entityreference_field_settings_ajax_process_element(&$element, $main_form) {
518
  if (isset($element['#ajax']) && $element['#ajax'] === TRUE) {
519
    $element['#ajax'] = array(
520
      'callback' => 'entityreference_settings_ajax',
521
      'wrapper' => $main_form['#id'],
522
      'element' => $main_form['#array_parents'],
523
    );
524
  }
525
526
  foreach (element_children($element) as $key) {
527
    _entityreference_field_settings_ajax_process_element($element[$key], $main_form);
528
  }
529
}
530
531 b1ab1c0c Assos Assos
/**
532
 * Custom callback for element processing.
533
 */
534 85ad3d82 Assos Assos
function _entityreference_form_process_merge_parent($element) {
535
  $parents = $element['#parents'];
536
  array_pop($parents);
537
  $element['#parents'] = $parents;
538
  return $element;
539
}
540
541 b1ab1c0c Assos Assos
/**
542
 * Helper function to remove blank elements.
543
 */
544 85ad3d82 Assos Assos
function _entityreference_element_validate_filter(&$element, &$form_state) {
545
  $element['#value'] = array_filter($element['#value']);
546
  form_set_value($element, $element['#value'], $form_state);
547
}
548
549 b1ab1c0c Assos Assos
/**
550
 * Implements hook_validate().
551
 */
552 85ad3d82 Assos Assos
function _entityreference_field_settings_validate($form, &$form_state) {
553
  // Store the new values in the form state.
554
  $field = $form['#field'];
555
  if (isset($form_state['values']['field'])) {
556
    $field['settings'] = $form_state['values']['field']['settings'];
557
  }
558
  $form_state['entityreference']['field'] = $field;
559
560
  unset($form_state['values']['field']['settings']['handler_submit']);
561
}
562
563
/**
564
 * Implements hook_field_instance_settings_form().
565
 */
566
function entityreference_field_instance_settings_form($field, $instance) {
567
  $form['settings'] = array(
568
    '#type' => 'container',
569
    '#attached' => array(
570
      'css' => array(drupal_get_path('module', 'entityreference') . '/entityreference.admin.css'),
571
    ),
572
    '#weight' => 10,
573
    '#tree' => TRUE,
574
    '#process' => array(
575
      '_entityreference_form_process_merge_parent',
576
      '_entityreference_field_instance_settings_form',
577
      '_entityreference_field_settings_ajax_process',
578
    ),
579
    '#element_validate' => array('_entityreference_field_instance_settings_validate'),
580
    '#field' => $field,
581
    '#instance' => $instance,
582
  );
583
584
  return $form;
585
}
586
587 b1ab1c0c Assos Assos
/**
588
 * Implements hook_field_settings_form().
589
 */
590 85ad3d82 Assos Assos
function _entityreference_field_instance_settings_form($form, $form_state) {
591
  $field = isset($form_state['entityreference']['field']) ? $form_state['entityreference']['field'] : $form['#field'];
592
  $instance = isset($form_state['entityreference']['instance']) ? $form_state['entityreference']['instance'] : $form['#instance'];
593
594
  _entityreference_get_behavior_elements($form, $field, $instance, 'instance');
595
  if (!empty($form['behaviors'])) {
596
    $form['behaviors'] += array(
597
      '#type' => 'fieldset',
598
      '#title' => t('Additional behaviors'),
599
      '#process' => array(
600
        '_entityreference_field_settings_ajax_process',
601
      ),
602
    );
603
  }
604
  return $form;
605
}
606
607 b1ab1c0c Assos Assos
/**
608
 * Implements hook_validate().
609
 */
610 85ad3d82 Assos Assos
function _entityreference_field_instance_settings_validate($form, &$form_state) {
611
  // Store the new values in the form state.
612
  $instance = $form['#instance'];
613
  if (isset($form_state['values']['instance'])) {
614
    $instance = drupal_array_merge_deep($instance, $form_state['values']['instance']);
615
  }
616
  $form_state['entityreference']['instance'] = $instance;
617
}
618
619
/**
620
 * Get the field or instance elements for the field configuration.
621
 */
622
function _entityreference_get_behavior_elements(&$element, $field, $instance, $level) {
623
  // Add the accessible behavior handlers.
624
  $behavior_plugins = entityreference_get_accessible_behavior_plugins($field, $instance);
625
626
  if ($behavior_plugins[$level]) {
627
    $element['behaviors'] = array();
628
629
    foreach ($behavior_plugins[$level] as $name => $plugin) {
630
      if ($level == 'field') {
631
        $settings = !empty($field['settings']['handler_settings']['behaviors'][$name]) ? $field['settings']['handler_settings']['behaviors'][$name] : array();
632
      }
633
      else {
634
        $settings = !empty($instance['settings']['behaviors'][$name]) ? $instance['settings']['behaviors'][$name] : array();
635
      }
636
      $settings += array('status' => $plugin['force enabled']);
637
638
      // Render the checkbox.
639
      $element['behaviors'][$name] = array(
640
        '#tree' => TRUE,
641
      );
642
      $element['behaviors'][$name]['status'] = array(
643
        '#type' => 'checkbox',
644
        '#title' => check_plain($plugin['title']),
645
        '#description' => $plugin['description'],
646
        '#default_value' => $settings['status'],
647
        '#disabled' => $plugin['force enabled'],
648
        '#ajax' => TRUE,
649
      );
650
651
      if ($settings['status']) {
652
        $handler = _entityreference_get_behavior_handler($name);
653
        if ($behavior_elements = $handler->settingsForm($field, $instance)) {
654
          foreach ($behavior_elements as $key => &$behavior_element) {
655
            $behavior_element += array(
656
              '#default_value' => !empty($settings[$key]) ? $settings[$key] : NULL,
657
            );
658
          }
659
660
          // Get the behavior settings.
661
          $behavior_elements += array(
662
            '#type' => 'container',
663
            '#process' => array('_entityreference_form_process_merge_parent'),
664
            '#attributes' => array(
665
              'class' => array('entityreference-settings'),
666
            ),
667
          );
668
          $element['behaviors'][$name]['settings'] = $behavior_elements;
669
        }
670
      }
671
    }
672
  }
673
}
674
675
/**
676
 * Get all accessible behavior plugins.
677
 */
678
function entityreference_get_accessible_behavior_plugins($field, $instance) {
679
  ctools_include('plugins');
680
  $plugins = array('field' => array(), 'instance' => array());
681
  foreach (ctools_get_plugins('entityreference', 'behavior') as $name => $plugin) {
682
    $handler = _entityreference_get_behavior_handler($name);
683
    $level = $plugin['behavior type'];
684
    if ($handler->access($field, $instance)) {
685
      $plugins[$level][$name] = $plugin;
686
    }
687
  }
688
  return $plugins;
689
}
690
691
/**
692
 * Ajax callback for the handler settings form.
693
 *
694
 * @see entityreference_field_settings_form()
695
 */
696
function entityreference_settings_ajax($form, $form_state) {
697
  $trigger = $form_state['triggering_element'];
698
  return drupal_array_get_nested_value($form, $trigger['#ajax']['element']);
699
}
700
701
/**
702
 * Submit handler for the non-JS case.
703
 *
704
 * @see entityreference_field_settings_form()
705
 */
706
function entityreference_settings_ajax_submit($form, &$form_state) {
707
  $form_state['rebuild'] = TRUE;
708
}
709
710
/**
711
 * Property callback for the Entity Metadata framework.
712
 */
713
function entityreference_field_property_callback(&$info, $entity_type, $field, $instance, $field_type) {
714
  // Set the property type based on the targe type.
715
  $field_type['property_type'] = $field['settings']['target_type'];
716
717
  // Then apply the default.
718
  entity_metadata_field_default_property_callback($info, $entity_type, $field, $instance, $field_type);
719
720
  // Invoke the behaviors to allow them to change the properties.
721
  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
722
    $handler->property_info_alter($info, $entity_type, $field, $instance, $field_type);
723
  }
724
}
725
726
/**
727
 * Implements hook_field_widget_info().
728
 */
729
function entityreference_field_widget_info() {
730
  $widgets['entityreference_autocomplete'] = array(
731
    'label' => t('Autocomplete'),
732
    'description' => t('An autocomplete text field.'),
733
    'field types' => array('entityreference'),
734
    'settings' => array(
735
      'match_operator' => 'CONTAINS',
736
      'size' => 60,
737
      // We don't have a default here, because it's not the same between
738
      // the two widgets, and the Field API doesn't update default
739
      // settings when the widget changes.
740
      'path' => '',
741
    ),
742
  );
743
744
  $widgets['entityreference_autocomplete_tags'] = array(
745
    'label' => t('Autocomplete (Tags style)'),
746
    'description' => t('An autocomplete text field.'),
747
    'field types' => array('entityreference'),
748
    'settings' => array(
749
      'match_operator' => 'CONTAINS',
750
      'size' => 60,
751
      // We don't have a default here, because it's not the same between
752
      // the two widgets, and the Field API doesn't update default
753
      // settings when the widget changes.
754
      'path' => '',
755
    ),
756
    'behaviors' => array(
757
      'multiple values' => FIELD_BEHAVIOR_CUSTOM,
758
    ),
759
  );
760
761
  return $widgets;
762
}
763
764
/**
765
 * Implements hook_field_widget_info_alter().
766
 */
767
function entityreference_field_widget_info_alter(&$info) {
768
  if (module_exists('options')) {
769
    $info['options_select']['field types'][] = 'entityreference';
770
    $info['options_buttons']['field types'][] = 'entityreference';
771
  }
772
}
773
774
/**
775
 * Implements hook_field_widget_settings_form().
776
 */
777
function entityreference_field_widget_settings_form($field, $instance) {
778
  $widget = $instance['widget'];
779
  $settings = $widget['settings'] + field_info_widget_settings($widget['type']);
780
781
  $form = array();
782
783
  if ($widget['type'] == 'entityreference_autocomplete' || $widget['type'] == 'entityreference_autocomplete_tags') {
784
    $form['match_operator'] = array(
785
      '#type' => 'select',
786
      '#title' => t('Autocomplete matching'),
787
      '#default_value' => $settings['match_operator'],
788
      '#options' => array(
789
        'STARTS_WITH' => t('Starts with'),
790
        'CONTAINS' => t('Contains'),
791
      ),
792
      '#description' => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of nodes.'),
793
    );
794
    $form['size'] = array(
795
      '#type' => 'textfield',
796
      '#title' => t('Size of textfield'),
797
      '#default_value' => $settings['size'],
798
      '#element_validate' => array('_element_validate_integer_positive'),
799
      '#required' => TRUE,
800
    );
801
  }
802
803
  return $form;
804
}
805
806
/**
807
 * Implements hook_options_list().
808
 */
809
function entityreference_options_list($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
810
  if (!$options = entityreference_get_selection_handler($field, $instance, $entity_type, $entity)->getReferencableEntities()) {
811
    return array();
812
  }
813
814
  // Rebuild the array, by changing the bundle key into the bundle label.
815
  $target_type = $field['settings']['target_type'];
816
  $entity_info = entity_get_info($target_type);
817
818
  $return = array();
819
  foreach ($options as $bundle => $entity_ids) {
820
    $bundle_label = check_plain($entity_info['bundles'][$bundle]['label']);
821
    $return[$bundle_label] = $entity_ids;
822
  }
823
824
  return count($return) == 1 ? reset($return) : $return;
825
}
826
827
/**
828
 * Implements hook_query_TAG_alter().
829
 */
830
function entityreference_query_entityreference_alter(QueryAlterableInterface $query) {
831
  $handler = $query->getMetadata('entityreference_selection_handler');
832
  $handler->entityFieldQueryAlter($query);
833
}
834
835
/**
836
 * Implements hook_field_widget_form().
837
 */
838
function entityreference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
839
  // Ensure that the entity target type exists before displaying the widget.
840
  $entity_info = entity_get_info($field['settings']['target_type']);
841 b1ab1c0c Assos Assos
  if (empty($entity_info)) {
842 85ad3d82 Assos Assos
    return;
843
  }
844
  $entity_type = $instance['entity_type'];
845
  $entity = isset($element['#entity']) ? $element['#entity'] : NULL;
846
  $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
847
848
  if ($instance['widget']['type'] == 'entityreference_autocomplete' || $instance['widget']['type'] == 'entityreference_autocomplete_tags') {
849
850
    if ($instance['widget']['type'] == 'entityreference_autocomplete') {
851
      // We let the Field API handles multiple values for us, only take
852
      // care of the one matching our delta.
853
      if (isset($items[$delta])) {
854
        $items = array($items[$delta]);
855
      }
856
      else {
857
        $items = array();
858
      }
859
    }
860
861
    $entity_ids = array();
862
    $entity_labels = array();
863
864
    // Build an array of entities ID.
865
    foreach ($items as $item) {
866 b1ab1c0c Assos Assos
      if (isset($item['target_id'])) {
867
        $entity_ids[] = $item['target_id'];
868
      }
869 85ad3d82 Assos Assos
    }
870
871
    // Load those entities and loop through them to extract their labels.
872
    $entities = entity_load($field['settings']['target_type'], $entity_ids);
873
874
    foreach ($entities as $entity_id => $entity_item) {
875
      $label = $handler->getLabel($entity_item);
876
      $key = "$label ($entity_id)";
877
      // Labels containing commas or quotes must be wrapped in quotes.
878
      if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) {
879
        $key = '"' . str_replace('"', '""', $key) . '"';
880
      }
881
      $entity_labels[] = $key;
882
    }
883
884
    // Prepare the autocomplete path.
885
    if (!empty($instance['widget']['settings']['path'])) {
886
      $autocomplete_path = $instance['widget']['settings']['path'];
887
    }
888
    else {
889
      $autocomplete_path = $instance['widget']['type'] == 'entityreference_autocomplete' ? 'entityreference/autocomplete/single' : 'entityreference/autocomplete/tags';
890
    }
891
892
    $autocomplete_path .= '/' . $field['field_name'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/';
893
    // Use <NULL> as a placeholder in the URL when we don't have an entity.
894
    // Most webservers collapse two consecutive slashes.
895
    $id = 'NULL';
896
    if ($entity) {
897
      list($eid) = entity_extract_ids($entity_type, $entity);
898
      if ($eid) {
899
        $id = $eid;
900
      }
901
    }
902
    $autocomplete_path .= $id;
903
904
    if ($instance['widget']['type'] == 'entityreference_autocomplete') {
905
      $element += array(
906
        '#type' => 'textfield',
907
        '#maxlength' => 1024,
908
        '#default_value' => implode(', ', $entity_labels),
909
        '#autocomplete_path' => $autocomplete_path,
910
        '#size' => $instance['widget']['settings']['size'],
911
        '#element_validate' => array('_entityreference_autocomplete_validate'),
912
      );
913
      return array('target_id' => $element);
914
    }
915
    else {
916
      $element += array(
917
        '#type' => 'textfield',
918
        '#maxlength' => 1024,
919
        '#default_value' => implode(', ', $entity_labels),
920
        '#autocomplete_path' => $autocomplete_path,
921
        '#size' => $instance['widget']['settings']['size'],
922
        '#element_validate' => array('_entityreference_autocomplete_tags_validate'),
923
      );
924
      return $element;
925
    }
926
  }
927
}
928
929 b1ab1c0c Assos Assos
/**
930
 * Implements hook_validate().
931
 */
932 85ad3d82 Assos Assos
function _entityreference_autocomplete_validate($element, &$form_state, $form) {
933
  // If a value was entered into the autocomplete...
934
  $value = '';
935
  if (!empty($element['#value'])) {
936
    // Take "label (entity id)', match the id from parenthesis.
937
    if (preg_match("/.+\((\d+)\)/", $element['#value'], $matches)) {
938
      $value = $matches[1];
939
    }
940
    else {
941
      // Try to get a match from the input string when the user didn't use the
942
      // autocomplete but filled in a value manually.
943
      $field = field_info_field($element['#field_name']);
944
      $handler = entityreference_get_selection_handler($field);
945
      $field_name = $element['#field_name'];
946
      $field = field_info_field($field_name);
947
      $instance = field_info_instance($element['#entity_type'], $field_name, $element['#bundle']);
948
      $handler = entityreference_get_selection_handler($field, $instance);
949
      $value = $handler->validateAutocompleteInput($element['#value'], $element, $form_state, $form);
950
    }
951
  }
952
  // Update the value of this element so the field can validate the product IDs.
953
  form_set_value($element, $value, $form_state);
954
}
955
956 b1ab1c0c Assos Assos
/**
957
 * Implements hook_validate().
958
 */
959 85ad3d82 Assos Assos
function _entityreference_autocomplete_tags_validate($element, &$form_state, $form) {
960
  $value = array();
961
  // If a value was entered into the autocomplete...
962
  if (!empty($element['#value'])) {
963
    $entities = drupal_explode_tags($element['#value']);
964
    $value = array();
965
    foreach ($entities as $entity) {
966
      // Take "label (entity id)', match the id from parenthesis.
967
      if (preg_match("/.+\((\d+)\)/", $entity, $matches)) {
968
        $value[] = array(
969
          'target_id' => $matches[1],
970
        );
971
      }
972
      else {
973
        // Try to get a match from the input string when the user didn't use the
974
        // autocomplete but filled in a value manually.
975
        $field = field_info_field($element['#field_name']);
976
        $handler = entityreference_get_selection_handler($field);
977
        $value[] = array(
978
          'target_id' => $handler->validateAutocompleteInput($entity, $element, $form_state, $form),
979
        );
980
      }
981
    }
982
  }
983
  // Update the value of this element so the field can validate the product IDs.
984
  form_set_value($element, $value, $form_state);
985
}
986
987
/**
988
 * Implements hook_field_widget_error().
989
 */
990
function entityreference_field_widget_error($element, $error) {
991
  form_error($element, $error['message']);
992
}
993
994
/**
995
 * Menu Access callback for the autocomplete widget.
996
 *
997
 * @param $type
998
 *   The widget type (i.e. 'single' or 'tags').
999
 * @param $field_name
1000
 *   The name of the entity-reference field.
1001
 * @param $entity_type
1002
 *   The entity type.
1003
 * @param $bundle_name
1004
 *   The bundle name.
1005 b1ab1c0c Assos Assos
 *
1006
 * @return bool
1007 85ad3d82 Assos Assos
 *   True if user can access this menu item.
1008
 */
1009
function entityreference_autocomplete_access_callback($type, $field_name, $entity_type, $bundle_name) {
1010
  $field = field_info_field($field_name);
1011
  $instance = field_info_instance($entity_type, $field_name, $bundle_name);
1012
1013
  if (!$field || !$instance || $field['type'] != 'entityreference' || !field_access('edit', $field, $entity_type)) {
1014
    return FALSE;
1015
  }
1016
  return TRUE;
1017
}
1018
1019
/**
1020
 * Menu callback: autocomplete the label of an entity.
1021
 *
1022
 * @param $type
1023
 *   The widget type (i.e. 'single' or 'tags').
1024
 * @param $field_name
1025
 *   The name of the entity-reference field.
1026
 * @param $entity_type
1027
 *   The entity type.
1028
 * @param $bundle_name
1029
 *   The bundle name.
1030
 * @param $entity_id
1031
 *   Optional; The entity ID the entity-reference field is attached to.
1032
 *   Defaults to ''.
1033
 * @param $string
1034
 *   The label of the entity to query by.
1035
 */
1036
function entityreference_autocomplete_callback($type, $field_name, $entity_type, $bundle_name, $entity_id = '', $string = '') {
1037
  // If the request has a '/' in the search text, then the menu system will have
1038 b1ab1c0c Assos Assos
  // split it into multiple arguments and $string will only be a partial.
1039
  // We want to make sure we recover the intended $string.
1040 85ad3d82 Assos Assos
  $args = func_get_args();
1041 b1ab1c0c Assos Assos
  // Shift off the $type, $field_name, $entity_type,
1042
  // $bundle_name, and $entity_id args.
1043 85ad3d82 Assos Assos
  array_shift($args);
1044
  array_shift($args);
1045
  array_shift($args);
1046
  array_shift($args);
1047
  array_shift($args);
1048
  $string = implode('/', $args);
1049
1050
  $field = field_info_field($field_name);
1051
  $instance = field_info_instance($entity_type, $field_name, $bundle_name);
1052
1053
  return entityreference_autocomplete_callback_get_matches($type, $field, $instance, $entity_type, $entity_id, $string);
1054
}
1055
1056
/**
1057
 * Return JSON based on given field, instance and string.
1058
 *
1059
 * This function can be used by other modules that wish to pass a mocked
1060
 * definition of the field on instance.
1061
 *
1062
 * @param $type
1063
 *   The widget type (i.e. 'single' or 'tags').
1064
 * @param $field
1065
 *   The field array defintion.
1066
 * @param $instance
1067
 *   The instance array defintion.
1068
 * @param $entity_type
1069
 *   The entity type.
1070
 * @param $entity_id
1071
 *   Optional; The entity ID the entity-reference field is attached to.
1072
 *   Defaults to ''.
1073
 * @param $string
1074
 *   The label of the entity to query by.
1075
 */
1076
function entityreference_autocomplete_callback_get_matches($type, $field, $instance, $entity_type, $entity_id = '', $string = '') {
1077
  $matches = array();
1078 b1ab1c0c Assos Assos
  $prefix = '';
1079 85ad3d82 Assos Assos
1080
  $entity = NULL;
1081
  if ($entity_id !== 'NULL') {
1082
    $entity = entity_load_single($entity_type, $entity_id);
1083
    $has_view_access = (entity_access('view', $entity_type, $entity) !== FALSE);
1084
    $has_update_access = (entity_access('update', $entity_type, $entity) !== FALSE);
1085
    if (!$entity || !($has_view_access || $has_update_access)) {
1086
      return MENU_ACCESS_DENIED;
1087
    }
1088
  }
1089
1090
  $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
1091
1092
  if ($type == 'tags') {
1093 b1ab1c0c Assos Assos
    // The user enters a comma-separated list of tags.
1094
    // We only autocomplete the last tag.
1095 85ad3d82 Assos Assos
    $tags_typed = drupal_explode_tags($string);
1096
    $tag_last = drupal_strtolower(array_pop($tags_typed));
1097
    if (!empty($tag_last)) {
1098
      $prefix = count($tags_typed) ? implode(', ', $tags_typed) . ', ' : '';
1099
    }
1100
  }
1101
  else {
1102
    // The user enters a single tag.
1103
    $tag_last = $string;
1104
  }
1105
1106
  if (isset($tag_last)) {
1107
    // Get an array of matching entities.
1108
    $entity_labels = $handler->getReferencableEntities($tag_last, $instance['widget']['settings']['match_operator'], 10);
1109
1110
    // Loop through the products and convert them into autocomplete output.
1111
    foreach ($entity_labels as $values) {
1112
      foreach ($values as $entity_id => $label) {
1113
        $key = "$label ($entity_id)";
1114 b1ab1c0c Assos Assos
        // Strip starting/trailing white spaces, line breaks and tags.
1115 85ad3d82 Assos Assos
        $key = preg_replace('/\s\s+/', ' ', str_replace("\n", '', trim(decode_entities(strip_tags($key)))));
1116
        // Names containing commas or quotes must be wrapped in quotes.
1117
        if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) {
1118
          $key = '"' . str_replace('"', '""', $key) . '"';
1119
        }
1120
        $matches[$prefix . $key] = '<div class="reference-autocomplete">' . $label . '</div>';
1121
      }
1122
    }
1123
  }
1124
1125
  drupal_json_output($matches);
1126
}
1127
1128 b1ab1c0c Assos Assos
 /**
1129
 * Introspects field and instance settings, and determines the correct settings
1130
 * for the functioning of the formatter.
1131
 *
1132
 * Settings:
1133
 *   - entity_type - The entity_type being loaded.
1134
 *   - column - The name of the ref. field column that stores the entity id.
1135
 */
1136
function entityreference_field_type_settings($field) {
1137
  $settings = array(
1138
    'entity_type' => NULL,
1139
    'column' => NULL,
1140
  );
1141
1142
  if ($field['type'] == 'entityreference') {
1143
    $settings['entity_type'] = $field['settings']['target_type'];
1144
    $settings['column'] = 'target_id';
1145
  }
1146
  elseif ($field['type'] == 'taxonomy_term_reference') {
1147
    $settings['entity_type'] = 'taxonomy_term';
1148
    $settings['column'] = 'tid';
1149
  }
1150
1151
  return $settings;
1152
}
1153
1154 85ad3d82 Assos Assos
/**
1155
 * Implements hook_field_formatter_info().
1156
 */
1157
function entityreference_field_formatter_info() {
1158
  return array(
1159
    'entityreference_label' => array(
1160
      'label' => t('Label'),
1161
      'description' => t('Display the label of the referenced entities.'),
1162
      'field types' => array('entityreference'),
1163
      'settings' => array(
1164
        'link' => FALSE,
1165 b1ab1c0c Assos Assos
        'bypass_access' => FALSE,
1166 85ad3d82 Assos Assos
      ),
1167
    ),
1168
    'entityreference_entity_id' => array(
1169
      'label' => t('Entity id'),
1170
      'description' => t('Display the id of the referenced entities.'),
1171
      'field types' => array('entityreference'),
1172
    ),
1173
    'entityreference_entity_view' => array(
1174
      'label' => t('Rendered entity'),
1175
      'description' => t('Display the referenced entities rendered by entity_view().'),
1176 b1ab1c0c Assos Assos
      'field types' => array('entityreference', 'taxonomy_term_reference'),
1177 85ad3d82 Assos Assos
      'settings' => array(
1178
        'view_mode' => 'default',
1179
        'links' => TRUE,
1180 56aebcb7 Assos Assos
        'use_content_language' => TRUE,
1181 85ad3d82 Assos Assos
      ),
1182
    ),
1183
  );
1184
}
1185
1186
/**
1187
 * Implements hook_field_formatter_settings_form().
1188
 */
1189
function entityreference_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
1190
  $display = $instance['display'][$view_mode];
1191
  $settings = $display['settings'];
1192 b1ab1c0c Assos Assos
  $field_type_settings = entityreference_field_type_settings($field);
1193 56aebcb7 Assos Assos
  $element = array();
1194 85ad3d82 Assos Assos
1195
  if ($display['type'] == 'entityreference_label') {
1196 b1ab1c0c Assos Assos
    $element['bypass_access'] = array(
1197
      '#title' => t('Show entity labels regardless of user access'),
1198
      '#description' => t("All entities in the field will be shown, without checking them for access. If the 'Link' setting is also enabled, an entity which the user does not have access to view will show without a link."),
1199
      '#type' => 'checkbox',
1200
      '#default_value' => $settings['bypass_access'],
1201
    );
1202
1203 85ad3d82 Assos Assos
    $element['link'] = array(
1204
      '#title' => t('Link label to the referenced entity'),
1205
      '#type' => 'checkbox',
1206
      '#default_value' => $settings['link'],
1207
    );
1208
  }
1209
1210
  if ($display['type'] == 'entityreference_entity_view') {
1211 b1ab1c0c Assos Assos
    $entity_info = entity_get_info($field_type_settings['entity_type']);
1212 85ad3d82 Assos Assos
    $options = array('default' => t('Default'));
1213
    if (!empty($entity_info['view modes'])) {
1214
      foreach ($entity_info['view modes'] as $view_mode => $view_mode_settings) {
1215
        $options[$view_mode] = $view_mode_settings['label'];
1216
      }
1217
    }
1218
1219
    $element['view_mode'] = array(
1220
      '#type' => 'select',
1221
      '#options' => $options,
1222
      '#title' => t('View mode'),
1223
      '#default_value' => $settings['view_mode'],
1224
      '#access' => count($options) > 1,
1225
    );
1226
1227
    $element['links'] = array(
1228
      '#type' => 'checkbox',
1229
      '#title' => t('Show links'),
1230
      '#default_value' => $settings['links'],
1231
    );
1232 56aebcb7 Assos Assos
1233
    $element['use_content_language'] = array(
1234
      '#type' => 'checkbox',
1235
      '#title' => t('Use current content language'),
1236
      '#default_value' => $settings['use_content_language'],
1237
    );
1238 85ad3d82 Assos Assos
  }
1239
1240
  return $element;
1241
}
1242
1243
/**
1244
 * Implements hook_field_formatter_settings_summary().
1245
 */
1246
function entityreference_field_formatter_settings_summary($field, $instance, $view_mode) {
1247
  $display = $instance['display'][$view_mode];
1248
  $settings = $display['settings'];
1249 b1ab1c0c Assos Assos
  $field_type_settings = entityreference_field_type_settings($field);
1250 85ad3d82 Assos Assos
1251
  $summary = array();
1252
1253
  if ($display['type'] == 'entityreference_label') {
1254
    $summary[] = $settings['link'] ? t('Link to the referenced entity') : t('No link');
1255 b1ab1c0c Assos Assos
    $summary[] = $settings['bypass_access'] ? t('Show labels regardless of access') : t('Respect entity access for label visibility');
1256 85ad3d82 Assos Assos
  }
1257
1258
  if ($display['type'] == 'entityreference_entity_view') {
1259 b1ab1c0c Assos Assos
    $entity_info = entity_get_info($field_type_settings['entity_type']);
1260 85ad3d82 Assos Assos
    $view_mode_label = $settings['view_mode'] == 'default' ? t('Default') : $settings['view_mode'];
1261
    if (isset($entity_info['view modes'][$settings['view_mode']]['label'])) {
1262
      $view_mode_label = $entity_info['view modes'][$settings['view_mode']]['label'];
1263
    }
1264
    $summary[] = t('Rendered as @mode', array('@mode' => $view_mode_label));
1265
    $summary[] = !empty($settings['links']) ? t('Display links') : t('Do not display links');
1266 56aebcb7 Assos Assos
    $summary[] = !empty($settings['use_content_language']) ? t('Use current content language') : t('Use field language');
1267 85ad3d82 Assos Assos
  }
1268
1269
  return implode('<br />', $summary);
1270
}
1271
1272
/**
1273
 * Implements hook_field_formatter_prepare_view().
1274
 */
1275
function entityreference_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
1276 b1ab1c0c Assos Assos
  $field_type_settings = entityreference_field_type_settings($field);
1277
  $target_type = $field_type_settings['entity_type'];
1278
  $column = $field_type_settings['column'];
1279 85ad3d82 Assos Assos
  $target_ids = array();
1280
1281
  // Collect every possible entity attached to any of the entities.
1282
  foreach ($entities as $id => $entity) {
1283
    foreach ($items[$id] as $delta => $item) {
1284 b1ab1c0c Assos Assos
      if (isset($item[$column])) {
1285
        $target_ids[] = $item[$column];
1286 85ad3d82 Assos Assos
      }
1287
    }
1288
  }
1289
1290
  if ($target_ids) {
1291 b1ab1c0c Assos Assos
    $target_entities = entity_load($target_type, $target_ids);
1292 85ad3d82 Assos Assos
  }
1293
  else {
1294
    $target_entities = array();
1295
  }
1296
1297
  // Iterate through the fieldable entities again to attach the loaded data.
1298
  foreach ($entities as $id => $entity) {
1299
    $rekey = FALSE;
1300
1301
    foreach ($items[$id] as $delta => $item) {
1302
      // Check whether the referenced entity could be loaded.
1303 b1ab1c0c Assos Assos
      if (isset($target_entities[$item[$column]]) && isset($target_entities[$item[$column]])) {
1304 85ad3d82 Assos Assos
        // Replace the instance value with the term data.
1305 b1ab1c0c Assos Assos
        $items[$id][$delta]['entity'] = $target_entities[$item[$column]];
1306 85ad3d82 Assos Assos
        // Check whether the user has access to the referenced entity.
1307 b1ab1c0c Assos Assos
        $has_view_access = (entity_access('view', $target_type, $target_entities[$item[$column]]) !== FALSE);
1308
        $has_update_access = (entity_access('update', $target_type, $target_entities[$item[$column]]) !== FALSE);
1309 85ad3d82 Assos Assos
        $items[$id][$delta]['access'] = ($has_view_access || $has_update_access);
1310
      }
1311
      // Otherwise, unset the instance value, since the entity does not exist.
1312
      else {
1313
        unset($items[$id][$delta]);
1314
        $rekey = TRUE;
1315
      }
1316
    }
1317
1318
    if ($rekey) {
1319
      // Rekey the items array.
1320
      $items[$id] = array_values($items[$id]);
1321
    }
1322
  }
1323
}
1324
1325
/**
1326
 * Implements hook_field_formatter_view().
1327
 */
1328
function entityreference_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
1329
  $result = array();
1330
  $settings = $display['settings'];
1331 b1ab1c0c Assos Assos
  $field_type_settings = entityreference_field_type_settings($field);
1332
  $target_type = $field_type_settings['entity_type'];
1333
  $column = $field_type_settings['column'];
1334 85ad3d82 Assos Assos
1335
  switch ($display['type']) {
1336
    case 'entityreference_label':
1337
      $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
1338
1339
      foreach ($items as $delta => $item) {
1340 b1ab1c0c Assos Assos
        // Skip an item that is not accessible, unless we're allowing output of
1341
        // entity labels without considering access.
1342
        if (empty($item['access']) && !$display['settings']['bypass_access']) {
1343
          continue;
1344 85ad3d82 Assos Assos
        }
1345 b1ab1c0c Assos Assos
1346
        // Calling EntityReferenceHandler::getLabel() would make a repeated,
1347
        // wasteful call to entity_access().
1348
        $label = entity_label($field['settings']['target_type'], $item['entity']);
1349
1350
        // Check if the settings and access allow a link to be displayed.
1351
        $display_link = $display['settings']['link'] && $item['access'];
1352
1353
        $uri = NULL;
1354
1355
        // If the link is allowed and the entity has a uri, display a link.
1356
        if ($display_link) {
1357
          $uri = entity_uri($target_type, $item['entity']);
1358 85ad3d82 Assos Assos
        }
1359 b1ab1c0c Assos Assos
1360
        $result[$delta] = array(
1361
          '#theme' => 'entityreference_label',
1362
          '#label' => $label,
1363
          '#item' => $item,
1364
          '#uri' => $uri,
1365
          '#settings' => array(
1366
            'display' => $display['settings'],
1367
            'field' => $field['settings'],
1368
          ),
1369
        );
1370 85ad3d82 Assos Assos
      }
1371
      break;
1372
1373
    case 'entityreference_entity_id':
1374
      foreach ($items as $delta => $item) {
1375 b1ab1c0c Assos Assos
        // Skip an item that is not accessible.
1376
        if (empty($item['access'])) {
1377
          continue;
1378
        }
1379
1380
        $result[$delta] = array(
1381
          '#theme' => 'entityreference_entity_id',
1382
          '#item' => $item,
1383
          '#settings' => array(
1384
            'display' => $display['settings'],
1385
            'field' => $field['settings'],
1386
          ),
1387
        );
1388 85ad3d82 Assos Assos
      }
1389
      break;
1390
1391
    case 'entityreference_entity_view':
1392 56aebcb7 Assos Assos
      $target_langcode = $langcode;
1393
      if (!empty($settings['use_content_language']) && !empty($GLOBALS['language_content']->language)) {
1394
        $target_langcode = $GLOBALS['language_content']->language;
1395
      }
1396
1397 85ad3d82 Assos Assos
      foreach ($items as $delta => $item) {
1398 b1ab1c0c Assos Assos
        // Skip an item that is not accessible.
1399
        if (empty($item['access'])) {
1400
          continue;
1401
        }
1402
1403 85ad3d82 Assos Assos
        // Protect ourselves from recursive rendering.
1404
        static $depth = 0;
1405
        $depth++;
1406
        if ($depth > 20) {
1407 b1ab1c0c Assos Assos
          throw new EntityReferenceRecursiveRenderingException(t('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $target_type, '@entity_id' => $item[$column])));
1408 85ad3d82 Assos Assos
        }
1409
1410 56aebcb7 Assos Assos
        $target_entity = clone $item['entity'];
1411
        unset($target_entity->content);
1412 b1ab1c0c Assos Assos
        $result[$delta] = entity_view($target_type, array($item[$column] => $target_entity), $settings['view_mode'], $target_langcode, FALSE);
1413 85ad3d82 Assos Assos
1414 b1ab1c0c Assos Assos
        if (empty($settings['links']) && isset($result[$delta][$target_type][$column]['links'])) {
1415
          $result[$delta][$target_type][$item[$column]]['links']['#access'] = FALSE;
1416 85ad3d82 Assos Assos
        }
1417
        $depth = 0;
1418
      }
1419
      break;
1420
  }
1421
1422
  return $result;
1423
}
1424
1425
/**
1426
 * Exception thrown when the entity view renderer goes into a potentially infinite loop.
1427
 */
1428
class EntityReferenceRecursiveRenderingException extends Exception {}
1429
1430
/**
1431
 * Implements hook_views_api().
1432
 */
1433
function entityreference_views_api() {
1434
  return array(
1435
    'api' => 3,
1436
    'path' => drupal_get_path('module', 'entityreference') . '/views',
1437
  );
1438
}
1439 b1ab1c0c Assos Assos
1440
/**
1441
 * Theme label.
1442
 *
1443
 * @ingroup themeable.
1444
 */
1445
function theme_entityreference_label($vars) {
1446
  $label = $vars['label'];
1447
  $settings = $vars['settings'];
1448
  $item = $vars['item'];
1449
  $uri = $vars['uri'];
1450
1451
  $output = '';
1452
1453
  // If the link is to be displayed and the entity has a uri, display a link.
1454
  // Note the assignment ($url = ) here is intended to be an assignment.
1455
  if ($settings['display']['link'] && isset($uri['path'])) {
1456
    $output .= l($label, $uri['path'], $uri['options']);
1457
  }
1458
  else {
1459
    $output .= check_plain($label);
1460
  }
1461
1462
  return $output;
1463
}
1464
1465
/**
1466
 * Theme entity_id
1467
 *
1468
 * @ingroup themeable.
1469
 */
1470
function theme_entityreference_entity_id($vars) {
1471
  $settings = $vars['settings'];
1472
  $item = $vars['item'];
1473
1474
  $output = '';
1475
1476
  $output = check_plain($item['target_id']);
1477
1478
  return $output;
1479
}