Projet

Général

Profil

Paste
Télécharger (44 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / entityreference / entityreference.module @ 56aebcb7

1
<?php
2

    
3
/**
4
 * Implements hook_ctools_plugin_directory().
5
 */
6
function entityreference_ctools_plugin_directory($module, $plugin) {
7
  if ($module == 'entityreference') {
8
    return 'plugins/' . $plugin;
9
  }
10
}
11

    
12
/**
13
 * Implements hook_init().
14
 */
15
function entityreference_init() {
16
  // Include feeds.module integration.
17
  if (module_exists('feeds')) {
18
    module_load_include('inc', 'entityreference', 'entityreference.feeds');
19
  }
20
}
21

    
22
/**
23
 * Implements hook_ctools_plugin_type().
24
 */
25
function entityreference_ctools_plugin_type() {
26
  $plugins['selection'] = array(
27
    'classes' => array('class'),
28
  );
29
  $plugins['behavior'] = array(
30
    'classes' => array('class'),
31
    'process' => 'entityreference_behavior_plugin_process',
32
  );
33
  return $plugins;
34
}
35

    
36
/**
37
 * CTools callback; Process the behavoir plugins.
38
 */
39
function entityreference_behavior_plugin_process(&$plugin, $info) {
40
  $plugin += array(
41
    'description' => '',
42
    'behavior type' => 'field',
43
    'access callback' => FALSE,
44
    'force enabled' => FALSE,
45
  );
46
}
47

    
48
/**
49
 * Implements hook_field_info().
50
 */
51
function entityreference_field_info() {
52
  $field_info['entityreference'] = array(
53
    'label' => t('Entity Reference'),
54
    'description' => t('This field reference another entity.'),
55
    'settings' => array(
56
      // Default to the core target entity type node.
57
      'target_type' => 'node',
58
      // The handler for this field.
59
      'handler' => 'base',
60
      // The handler settings.
61
      'handler_settings' => array(),
62
    ),
63
    'instance_settings' => array(),
64
    'default_widget' => 'entityreference_autocomplete',
65
    'default_formatter' => 'entityreference_label',
66
    'property_callbacks' => array('entityreference_field_property_callback'),
67
  );
68
  return $field_info;
69
}
70

    
71
/**
72
 * Implements hook_flush_caches().
73
 */
74
function entityreference_flush_caches() {
75
  // Because of the intricacies of the info hooks, we are forced to keep a
76
  // separate list of the base tables of each entities, so that we can use
77
  // it in entityreference_field_schema() without calling entity_get_info().
78
  // See http://drupal.org/node/1416558 for details.
79
  $base_tables = array();
80
  foreach (entity_get_info() as $entity_type => $entity_info) {
81
    if (!empty($entity_info['base table']) && !empty($entity_info['entity keys']['id'])) {
82
      $base_tables[$entity_type] = array($entity_info['base table'], $entity_info['entity keys']['id']);
83
    }
84
  }
85
  // We are using a variable because cache is going to be cleared right after
86
  // hook_flush_caches() is finished.
87
  variable_set('entityreference:base-tables', $base_tables);
88
}
89

    
90
/**
91
 * Implements hook_menu().
92
 */
93
function entityreference_menu() {
94
  $items = array();
95

    
96
  $items['entityreference/autocomplete/single/%/%/%'] = array(
97
    'title' => 'Entity Reference Autocomplete',
98
    'page callback' => 'entityreference_autocomplete_callback',
99
    'page arguments' => array(2, 3, 4, 5),
100
    'access callback' => 'entityreference_autocomplete_access_callback',
101
    'access arguments' => array(2, 3, 4, 5),
102
    'type' => MENU_CALLBACK,
103
  );
104
  $items['entityreference/autocomplete/tags/%/%/%'] = array(
105
    'title' => 'Entity Reference Autocomplete',
106
    'page callback' => 'entityreference_autocomplete_callback',
107
    'page arguments' => array(2, 3, 4, 5),
108
    'access callback' => 'entityreference_autocomplete_access_callback',
109
    'access arguments' => array(2, 3, 4, 5),
110
    'type' => MENU_CALLBACK,
111
  );
112

    
113
  return $items;
114
}
115

    
116
/**
117
 * Implements hook_field_is_empty().
118
 */
119
function entityreference_field_is_empty($item, $field) {
120
  $empty = !isset($item['target_id']) || !is_numeric($item['target_id']);
121

    
122
  // Invoke the behaviors to allow them to override the empty status.
123
  foreach (entityreference_get_behavior_handlers($field) as $handler) {
124
    $handler->is_empty_alter($empty, $item, $field);
125
  }
126
  return $empty;
127
}
128

    
129
/**
130
 * Get the behavior handlers for a given entityreference field.
131
 */
132
function entityreference_get_behavior_handlers($field, $instance = NULL) {
133
  $object_cache = drupal_static(__FUNCTION__);
134
  $identifier = $field['field_name'];
135
  if (!empty($instance)) {
136
    $identifier .= ':' . $instance['entity_type'] . ':' . $instance['bundle'];
137
  }
138

    
139
  if (!isset($object_cache[$identifier])) {
140
    $object_cache[$identifier] = array();
141

    
142
    // Merge in defaults.
143
    $field['settings'] += array('behaviors' => array());
144

    
145
    $object_cache[$field['field_name']] = array();
146
    $behaviors = !empty($field['settings']['handler_settings']['behaviors']) ? $field['settings']['handler_settings']['behaviors'] : array();
147
    if (!empty($instance['settings']['behaviors'])) {
148
      $behaviors = array_merge($behaviors, $instance['settings']['behaviors']);
149
    }
150
    foreach ($behaviors as $behavior => $settings) {
151
      if (empty($settings['status'])) {
152
        // Behavior is not enabled.
153
        continue;
154
      }
155

    
156
      $object_cache[$identifier][] = _entityreference_get_behavior_handler($behavior);
157
    }
158
  }
159

    
160
  return $object_cache[$identifier];
161
}
162

    
163
/**
164
 * Get the behavior handler for a given entityreference field and instance.
165
 *
166
 * @param $handler
167
 *   The behavior handler name.
168
 */
169
function _entityreference_get_behavior_handler($behavior) {
170
  $object_cache = drupal_static(__FUNCTION__);
171

    
172
  if (!isset($object_cache[$behavior])) {
173
    ctools_include('plugins');
174
    $class = ctools_plugin_load_class('entityreference', 'behavior', $behavior, 'class');
175

    
176
    $class = class_exists($class) ? $class : 'EntityReference_BehaviorHandler_Broken';
177
    $object_cache[$behavior] = new $class($behavior);
178
  }
179

    
180
  return $object_cache[$behavior];
181
}
182

    
183
/**
184
 * Get the selection handler for a given entityreference field.
185
 */
186
function entityreference_get_selection_handler($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
187
  ctools_include('plugins');
188
  $handler = $field['settings']['handler'];
189
  $class = ctools_plugin_load_class('entityreference', 'selection', $handler, 'class');
190

    
191
  if (class_exists($class)) {
192
    return call_user_func(array($class, 'getInstance'), $field, $instance, $entity_type, $entity);
193
  }
194
  else {
195
    return EntityReference_SelectionHandler_Broken::getInstance($field, $instance, $entity_type, $entity);
196
  }
197
}
198

    
199
/**
200
 * Implements hook_field_load().
201
 */
202
function entityreference_field_load($entity_type, $entities, $field, $instances, $langcode, &$items) {
203
  // Invoke the behaviors.
204
  foreach (entityreference_get_behavior_handlers($field) as $handler) {
205
    $handler->load($entity_type, $entities, $field, $instances, $langcode, $items);
206
  }
207
}
208

    
209
/**
210
 * Implements hook_field_validate().
211
 */
212
function entityreference_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
213
  $ids = array();
214
  foreach ($items as $delta => $item) {
215
    if (!entityreference_field_is_empty($item, $field) && $item['target_id'] !== NULL) {
216
      $ids[$item['target_id']] = $delta;
217
    }
218
  }
219

    
220
  if ($ids) {
221
    $valid_ids = entityreference_get_selection_handler($field, $instance, $entity_type, $entity)->validateReferencableEntities(array_keys($ids));
222

    
223
    if (!empty($valid_ids)) {
224
      $invalid_entities = array_diff_key($ids, array_flip($valid_ids));
225
      if ($invalid_entities) {
226
        foreach ($invalid_entities as $id => $delta) {
227
          $errors[$field['field_name']][$langcode][$delta][] = array(
228
            'error' => 'entityreference_invalid_entity',
229
            'message' => t('The referenced entity (@type: @id) is invalid.', array('@type' => $field['settings']['target_type'], '@id' => $id)),
230
          );
231
        }
232
      }
233
    }
234
  }
235

    
236
  // Invoke the behaviors.
237
  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
238
    $handler->validate($entity_type, $entity, $field, $instance, $langcode, $items, $errors);
239
  }
240
}
241

    
242
/**
243
 * Implements hook_field_presave().
244
 *
245
 * Adds the target type to the field data structure when saving.
246
 */
247
function entityreference_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
248
  // Invoke the behaviors.
249
  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
250
    $handler->presave($entity_type, $entity, $field, $instance, $langcode, $items);
251
  }
252
}
253

    
254
/**
255
 * Implements hook_field_insert().
256
 */
257
function entityreference_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
258
  // Invoke the behaviors.
259
  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
260
    $handler->insert($entity_type, $entity, $field, $instance, $langcode, $items);
261
  }
262
}
263

    
264
/**
265
 * Implements hook_field_attach_insert().
266
 *
267
 * Emulates a post-insert hook.
268
 */
269
function entityreference_field_attach_insert($entity_type, $entity) {
270
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
271
  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
272
    $field = field_info_field($field_name);
273
    if ($field['type'] == 'entityreference') {
274
      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
275
        $handler->postInsert($entity_type, $entity, $field, $instance);
276
      }
277
    }
278
  }
279
}
280

    
281
/**
282
 * Implements hook_field_update().
283
 */
284
function entityreference_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
285
  // Invoke the behaviors.
286
  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
287
    $handler->update($entity_type, $entity, $field, $instance, $langcode, $items);
288
  }
289
}
290

    
291
/**
292
 * Implements hook_field_attach_update().
293
 *
294
 * Emulates a post-update hook.
295
 */
296
function entityreference_field_attach_update($entity_type, $entity) {
297
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
298
  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
299
    $field = field_info_field($field_name);
300
    if ($field['type'] == 'entityreference') {
301
      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
302
        $handler->postUpdate($entity_type, $entity, $field, $instance);
303
      }
304
    }
305
  }
306
}
307

    
308
/**
309
 * Implements hook_field_delete().
310
 */
311
function entityreference_field_delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
312
  // Invoke the behaviors.
313
  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
314
    $handler->delete($entity_type, $entity, $field, $instance, $langcode, $items);
315
  }
316
}
317

    
318
/**
319
 * Implements hook_field_attach_delete().
320
 *
321
 * Emulates a post-delete hook.
322
 */
323
function entityreference_field_attach_delete($entity_type, $entity) {
324
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
325
  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
326
    $field = field_info_field($field_name);
327
    if ($field['type'] == 'entityreference') {
328
      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
329
        $handler->postDelete($entity_type, $entity, $field, $instance);
330
      }
331
    }
332
  }
333
}
334

    
335
/**
336
 * Implements hook_entity_insert().
337
 */
338
function entityreference_entity_insert($entity, $entity_type) {
339
  entityreference_entity_crud($entity, $entity_type, 'entityPostInsert');
340
}
341

    
342
/**
343
 * Implements hook_entity_update().
344
 */
345
function entityreference_entity_update($entity, $entity_type) {
346
  entityreference_entity_crud($entity, $entity_type, 'entityPostUpdate');
347
}
348

    
349
/**
350
 * Implements hook_entity_delete().
351
 */
352
function entityreference_entity_delete($entity, $entity_type) {
353
  entityreference_entity_crud($entity, $entity_type, 'entityPostDelete');
354
}
355

    
356
/**
357
 * Invoke a behavior based on entity CRUD.
358
 *
359
 * @param $entity
360
 *   The entity object.
361
 * @param $entity_type
362
 *   The entity type.
363
 * @param $method_name
364
 *   The method to invoke.
365
 */
366
function entityreference_entity_crud($entity, $entity_type, $method_name) {
367
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
368
  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
369
    $field = field_info_field($field_name);
370
    if ($field['type'] == 'entityreference') {
371
      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
372
        $handler->{$method_name}($entity_type, $entity, $field, $instance);
373
      }
374
    }
375
  }
376
}
377

    
378
/**
379
 * Implements hook_field_settings_form().
380
 */
381
function entityreference_field_settings_form($field, $instance, $has_data) {
382
  // The field settings infrastructure is not AJAX enabled by default,
383
  // because it doesn't pass over the $form_state.
384
  // Build the whole form into a #process in which we actually have access
385
  // to the form state.
386
  $form = array(
387
    '#type' => 'container',
388
    '#attached' => array(
389
      'css' => array(drupal_get_path('module', 'entityreference') . '/entityreference.admin.css'),
390
    ),
391
    '#process' => array(
392
      '_entityreference_field_settings_process',
393
      '_entityreference_field_settings_ajax_process',
394
    ),
395
    '#element_validate' => array('_entityreference_field_settings_validate'),
396
    '#field' => $field,
397
    '#instance' => $instance,
398
    '#has_data' => $has_data,
399
  );
400
  return $form;
401
}
402

    
403
function _entityreference_field_settings_process($form, $form_state) {
404
  $field = isset($form_state['entityreference']['field']) ? $form_state['entityreference']['field'] : $form['#field'];
405
  $instance = isset($form_state['entityreference']['instance']) ? $form_state['entityreference']['instance'] : $form['#instance'];
406
  $has_data = $form['#has_data'];
407

    
408
  $settings = $field['settings'];
409
  $settings += array('handler' => 'base');
410

    
411
  // Select the target entity type.
412
  $entity_type_options = array();
413
  foreach (entity_get_info() as $entity_type => $entity_info) {
414
    $entity_type_options[$entity_type] = $entity_info['label'];
415
  }
416

    
417
  $form['target_type'] = array(
418
    '#type' => 'select',
419
    '#title' => t('Target type'),
420
    '#options' => $entity_type_options,
421
    '#default_value' => $field['settings']['target_type'],
422
    '#required' => TRUE,
423
    '#description' => t('The entity type that can be referenced through this field.'),
424
    '#disabled' => $has_data,
425
    '#size' => 1,
426
    '#ajax' => TRUE,
427
    '#limit_validation_errors' => array(),
428
  );
429

    
430
  ctools_include('plugins');
431
  $handlers = ctools_get_plugins('entityreference', 'selection');
432
  uasort($handlers, 'ctools_plugin_sort');
433
  $handlers_options = array();
434
  foreach ($handlers as $handler => $handler_info) {
435
    $handlers_options[$handler] = check_plain($handler_info['title']);
436
  }
437

    
438
  $form['handler'] = array(
439
    '#type' => 'fieldset',
440
    '#title' => t('Entity selection'),
441
    '#tree' => TRUE,
442
    '#process' => array('_entityreference_form_process_merge_parent'),
443
  );
444

    
445
  $form['handler']['handler'] = array(
446
    '#type' => 'select',
447
    '#title' => t('Mode'),
448
    '#options' => $handlers_options,
449
    '#default_value' => $settings['handler'],
450
    '#required' => TRUE,
451
    '#ajax' => TRUE,
452
    '#limit_validation_errors' => array(),
453
  );
454
  $form['handler_submit'] = array(
455
    '#type' => 'submit',
456
    '#value' => t('Change handler'),
457
    '#limit_validation_errors' => array(),
458
    '#attributes' => array(
459
      'class' => array('js-hide'),
460
    ),
461
    '#submit' => array('entityreference_settings_ajax_submit'),
462
  );
463

    
464
  $form['handler']['handler_settings'] = array(
465
    '#type' => 'container',
466
    '#attributes' => array('class' => array('entityreference-settings')),
467
  );
468

    
469
  $handler = entityreference_get_selection_handler($field, $instance);
470
  $form['handler']['handler_settings'] += $handler->settingsForm($field, $instance);
471

    
472
  _entityreference_get_behavior_elements($form, $field, $instance, 'field');
473
  if (!empty($form['behaviors'])) {
474
    $form['behaviors'] += array(
475
      '#type' => 'fieldset',
476
      '#title' => t('Additional behaviors'),
477
      '#parents' => array_merge($form['#parents'], array('handler_settings', 'behaviors')),
478
    );
479
  }
480

    
481
  return $form;
482
}
483

    
484
function _entityreference_field_settings_ajax_process($form, $form_state) {
485
  _entityreference_field_settings_ajax_process_element($form, $form);
486
  return $form;
487
}
488

    
489
function _entityreference_field_settings_ajax_process_element(&$element, $main_form) {
490
  if (isset($element['#ajax']) && $element['#ajax'] === TRUE) {
491
    $element['#ajax'] = array(
492
      'callback' => 'entityreference_settings_ajax',
493
      'wrapper' => $main_form['#id'],
494
      'element' => $main_form['#array_parents'],
495
    );
496
  }
497

    
498
  foreach (element_children($element) as $key) {
499
    _entityreference_field_settings_ajax_process_element($element[$key], $main_form);
500
  }
501
}
502

    
503
function _entityreference_form_process_merge_parent($element) {
504
  $parents = $element['#parents'];
505
  array_pop($parents);
506
  $element['#parents'] = $parents;
507
  return $element;
508
}
509

    
510
function _entityreference_element_validate_filter(&$element, &$form_state) {
511
  $element['#value'] = array_filter($element['#value']);
512
  form_set_value($element, $element['#value'], $form_state);
513
}
514

    
515
function _entityreference_field_settings_validate($form, &$form_state) {
516
  // Store the new values in the form state.
517
  $field = $form['#field'];
518
  if (isset($form_state['values']['field'])) {
519
    $field['settings'] = $form_state['values']['field']['settings'];
520
  }
521
  $form_state['entityreference']['field'] = $field;
522

    
523
  unset($form_state['values']['field']['settings']['handler_submit']);
524
}
525

    
526
/**
527
 * Implements hook_field_instance_settings_form().
528
 */
529
function entityreference_field_instance_settings_form($field, $instance) {
530
  $form['settings'] = array(
531
    '#type' => 'container',
532
    '#attached' => array(
533
      'css' => array(drupal_get_path('module', 'entityreference') . '/entityreference.admin.css'),
534
    ),
535
    '#weight' => 10,
536
    '#tree' => TRUE,
537
    '#process' => array(
538
      '_entityreference_form_process_merge_parent',
539
      '_entityreference_field_instance_settings_form',
540
      '_entityreference_field_settings_ajax_process',
541
    ),
542
    '#element_validate' => array('_entityreference_field_instance_settings_validate'),
543
    '#field' => $field,
544
    '#instance' => $instance,
545
  );
546

    
547
  return $form;
548
}
549

    
550
function _entityreference_field_instance_settings_form($form, $form_state) {
551
  $field = isset($form_state['entityreference']['field']) ? $form_state['entityreference']['field'] : $form['#field'];
552
  $instance = isset($form_state['entityreference']['instance']) ? $form_state['entityreference']['instance'] : $form['#instance'];
553

    
554
  _entityreference_get_behavior_elements($form, $field, $instance, 'instance');
555
  if (!empty($form['behaviors'])) {
556
    $form['behaviors'] += array(
557
      '#type' => 'fieldset',
558
      '#title' => t('Additional behaviors'),
559
      '#process' => array(
560
        '_entityreference_field_settings_ajax_process',
561
      ),
562
    );
563
  }
564
  return $form;
565
}
566

    
567
function _entityreference_field_instance_settings_validate($form, &$form_state) {
568
  // Store the new values in the form state.
569
  $instance = $form['#instance'];
570
  if (isset($form_state['values']['instance'])) {
571
    $instance = drupal_array_merge_deep($instance, $form_state['values']['instance']);
572
  }
573
  $form_state['entityreference']['instance'] = $instance;
574
}
575

    
576
/**
577
 * Get the field or instance elements for the field configuration.
578
 */
579
function _entityreference_get_behavior_elements(&$element, $field, $instance, $level) {
580
  // Add the accessible behavior handlers.
581
  $behavior_plugins = entityreference_get_accessible_behavior_plugins($field, $instance);
582

    
583
  if ($behavior_plugins[$level]) {
584
    $element['behaviors'] = array();
585

    
586
    foreach ($behavior_plugins[$level] as $name => $plugin) {
587
      if ($level == 'field') {
588
        $settings = !empty($field['settings']['handler_settings']['behaviors'][$name]) ? $field['settings']['handler_settings']['behaviors'][$name] : array();
589
      }
590
      else {
591
        $settings = !empty($instance['settings']['behaviors'][$name]) ? $instance['settings']['behaviors'][$name] : array();
592
      }
593
      $settings += array('status' => $plugin['force enabled']);
594

    
595
      // Render the checkbox.
596
      $element['behaviors'][$name] = array(
597
        '#tree' => TRUE,
598
      );
599
      $element['behaviors'][$name]['status'] = array(
600
        '#type' => 'checkbox',
601
        '#title' => check_plain($plugin['title']),
602
        '#description' => $plugin['description'],
603
        '#default_value' => $settings['status'],
604
        '#disabled' => $plugin['force enabled'],
605
        '#ajax' => TRUE,
606
      );
607

    
608
      if ($settings['status']) {
609
        $handler = _entityreference_get_behavior_handler($name);
610
        if ($behavior_elements = $handler->settingsForm($field, $instance)) {
611
          foreach ($behavior_elements as $key => &$behavior_element) {
612
            $behavior_element += array(
613
              '#default_value' => !empty($settings[$key]) ? $settings[$key] : NULL,
614
            );
615
          }
616

    
617
          // Get the behavior settings.
618
          $behavior_elements += array(
619
            '#type' => 'container',
620
            '#process' => array('_entityreference_form_process_merge_parent'),
621
            '#attributes' => array(
622
              'class' => array('entityreference-settings'),
623
            ),
624
          );
625
          $element['behaviors'][$name]['settings'] = $behavior_elements;
626
        }
627
      }
628
    }
629
  }
630
}
631

    
632
/**
633
 * Get all accessible behavior plugins.
634
 */
635
function entityreference_get_accessible_behavior_plugins($field, $instance) {
636
  ctools_include('plugins');
637
  $plugins = array('field' => array(), 'instance' => array());
638
  foreach (ctools_get_plugins('entityreference', 'behavior') as $name => $plugin) {
639
    $handler = _entityreference_get_behavior_handler($name);
640
    $level = $plugin['behavior type'];
641
    if ($handler->access($field, $instance)) {
642
      $plugins[$level][$name] = $plugin;
643
    }
644
  }
645
  return $plugins;
646
}
647

    
648
/**
649
 * Ajax callback for the handler settings form.
650
 *
651
 * @see entityreference_field_settings_form()
652
 */
653
function entityreference_settings_ajax($form, $form_state) {
654
  $trigger = $form_state['triggering_element'];
655
  return drupal_array_get_nested_value($form, $trigger['#ajax']['element']);
656
}
657

    
658
/**
659
 * Submit handler for the non-JS case.
660
 *
661
 * @see entityreference_field_settings_form()
662
 */
663
function entityreference_settings_ajax_submit($form, &$form_state) {
664
  $form_state['rebuild'] = TRUE;
665
}
666

    
667
/**
668
 * Property callback for the Entity Metadata framework.
669
 */
670
function entityreference_field_property_callback(&$info, $entity_type, $field, $instance, $field_type) {
671
  // Set the property type based on the targe type.
672
  $field_type['property_type'] = $field['settings']['target_type'];
673

    
674
  // Then apply the default.
675
  entity_metadata_field_default_property_callback($info, $entity_type, $field, $instance, $field_type);
676

    
677
  // Invoke the behaviors to allow them to change the properties.
678
  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
679
    $handler->property_info_alter($info, $entity_type, $field, $instance, $field_type);
680
  }
681
}
682

    
683
/**
684
 * Implements hook_field_widget_info().
685
 */
686
function entityreference_field_widget_info() {
687
  $widgets['entityreference_autocomplete'] = array(
688
    'label' => t('Autocomplete'),
689
    'description' => t('An autocomplete text field.'),
690
    'field types' => array('entityreference'),
691
    'settings' => array(
692
      'match_operator' => 'CONTAINS',
693
      'size' => 60,
694
      // We don't have a default here, because it's not the same between
695
      // the two widgets, and the Field API doesn't update default
696
      // settings when the widget changes.
697
      'path' => '',
698
    ),
699
  );
700

    
701
  $widgets['entityreference_autocomplete_tags'] = array(
702
    'label' => t('Autocomplete (Tags style)'),
703
    'description' => t('An autocomplete text field.'),
704
    'field types' => array('entityreference'),
705
    'settings' => array(
706
      'match_operator' => 'CONTAINS',
707
      'size' => 60,
708
      // We don't have a default here, because it's not the same between
709
      // the two widgets, and the Field API doesn't update default
710
      // settings when the widget changes.
711
      'path' => '',
712
    ),
713
    'behaviors' => array(
714
      'multiple values' => FIELD_BEHAVIOR_CUSTOM,
715
    ),
716
  );
717

    
718
  return $widgets;
719
}
720

    
721
/**
722
 * Implements hook_field_widget_info_alter().
723
 */
724
function entityreference_field_widget_info_alter(&$info) {
725
  if (module_exists('options')) {
726
    $info['options_select']['field types'][] = 'entityreference';
727
    $info['options_buttons']['field types'][] = 'entityreference';
728
  }
729
}
730

    
731
/**
732
 * Implements hook_field_widget_settings_form().
733
 */
734
function entityreference_field_widget_settings_form($field, $instance) {
735
  $widget = $instance['widget'];
736
  $settings = $widget['settings'] + field_info_widget_settings($widget['type']);
737

    
738
  $form = array();
739

    
740
  if ($widget['type'] == 'entityreference_autocomplete' || $widget['type'] == 'entityreference_autocomplete_tags') {
741
    $form['match_operator'] = array(
742
      '#type' => 'select',
743
      '#title' => t('Autocomplete matching'),
744
      '#default_value' => $settings['match_operator'],
745
      '#options' => array(
746
        'STARTS_WITH' => t('Starts with'),
747
        'CONTAINS' => t('Contains'),
748
      ),
749
      '#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.'),
750
    );
751
    $form['size'] = array(
752
      '#type' => 'textfield',
753
      '#title' => t('Size of textfield'),
754
      '#default_value' => $settings['size'],
755
      '#element_validate' => array('_element_validate_integer_positive'),
756
      '#required' => TRUE,
757
    );
758
  }
759

    
760
  return $form;
761
}
762

    
763
/**
764
 * Implements hook_options_list().
765
 */
766
function entityreference_options_list($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
767
  if (!$options = entityreference_get_selection_handler($field, $instance, $entity_type, $entity)->getReferencableEntities()) {
768
    return array();
769
  }
770

    
771
  // Rebuild the array, by changing the bundle key into the bundle label.
772
  $target_type = $field['settings']['target_type'];
773
  $entity_info = entity_get_info($target_type);
774

    
775
  $return = array();
776
  foreach ($options as $bundle => $entity_ids) {
777
    $bundle_label = check_plain($entity_info['bundles'][$bundle]['label']);
778
    $return[$bundle_label] = $entity_ids;
779
  }
780

    
781
  return count($return) == 1 ? reset($return) : $return;
782
}
783

    
784
/**
785
 * Implements hook_query_TAG_alter().
786
 */
787
function entityreference_query_entityreference_alter(QueryAlterableInterface $query) {
788
  $handler = $query->getMetadata('entityreference_selection_handler');
789
  $handler->entityFieldQueryAlter($query);
790
}
791

    
792
/**
793
 * Implements hook_field_widget_form().
794
 */
795
function entityreference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
796
  // Ensure that the entity target type exists before displaying the widget.
797
  $entity_info = entity_get_info($field['settings']['target_type']);
798
  if (empty($entity_info)){
799
    return;
800
  }
801
  $entity_type = $instance['entity_type'];
802
  $entity = isset($element['#entity']) ? $element['#entity'] : NULL;
803
  $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
804

    
805
  if ($instance['widget']['type'] == 'entityreference_autocomplete' || $instance['widget']['type'] == 'entityreference_autocomplete_tags') {
806

    
807
    if ($instance['widget']['type'] == 'entityreference_autocomplete') {
808
      // We let the Field API handles multiple values for us, only take
809
      // care of the one matching our delta.
810
      if (isset($items[$delta])) {
811
        $items = array($items[$delta]);
812
      }
813
      else {
814
        $items = array();
815
      }
816
    }
817

    
818
    $entity_ids = array();
819
    $entity_labels = array();
820

    
821
    // Build an array of entities ID.
822
    foreach ($items as $item) {
823
      $entity_ids[] = $item['target_id'];
824
    }
825

    
826
    // Load those entities and loop through them to extract their labels.
827
    $entities = entity_load($field['settings']['target_type'], $entity_ids);
828

    
829
    foreach ($entities as $entity_id => $entity_item) {
830
      $label = $handler->getLabel($entity_item);
831
      $key = "$label ($entity_id)";
832
      // Labels containing commas or quotes must be wrapped in quotes.
833
      if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) {
834
        $key = '"' . str_replace('"', '""', $key) . '"';
835
      }
836
      $entity_labels[] = $key;
837
    }
838

    
839
    // Prepare the autocomplete path.
840
    if (!empty($instance['widget']['settings']['path'])) {
841
      $autocomplete_path = $instance['widget']['settings']['path'];
842
    }
843
    else {
844
      $autocomplete_path = $instance['widget']['type'] == 'entityreference_autocomplete' ? 'entityreference/autocomplete/single' : 'entityreference/autocomplete/tags';
845
    }
846

    
847
    $autocomplete_path .= '/' . $field['field_name'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/';
848
    // Use <NULL> as a placeholder in the URL when we don't have an entity.
849
    // Most webservers collapse two consecutive slashes.
850
    $id = 'NULL';
851
    if ($entity) {
852
      list($eid) = entity_extract_ids($entity_type, $entity);
853
      if ($eid) {
854
        $id = $eid;
855
      }
856
    }
857
    $autocomplete_path .= $id;
858

    
859
    if ($instance['widget']['type'] == 'entityreference_autocomplete') {
860
      $element += array(
861
        '#type' => 'textfield',
862
        '#maxlength' => 1024,
863
        '#default_value' => implode(', ', $entity_labels),
864
        '#autocomplete_path' => $autocomplete_path,
865
        '#size' => $instance['widget']['settings']['size'],
866
        '#element_validate' => array('_entityreference_autocomplete_validate'),
867
      );
868
      return array('target_id' => $element);
869
    }
870
    else {
871
      $element += array(
872
        '#type' => 'textfield',
873
        '#maxlength' => 1024,
874
        '#default_value' => implode(', ', $entity_labels),
875
        '#autocomplete_path' => $autocomplete_path,
876
        '#size' => $instance['widget']['settings']['size'],
877
        '#element_validate' => array('_entityreference_autocomplete_tags_validate'),
878
      );
879
      return $element;
880
    }
881
  }
882
}
883

    
884
function _entityreference_autocomplete_validate($element, &$form_state, $form) {
885
  // If a value was entered into the autocomplete...
886
  $value = '';
887
  if (!empty($element['#value'])) {
888
    // Take "label (entity id)', match the id from parenthesis.
889
    if (preg_match("/.+\((\d+)\)/", $element['#value'], $matches)) {
890
      $value = $matches[1];
891
    }
892
    else {
893
      // Try to get a match from the input string when the user didn't use the
894
      // autocomplete but filled in a value manually.
895
      $field = field_info_field($element['#field_name']);
896
      $handler = entityreference_get_selection_handler($field);
897
      $field_name = $element['#field_name'];
898
      $field = field_info_field($field_name);
899
      $instance = field_info_instance($element['#entity_type'], $field_name, $element['#bundle']);
900
      $handler = entityreference_get_selection_handler($field, $instance);
901
      $value = $handler->validateAutocompleteInput($element['#value'], $element, $form_state, $form);
902
    }
903
  }
904
  // Update the value of this element so the field can validate the product IDs.
905
  form_set_value($element, $value, $form_state);
906
}
907

    
908
function _entityreference_autocomplete_tags_validate($element, &$form_state, $form) {
909
  $value = array();
910
  // If a value was entered into the autocomplete...
911
  if (!empty($element['#value'])) {
912
    $entities = drupal_explode_tags($element['#value']);
913
    $value = array();
914
    foreach ($entities as $entity) {
915
      // Take "label (entity id)', match the id from parenthesis.
916
      if (preg_match("/.+\((\d+)\)/", $entity, $matches)) {
917
        $value[] = array(
918
          'target_id' => $matches[1],
919
        );
920
      }
921
      else {
922
        // Try to get a match from the input string when the user didn't use the
923
        // autocomplete but filled in a value manually.
924
        $field = field_info_field($element['#field_name']);
925
        $handler = entityreference_get_selection_handler($field);
926
        $value[] = array(
927
          'target_id' => $handler->validateAutocompleteInput($entity, $element, $form_state, $form),
928
        );
929
      }
930
    }
931
  }
932
  // Update the value of this element so the field can validate the product IDs.
933
  form_set_value($element, $value, $form_state);
934
}
935

    
936
/**
937
 * Implements hook_field_widget_error().
938
 */
939
function entityreference_field_widget_error($element, $error) {
940
  form_error($element, $error['message']);
941
}
942

    
943
/**
944
 * Menu Access callback for the autocomplete widget.
945
 *
946
 * @param $type
947
 *   The widget type (i.e. 'single' or 'tags').
948
 * @param $field_name
949
 *   The name of the entity-reference field.
950
 * @param $entity_type
951
 *   The entity type.
952
 * @param $bundle_name
953
 *   The bundle name.
954
 * @return
955
 *   True if user can access this menu item.
956
 */
957
function entityreference_autocomplete_access_callback($type, $field_name, $entity_type, $bundle_name) {
958
  $field = field_info_field($field_name);
959
  $instance = field_info_instance($entity_type, $field_name, $bundle_name);
960

    
961
  if (!$field || !$instance || $field['type'] != 'entityreference' || !field_access('edit', $field, $entity_type)) {
962
    return FALSE;
963
  }
964
  return TRUE;
965
}
966

    
967
/**
968
 * Menu callback: autocomplete the label of an entity.
969
 *
970
 * @param $type
971
 *   The widget type (i.e. 'single' or 'tags').
972
 * @param $field_name
973
 *   The name of the entity-reference field.
974
 * @param $entity_type
975
 *   The entity type.
976
 * @param $bundle_name
977
 *   The bundle name.
978
 * @param $entity_id
979
 *   Optional; The entity ID the entity-reference field is attached to.
980
 *   Defaults to ''.
981
 * @param $string
982
 *   The label of the entity to query by.
983
 */
984
function entityreference_autocomplete_callback($type, $field_name, $entity_type, $bundle_name, $entity_id = '', $string = '') {
985
  // If the request has a '/' in the search text, then the menu system will have
986
  // split it into multiple arguments and $string will only be a partial. We want
987
  //  to make sure we recover the intended $string.
988
  $args = func_get_args();
989
  // Shift off the $type, $field_name, $entity_type, $bundle_name, and $entity_id args.
990
  array_shift($args);
991
  array_shift($args);
992
  array_shift($args);
993
  array_shift($args);
994
  array_shift($args);
995
  $string = implode('/', $args);
996

    
997
  $field = field_info_field($field_name);
998
  $instance = field_info_instance($entity_type, $field_name, $bundle_name);
999

    
1000
  return entityreference_autocomplete_callback_get_matches($type, $field, $instance, $entity_type, $entity_id, $string);
1001
}
1002

    
1003
/**
1004
 * Return JSON based on given field, instance and string.
1005
 *
1006
 * This function can be used by other modules that wish to pass a mocked
1007
 * definition of the field on instance.
1008
 *
1009
 * @param $type
1010
 *   The widget type (i.e. 'single' or 'tags').
1011
 * @param $field
1012
 *   The field array defintion.
1013
 * @param $instance
1014
 *   The instance array defintion.
1015
 * @param $entity_type
1016
 *   The entity type.
1017
 * @param $entity_id
1018
 *   Optional; The entity ID the entity-reference field is attached to.
1019
 *   Defaults to ''.
1020
 * @param $string
1021
 *   The label of the entity to query by.
1022
 */
1023
function entityreference_autocomplete_callback_get_matches($type, $field, $instance, $entity_type, $entity_id = '', $string = '') {
1024
  $matches = array();
1025

    
1026
  $entity = NULL;
1027
  if ($entity_id !== 'NULL') {
1028
    $entity = entity_load_single($entity_type, $entity_id);
1029
    $has_view_access = (entity_access('view', $entity_type, $entity) !== FALSE);
1030
    $has_update_access = (entity_access('update', $entity_type, $entity) !== FALSE);
1031
    if (!$entity || !($has_view_access || $has_update_access)) {
1032
      return MENU_ACCESS_DENIED;
1033
    }
1034
  }
1035

    
1036
  $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
1037

    
1038
  if ($type == 'tags') {
1039
    // The user enters a comma-separated list of tags. We only autocomplete the last tag.
1040
    $tags_typed = drupal_explode_tags($string);
1041
    $tag_last = drupal_strtolower(array_pop($tags_typed));
1042
    if (!empty($tag_last)) {
1043
      $prefix = count($tags_typed) ? implode(', ', $tags_typed) . ', ' : '';
1044
    }
1045
  }
1046
  else {
1047
    // The user enters a single tag.
1048
    $prefix = '';
1049
    $tag_last = $string;
1050
  }
1051

    
1052
  if (isset($tag_last)) {
1053
    // Get an array of matching entities.
1054
    $entity_labels = $handler->getReferencableEntities($tag_last, $instance['widget']['settings']['match_operator'], 10);
1055

    
1056
    // Loop through the products and convert them into autocomplete output.
1057
    foreach ($entity_labels as $values) {
1058
      foreach ($values as $entity_id => $label) {
1059
        $key = "$label ($entity_id)";
1060
        // Strip things like starting/trailing white spaces, line breaks and tags.
1061
        $key = preg_replace('/\s\s+/', ' ', str_replace("\n", '', trim(decode_entities(strip_tags($key)))));
1062
        // Names containing commas or quotes must be wrapped in quotes.
1063
        if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) {
1064
          $key = '"' . str_replace('"', '""', $key) . '"';
1065
        }
1066
        $matches[$prefix . $key] = '<div class="reference-autocomplete">' . $label . '</div>';
1067
      }
1068
    }
1069
  }
1070

    
1071
  drupal_json_output($matches);
1072
}
1073

    
1074
/**
1075
 * Implements hook_field_formatter_info().
1076
 */
1077
function entityreference_field_formatter_info() {
1078
  return array(
1079
    'entityreference_label' => array(
1080
      'label' => t('Label'),
1081
      'description' => t('Display the label of the referenced entities.'),
1082
      'field types' => array('entityreference'),
1083
      'settings' => array(
1084
        'link' => FALSE,
1085
      ),
1086
    ),
1087
    'entityreference_entity_id' => array(
1088
      'label' => t('Entity id'),
1089
      'description' => t('Display the id of the referenced entities.'),
1090
      'field types' => array('entityreference'),
1091
    ),
1092
    'entityreference_entity_view' => array(
1093
      'label' => t('Rendered entity'),
1094
      'description' => t('Display the referenced entities rendered by entity_view().'),
1095
      'field types' => array('entityreference'),
1096
      'settings' => array(
1097
        'view_mode' => 'default',
1098
        'links' => TRUE,
1099
        'use_content_language' => TRUE,
1100
      ),
1101
    ),
1102
  );
1103
}
1104

    
1105
/**
1106
 * Implements hook_field_formatter_settings_form().
1107
 */
1108
function entityreference_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
1109
  $display = $instance['display'][$view_mode];
1110
  $settings = $display['settings'];
1111
  $element = array();
1112

    
1113
  if ($display['type'] == 'entityreference_label') {
1114
    $element['link'] = array(
1115
      '#title' => t('Link label to the referenced entity'),
1116
      '#type' => 'checkbox',
1117
      '#default_value' => $settings['link'],
1118
    );
1119
  }
1120

    
1121
  if ($display['type'] == 'entityreference_entity_view') {
1122
    $entity_info = entity_get_info($field['settings']['target_type']);
1123
    $options = array('default' => t('Default'));
1124
    if (!empty($entity_info['view modes'])) {
1125
      foreach ($entity_info['view modes'] as $view_mode => $view_mode_settings) {
1126
        $options[$view_mode] = $view_mode_settings['label'];
1127
      }
1128
    }
1129

    
1130
    $element['view_mode'] = array(
1131
      '#type' => 'select',
1132
      '#options' => $options,
1133
      '#title' => t('View mode'),
1134
      '#default_value' => $settings['view_mode'],
1135
      '#access' => count($options) > 1,
1136
    );
1137

    
1138
    $element['links'] = array(
1139
      '#type' => 'checkbox',
1140
      '#title' => t('Show links'),
1141
      '#default_value' => $settings['links'],
1142
    );
1143

    
1144
    $element['use_content_language'] = array(
1145
      '#type' => 'checkbox',
1146
      '#title' => t('Use current content language'),
1147
      '#default_value' => $settings['use_content_language'],
1148
    );
1149
  }
1150

    
1151
  return $element;
1152
}
1153

    
1154
/**
1155
 * Implements hook_field_formatter_settings_summary().
1156
 */
1157
function entityreference_field_formatter_settings_summary($field, $instance, $view_mode) {
1158
  $display = $instance['display'][$view_mode];
1159
  $settings = $display['settings'];
1160

    
1161
  $summary = array();
1162

    
1163
  if ($display['type'] == 'entityreference_label') {
1164
    $summary[] = $settings['link'] ? t('Link to the referenced entity') : t('No link');
1165
  }
1166

    
1167
  if ($display['type'] == 'entityreference_entity_view') {
1168
    $entity_info = entity_get_info($field['settings']['target_type']);
1169
    $view_mode_label = $settings['view_mode'] == 'default' ? t('Default') : $settings['view_mode'];
1170
    if (isset($entity_info['view modes'][$settings['view_mode']]['label'])) {
1171
      $view_mode_label = $entity_info['view modes'][$settings['view_mode']]['label'];
1172
    }
1173
    $summary[] = t('Rendered as @mode', array('@mode' => $view_mode_label));
1174
    $summary[] = !empty($settings['links']) ? t('Display links') : t('Do not display links');
1175
    $summary[] = !empty($settings['use_content_language']) ? t('Use current content language') : t('Use field language');
1176
  }
1177

    
1178
  return implode('<br />', $summary);
1179
}
1180

    
1181
/**
1182
 * Implements hook_field_formatter_prepare_view().
1183
 */
1184
function entityreference_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
1185
  $target_ids = array();
1186

    
1187
  // Collect every possible entity attached to any of the entities.
1188
  foreach ($entities as $id => $entity) {
1189
    foreach ($items[$id] as $delta => $item) {
1190
      if (isset($item['target_id'])) {
1191
        $target_ids[] = $item['target_id'];
1192
      }
1193
    }
1194
  }
1195

    
1196
  if ($target_ids) {
1197
    $target_entities = entity_load($field['settings']['target_type'], $target_ids);
1198
  }
1199
  else {
1200
    $target_entities = array();
1201
  }
1202

    
1203
  // Iterate through the fieldable entities again to attach the loaded data.
1204
  foreach ($entities as $id => $entity) {
1205
    $rekey = FALSE;
1206

    
1207
    foreach ($items[$id] as $delta => $item) {
1208
      // Check whether the referenced entity could be loaded.
1209
      if (isset($item['target_id']) && isset($target_entities[$item['target_id']])) {
1210
        // Replace the instance value with the term data.
1211
        $items[$id][$delta]['entity'] = $target_entities[$item['target_id']];
1212
        // Check whether the user has access to the referenced entity.
1213
        $has_view_access = (entity_access('view', $field['settings']['target_type'], $target_entities[$item['target_id']]) !== FALSE);
1214
        $has_update_access = (entity_access('update', $field['settings']['target_type'], $target_entities[$item['target_id']]) !== FALSE);
1215
        $items[$id][$delta]['access'] = ($has_view_access || $has_update_access);
1216
      }
1217
      // Otherwise, unset the instance value, since the entity does not exist.
1218
      else {
1219
        unset($items[$id][$delta]);
1220
        $rekey = TRUE;
1221
      }
1222
    }
1223

    
1224
    if ($rekey) {
1225
      // Rekey the items array.
1226
      $items[$id] = array_values($items[$id]);
1227
    }
1228
  }
1229
}
1230

    
1231
/**
1232
 * Implements hook_field_formatter_view().
1233
 */
1234
function entityreference_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
1235
  $result = array();
1236
  $settings = $display['settings'];
1237

    
1238
  // Rebuild the items list to contain only those with access.
1239
  foreach ($items as $key => $item) {
1240
    if (empty($item['access'])) {
1241
      unset($items[$key]);
1242
    }
1243
  }
1244

    
1245
  switch ($display['type']) {
1246
    case 'entityreference_label':
1247
      $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
1248

    
1249
      foreach ($items as $delta => $item) {
1250
        $label = $handler->getLabel($item['entity']);
1251
        // If the link is to be displayed and the entity has a uri, display a link.
1252
        // Note the assignment ($url = ) here is intended to be an assignment.
1253
        if ($display['settings']['link'] && ($uri = entity_uri($field['settings']['target_type'], $item['entity']))) {
1254
          $result[$delta] = array('#markup' => l($label, $uri['path'], $uri['options']));
1255
        }
1256
        else {
1257
          $result[$delta] = array('#markup' => check_plain($label));
1258
        }
1259
      }
1260
      break;
1261

    
1262
    case 'entityreference_entity_id':
1263
      foreach ($items as $delta => $item) {
1264
        $result[$delta] = array('#markup' => check_plain($item['target_id']));
1265
      }
1266
      break;
1267

    
1268
    case 'entityreference_entity_view':
1269
      $target_langcode = $langcode;
1270
      if (!empty($settings['use_content_language']) && !empty($GLOBALS['language_content']->language)) {
1271
        $target_langcode = $GLOBALS['language_content']->language;
1272
      }
1273

    
1274
      foreach ($items as $delta => $item) {
1275
        // Protect ourselves from recursive rendering.
1276
        static $depth = 0;
1277
        $depth++;
1278
        if ($depth > 20) {
1279
          throw new EntityReferenceRecursiveRenderingException(t('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $entity_type, '@entity_id' => $item['target_id'])));
1280
        }
1281

    
1282
        $target_entity = clone $item['entity'];
1283
        unset($target_entity->content);
1284
        $result[$delta] = entity_view($field['settings']['target_type'], array($item['target_id'] => $target_entity), $settings['view_mode'], $target_langcode, FALSE);
1285

    
1286
        if (empty($settings['links']) && isset($result[$delta][$field['settings']['target_type']][$item['target_id']]['links'])) {
1287
          $result[$delta][$field['settings']['target_type']][$item['target_id']]['links']['#access'] = FALSE;
1288
        }
1289
        $depth = 0;
1290
      }
1291
      break;
1292
  }
1293

    
1294
  return $result;
1295
}
1296

    
1297
/**
1298
 * Exception thrown when the entity view renderer goes into a potentially infinite loop.
1299
 */
1300
class EntityReferenceRecursiveRenderingException extends Exception {}
1301

    
1302
/**
1303
 * Implements hook_views_api().
1304
 */
1305
function entityreference_views_api() {
1306
  return array(
1307
    'api' => 3,
1308
    'path' => drupal_get_path('module', 'entityreference') . '/views',
1309
  );
1310
}