Projet

Général

Profil

Paste
Télécharger (32,5 ko) Statistiques
| Branche: | Révision:

root / htmltest / sites / all / modules / entity / modules / callbacks.inc @ dd54aff9

1
<?php
2

    
3
/**
4
 * @file
5
 * Provides various callbacks for the whole core module integration.
6
 */
7

    
8
/**
9
 * Callback for getting properties of an entity.
10
 */
11
function entity_metadata_entity_get_properties($entity, array $options, $name, $entity_type) {
12
  if ($name == 'url') {
13
    $return = entity_uri($entity_type, $entity);
14
    return url($return['path'], $return['options'] + $options);
15
  }
16
}
17

    
18
/**
19
 * Callback for getting book node properties.
20
 * @see entity_metadata_book_entity_info_alter()
21
 */
22
function entity_metadata_book_get_properties($node, array $options, $name, $entity_type) {
23
  if (!isset($node->book['bid'])) {
24
    throw new EntityMetadataWrapperException('This node is no book page.');
25
  }
26
  switch ($name) {
27
    case 'book':
28
      return $node->book['bid'];
29

    
30
    case 'book_ancestors':
31
      $ancestors = array();
32
      while (!empty($node->book['plid'])) {
33
        $link = book_link_load($node->book['plid']);
34
        array_unshift($ancestors, $link['nid']);
35
        $node = node_load($link['nid']);
36
      }
37
      return $ancestors;
38
  }
39
}
40

    
41
/**
42
 * Callback for getting comment properties.
43
 * @see entity_metadata_comment_entity_info_alter()
44
 */
45
function entity_metadata_comment_get_properties($comment, array $options, $name) {
46
  switch ($name) {
47
    case 'name':
48
      return $comment->name;
49

    
50
    case 'mail':
51
      if ($comment->uid != 0) {
52
        $account = user_load($comment->uid);
53
        return $account->mail;
54
      }
55
      return $comment->mail;
56

    
57
    case 'edit_url':
58
      return url('comment/edit/' . $comment->cid, $options);
59

    
60
    case 'parent':
61
      if (!empty($comment->pid)) {
62
        return $comment->pid;
63
      }
64
      // There is no parent comment.
65
      return NULL;
66
  }
67
}
68

    
69
/**
70
 * Callback for setting comment properties.
71
 * @see entity_metadata_comment_entity_info_alter()
72
 */
73
function entity_metadata_comment_setter($comment, $name, $value) {
74
  switch ($name) {
75
    case 'node':
76
      $comment->nid = $value;
77
      // Also set the bundle name.
78
      $node = node_load($value);
79
      $comment->node_type = 'comment_node_' . $node->type;
80
      break;
81
  }
82
}
83

    
84
/**
85
 * Callback for getting comment related node properties.
86
 * @see entity_metadata_comment_entity_info_alter()
87
 */
88
function entity_metadata_comment_get_node_properties($node, array $options, $name, $entity_type) {
89
  switch ($name) {
90
    case 'comment_count':
91
      return isset($node->comment_count) ? $node->comment_count : 0;
92

    
93
    case 'comment_count_new':
94
      return comment_num_new($node->nid);
95
  }
96
}
97

    
98
/**
99
 * Getter callback for getting global languages.
100
 */
101
function entity_metadata_locale_get_languages($data, array $options, $name) {
102
  return isset($GLOBALS[$name]) ? $GLOBALS[$name]->language : NULL;
103
}
104

    
105
/**
106
 * Getter callback for getting the preferred user language.
107
 */
108
function entity_metadata_locale_get_user_language($account, array $options, $name) {
109
  return user_preferred_language($account)->language;
110
}
111

    
112
/**
113
 * Return the options lists for the node and comment status property.
114
 */
115
function entity_metadata_status_options_list() {
116
  return array(
117
    NODE_PUBLISHED => t('Published'),
118
    NODE_NOT_PUBLISHED => t('Unpublished'),
119
  );
120
}
121

    
122
/**
123
 * Callback for getting node properties.
124
 *
125
 * @see entity_metadata_node_entity_info_alter()
126
 */
127
function entity_metadata_node_get_properties($node, array $options, $name, $entity_type) {
128
  switch ($name) {
129
    case 'is_new':
130
      return empty($node->nid) || !empty($node->is_new);
131

    
132
    case 'source':
133
      if (!empty($node->tnid) && $source = node_load($node->tnid)) {
134
        return $source;
135
      }
136
      return NULL;
137

    
138
    case 'edit_url':
139
      return url('node/' . $node->nid . '/edit', $options);
140

    
141
    case 'author':
142
      return !empty($node->uid) ? $node->uid : drupal_anonymous_user();
143
  }
144
}
145

    
146
/**
147
 * Callback for determing access for node revision related properties.
148
 */
149
function entity_metadata_node_revision_access($op, $name, $entity = NULL, $account = NULL) {
150
  return $op == 'view' ? user_access('view revisions', $account) : user_access('administer nodes', $account);
151
}
152

    
153
/**
154
 * Callback for getting poll properties.
155
 * @see entity_metadata_poll_entity_info_alter()
156
 */
157
function entity_metadata_poll_node_get_properties($node, array $options, $name) {
158
  $total_votes = $highest_votes = 0;
159
  foreach ($node->choice as $choice) {
160
    if ($choice['chvotes'] > $highest_votes) {
161
      $winner = $choice;
162
      $highest_votes = $choice['chvotes'];
163
    }
164
    $total_votes = $total_votes + $choice['chvotes'];
165
  }
166

    
167
  if ($name == 'poll_duration') {
168
    return $node->runtime;
169
  }
170
  elseif ($name == 'poll_votes') {
171
    return $total_votes;
172
  }
173
  elseif (!isset($winner)) {
174
    // There is no poll winner yet.
175
    return NULL;
176
  }
177
  switch ($name) {
178
    case 'poll_winner_votes':
179
        return $winner['chvotes'];
180

    
181
    case 'poll_winner':
182
        return $winner['chtext'];
183

    
184
    case 'poll_winner_percent':
185
        return ($winner['chvotes'] / $total_votes) * 100;
186
  }
187
}
188

    
189
/**
190
 * Callback for getting statistics properties.
191
 * @see entity_metadata_statistics_entity_info_alter()
192
 */
193
function entity_metadata_statistics_node_get_properties($node, array $options, $name) {
194
  $statistics = (array) statistics_get($node->nid);
195
  $statistics += array('totalcount' => 0, 'daycount' => 0, 'timestamp' => NULL);
196

    
197
  switch ($name) {
198
    case 'views':
199
      return $statistics['totalcount'];
200

    
201
    case 'day_views':
202
      return $statistics['daycount'];
203

    
204
    case 'last_view':
205
      return $statistics['timestamp'];
206
  }
207
}
208

    
209
/**
210
 * Access callback for restricted node statistics properties.
211
 */
212
function entity_metadata_statistics_properties_access($op, $property, $entity = NULL, $account = NULL) {
213
  if ($property == 'views' && user_access('view post access counter', $account)) {
214
    return TRUE;
215
  }
216
  return user_access('access statistics', $account);
217
}
218

    
219
/**
220
 * Callback for getting site-wide properties.
221
 * @see entity_metadata_system_entity_info_alter()
222
 */
223
function entity_metadata_system_get_properties($data = FALSE, array $options, $name) {
224
  switch ($name) {
225
    case 'name':
226
      return variable_get('site_name', 'Drupal');
227

    
228
    case 'url':
229
      return url('<front>', $options);
230

    
231
    case 'login_url':
232
      return url('user', $options);
233

    
234
    case 'current_user':
235
      return $GLOBALS['user']->uid ? $GLOBALS['user']->uid : drupal_anonymous_user();
236

    
237
    case 'current_date':
238
      return REQUEST_TIME;
239

    
240
    case 'current_page':
241
      // Subsequent getters of the struct retrieve the actual values.
242
      return array();
243

    
244
    default:
245
      return variable_get('site_' . $name, '');
246
  }
247
}
248

    
249
/**
250
 * Callback for getting properties for the current page request.
251
 * @see entity_metadata_system_entity_info_alter()
252
 */
253
function entity_metadata_system_get_page_properties($data = array(), array $options, $name) {
254
  switch ($name) {
255
    case 'url':
256
      return $GLOBALS['base_root'] . request_uri();
257
  }
258
}
259

    
260
/**
261
 * Callback for getting file properties.
262
 * @see entity_metadata_system_entity_info_alter()
263
 */
264
function entity_metadata_system_get_file_properties($file, array $options, $name) {
265
  switch ($name) {
266
    case 'name':
267
      return $file->filename;
268

    
269
    case 'mime':
270
      return $file->filemime;
271

    
272
    case 'size':
273
      return $file->filesize;
274

    
275
    case 'url':
276
      return url(file_create_url($file->uri), $options);
277

    
278
    case 'owner':
279
      return $file->uid;
280
  }
281
}
282

    
283
/**
284
 * Callback for getting term properties.
285
 *
286
 * @see entity_metadata_taxonomy_entity_info_alter()
287
 */
288
function entity_metadata_taxonomy_term_get_properties($term, array $options, $name) {
289
  switch ($name) {
290
    case 'node_count':
291
      return count(taxonomy_select_nodes($term->tid));
292

    
293
    case 'description':
294
      return check_markup($term->description, isset($term->format) ? $term->format : NULL, '', TRUE);
295

    
296
    case 'parent':
297
      if (isset($term->parent[0]) && !is_array(isset($term->parent[0]))) {
298
        return $term->parent;
299
      }
300
      return array_keys(taxonomy_get_parents($term->tid));
301

    
302
    case 'parents_all':
303
      // We have to return an array of ids.
304
      $tids = array();
305
      foreach (taxonomy_get_parents_all($term->tid) as $parent) {
306
        $tids[] = $parent->tid;
307
      }
308
      return $tids;
309
  }
310
}
311

    
312
/**
313
 * Callback for setting term properties.
314
 *
315
 * @see entity_metadata_taxonomy_entity_info_alter()
316
 */
317
function entity_metadata_taxonomy_term_setter($term, $name, $value) {
318
  switch ($name) {
319
    case 'vocabulary':
320
      // Make sure to update the taxonomy bundle key, so load the vocabulary.
321
      // Support both, loading by name or ID.
322
      $vocabulary = is_numeric($value) ? taxonomy_vocabulary_load($value) : taxonomy_vocabulary_machine_name_load($value);
323
      $term->vocabulary_machine_name = $vocabulary->machine_name;
324
      return $term->vid = $vocabulary->vid;
325
    case 'parent':
326
      return $term->parent = $value;
327
  }
328
}
329

    
330
/**
331
 * Callback for getting vocabulary properties.
332
 * @see entity_metadata_taxonomy_entity_info_alter()
333
 */
334
function entity_metadata_taxonomy_vocabulary_get_properties($vocabulary, array $options, $name) {
335
  switch ($name) {
336
    case 'term_count':
337
      $sql = "SELECT COUNT (1) FROM {taxonomy_term_data} td WHERE td.vid = :vid";
338
      return db_query($sql, array(':vid' => $vocabulary->vid))->fetchField();
339
  }
340
}
341

    
342
/**
343
 * Callback for getting user properties.
344
 * @see entity_metadata_user_entity_info_alter()
345
 */
346
function entity_metadata_user_get_properties($account, array $options, $name, $entity_type) {
347
  switch ($name) {
348
    case 'last_access':
349
      // In case there was no access the value is 0, but we have to return NULL.
350
      return empty($account->access) ? NULL : $account->access;
351

    
352
    case 'last_login':
353
      return empty($account->login) ? NULL : $account->login;
354

    
355
    case 'name':
356
      return empty($account->uid) ? variable_get('anonymous', t('Anonymous')) : $account->name;
357

    
358
    case 'url':
359
      if (empty($account->uid)) {
360
        return NULL;
361
      }
362
      $return = entity_uri('user', $account);
363
      return $return ? url($return['path'], $return['options'] + $options) : '';
364

    
365
    case 'edit_url':
366
      return empty($account->uid) ? NULL : url("user/$account->uid/edit", $options);
367

    
368
    case 'roles':
369
      return isset($account->roles) ? array_keys($account->roles) : array();
370

    
371
    case 'theme':
372
      return empty($account->theme) ? variable_get('theme_default', 'bartik') : $account->theme;
373
  }
374
}
375

    
376
/**
377
 * Callback for setting user properties.
378
 * @see entity_metadata_user_entity_info_alter()
379
 */
380
function entity_metadata_user_set_properties($account, $name, $value) {
381
  switch ($name) {
382
    case 'roles':
383
      $account->roles = array_intersect_key(user_roles(), array_flip($value));
384
      break;
385
  }
386
}
387

    
388
/**
389
 * Options list callback returning all user roles.
390
 */
391
function entity_metadata_user_roles($property_name = 'roles', $info = array(), $op = 'edit') {
392
  $roles = user_roles();
393
  if ($op == 'edit') {
394
    unset($roles[DRUPAL_AUTHENTICATED_RID], $roles[DRUPAL_ANONYMOUS_RID]);
395
  }
396
  return $roles;
397
}
398

    
399
/**
400
 * Return the options lists for user status property.
401
 */
402
function entity_metadata_user_status_options_list() {
403
  return array(
404
    0 => t('Blocked'),
405
    1 => t('Active'),
406
  );
407
}
408

    
409
/**
410
 * Callback defining an options list for language properties.
411
 */
412
function entity_metadata_language_list() {
413
  $list = array();
414
  $list[LANGUAGE_NONE] = t('Language neutral');
415
  foreach (language_list() as $language) {
416
    $list[$language->language] = $language->name;
417
  }
418
  return $list;
419
}
420

    
421
/**
422
 * Callback for getting field property values.
423
 */
424
function entity_metadata_field_property_get($entity, array $options, $name, $entity_type, $info) {
425
  $field = field_info_field($name);
426
  $columns = array_keys($field['columns']);
427
  $langcode = isset($options['language']) ? $options['language']->language : LANGUAGE_NONE;
428
  $langcode = entity_metadata_field_get_language($entity_type, $entity, $field, $langcode, TRUE);
429
  $values = array();
430
  if (isset($entity->{$name}[$langcode])) {
431
    foreach ($entity->{$name}[$langcode] as $delta => $data) {
432
      $values[$delta] = $data[$columns[0]];
433
      if ($info['type'] == 'boolean' || $info['type'] == 'list<boolean>') {
434
        // Ensure that we have a clean boolean data type.
435
        $values[$delta] = (boolean) $values[$delta];
436
      }
437
    }
438
  }
439
  // For an empty single-valued field, we have to return NULL.
440
  return $field['cardinality'] == 1 ? ($values ? reset($values) : NULL) : $values;
441
}
442

    
443
/**
444
 * Callback for setting field property values.
445
 */
446
function entity_metadata_field_property_set($entity, $name, $value, $langcode, $entity_type, $info) {
447
  $field = field_info_field($name);
448
  $columns = array_keys($field['columns']);
449
  $langcode = entity_metadata_field_get_language($entity_type, $entity, $field, $langcode);
450
  $values = $field['cardinality'] == 1 ? array($value) : (array) $value;
451

    
452
  $items = array();
453
  foreach ($values as $delta => $value) {
454
    if (isset($value)) {
455
      $items[$delta][$columns[0]] = $value;
456
      if ($info['type'] == 'boolean' || $info['type'] == 'list<boolean>') {
457
        // Convert boolean values back to an integer for writing.
458
        $items[$delta][$columns[0]] = (integer) $items[$delta][$columns[0]] = $value;
459
      }
460
    }
461
  }
462
  $entity->{$name}[$langcode] = $items;
463
  // Empty the static field language cache, so the field system picks up any
464
  // possible new languages.
465
  drupal_static_reset('field_language');
466
}
467

    
468
/**
469
 * Callback returning the options list of a field.
470
 */
471
function entity_metadata_field_options_list($name, $info) {
472
  $field_property_info = $info;
473
  if (is_numeric($name) && isset($info['parent'])) {
474
    // The options list is to be returned for a single item of a multiple field.
475
    $field_property_info = $info['parent']->info();
476
    $name = $field_property_info['name'];
477
  }
478
  if (($field = field_info_field($name)) && isset($field_property_info['parent'])) {
479
    // Retrieve the wrapped entity holding the field.
480
    $wrapper = $field_property_info['parent'];
481
    try {
482
      $entity = $wrapper->value();
483
    }
484
    catch (EntityMetadataWrapperException $e) {
485
      // No data available.
486
      $entity = NULL;
487
    }
488
    $instance = $wrapper->getBundle() ? field_info_instance($wrapper->type(), $name, $wrapper->getBundle()) : NULL;
489
    return (array) module_invoke($field['module'], 'options_list', $field, $instance, $wrapper->type(), $entity);
490
  }
491
}
492

    
493
/**
494
 * Callback to verbatim get the data structure of a field. Useful for fields
495
 * that add metadata for their own data structure.
496
 */
497
function entity_metadata_field_verbatim_get($entity, array $options, $name, $entity_type, &$context) {
498
  // Set contextual info useful for getters of any child properties.
499
  $context['instance'] = field_info_instance($context['parent']->type(), $name, $context['parent']->getBundle());
500
  $context['field'] = field_info_field($name);
501
  $langcode = isset($options['language']) ? $options['language']->language : LANGUAGE_NONE;
502
  $langcode = entity_metadata_field_get_language($entity_type, $entity, $context['field'], $langcode, TRUE);
503

    
504
  if ($context['field']['cardinality'] == 1) {
505
    return isset($entity->{$name}[$langcode][0]) ? $entity->{$name}[$langcode][0] : NULL;
506
  }
507
  return isset($entity->{$name}[$langcode]) ? $entity->{$name}[$langcode] : array();
508
}
509

    
510
/**
511
 * Writes the passed field items in the object. Useful as field level setter
512
 * to set the whole data structure at once.
513
 */
514
function entity_metadata_field_verbatim_set($entity, $name, $items, $langcode, $entity_type) {
515
  $field = field_info_field($name);
516
  $langcode = entity_metadata_field_get_language($entity_type, $entity, $field, $langcode);
517
  $value = $field['cardinality'] == 1 ? array($items) : (array) $items;
518
  // Filter out any items set to NULL.
519
  $entity->{$name}[$langcode] = array_filter($value);
520

    
521
  // Empty the static field language cache, so the field system picks up any
522
  // possible new languages.
523
  drupal_static_reset('field_language');
524
}
525

    
526
/**
527
 * Helper for determining the field language to be used.
528
 *
529
 * Note that we cannot use field_language() as we are not about to display
530
 * values, but generally read/write values.
531
 *
532
 * @param $fallback
533
 *   (optional) Whether to fall back to the entity default language, if no
534
 *   value is available for the given language code yet.
535
 *
536
 * @return
537
 *   The language code to use.
538
 */
539
function entity_metadata_field_get_language($entity_type, $entity, $field, $langcode = LANGUAGE_NONE, $fallback = FALSE) {
540
  // Try to figure out the default language used by the entity.
541
  // With Drupal >= 7.15 we can use entity_language().
542
  if (function_exists('entity_language')) {
543
    $default_langcode = entity_language($entity_type, $entity);
544
  }
545
  else {
546
    $default_langcode = !empty($entity->language) ? $entity->language : LANGUAGE_NONE;
547
  }
548

    
549
  // Determine the right language to use.
550
  if ($default_langcode != LANGUAGE_NONE && field_is_translatable($entity_type, $field)) {
551
    $langcode = ($langcode != LANGUAGE_NONE) ? field_valid_language($langcode, $default_langcode) : $default_langcode;
552
    if (!isset($entity->{$field['field_name']}[$langcode]) && $fallback) {
553
      $langcode = $default_langcode;
554
    }
555
    return $langcode;
556
  }
557
  else {
558
    return LANGUAGE_NONE;
559
  }
560
}
561

    
562
/**
563
 * Callback for getting the sanitized text of 'text_formatted' properties.
564
 * This callback is used for both the 'value' and the 'summary'.
565
 */
566
function entity_metadata_field_text_get($item, array $options, $name, $type, $context) {
567
  // $name is either 'value' or 'summary'.
568
  if (!isset($item['safe_' . $name])) {
569
    // Apply input formats.
570
    $langcode = isset($options['language']) ? $options['language']->language : '';
571
    $format = isset($item['format']) ? $item['format'] : filter_default_format();
572
    $item['safe_' . $name] = check_markup($item[$name], $format, $langcode);
573
    // To speed up subsequent calls, update $item with the 'safe_value'.
574
    $context['parent']->set($item);
575
  }
576
  return $item['safe_' . $name];
577
}
578

    
579
/**
580
 * Defines the list of all available text formats.
581
 */
582
function entity_metadata_field_text_formats() {
583
  foreach (filter_formats() as $key => $format) {
584
    $formats[$key] = $format->name;
585
  }
586
  return $formats;
587
}
588

    
589
/**
590
 * Callback for getting the file entity of file fields.
591
 */
592
function entity_metadata_field_file_get($item) {
593
  return $item['fid'];
594
}
595

    
596
/**
597
 * Callback for setting the file entity of file fields.
598
 */
599
function entity_metadata_field_file_set(&$item, $property_name, $value) {
600
  $item['fid'] = $value;
601
}
602

    
603
/**
604
 * Callback for auto-creating file field $items.
605
 */
606
function entity_metadata_field_file_create_item($property_name, $context) {
607
  // 'fid' is required, so 'file' has to be set as initial property.
608
  return array('display' => isset($context['field']['settings']['display_default']) ? $context['field']['settings']['display_default'] : 0);
609
}
610

    
611
/**
612
 * Callback for validating file field $items.
613
 */
614
function entity_metadata_field_file_validate_item($items, $context) {
615
  // Allow NULL values.
616
  if (!isset($items)) {
617
    return TRUE;
618
  }
619

    
620
  // Stream-line $items for multiple vs non-multiple fields.
621
  $items = !entity_property_list_extract_type($context['type']) ? array($items) : (array) $items;
622

    
623
  foreach ($items as $item) {
624
    // File-field items require a valid file.
625
    if (!isset($item['fid']) || !file_load($item['fid'])) {
626
      return FALSE;
627
    }
628
    if (isset($context['property info']['display']) && !isset($item['display'])) {
629
      return FALSE;
630
    }
631
  }
632
  return TRUE;
633
}
634

    
635
/**
636
 * Access callback for the node entity.
637
 *
638
 * This function does not implement hook_node_access(), thus it may not be
639
 * called entity_metadata_node_access().
640
 *
641
 * @see entity_access()
642
 *
643
 * @param $op
644
 *   The operation being performed. One of 'view', 'update', 'create' or
645
 *   'delete'.
646
 * @param $node
647
 *   A node to check access for. Must be a node object. Must have nid,
648
 *   except in the case of 'create' operations.
649
 * @param $account
650
 *   The user to check for. Leave it to NULL to check for the global user.
651
 *
652
 * @throws EntityMalformedException
653
 *
654
 * @return boolean
655
 *   TRUE if access is allowed, FALSE otherwise.
656
 */
657
function entity_metadata_no_hook_node_access($op, $node = NULL, $account = NULL) {
658
  // First deal with the case where a $node is provided.
659
  if (isset($node)) {
660
    if ($op == 'create') {
661
      if (isset($node->type)) {
662
        return node_access($op, $node->type, $account);
663
      }
664
      else {
665
        throw new EntityMalformedException('Permission to create a node was requested but no node type was given.');
666
      }
667
    }
668
    // If a non-default revision is given, incorporate revision access.
669
    $default_revision = node_load($node->nid);
670
    if ($node->vid !== $default_revision->vid) {
671
      return _node_revision_access($node, $op, $account);
672
    }
673
    else {
674
      return node_access($op, $node, $account);
675
    }
676
  }
677
  // No node is provided. Check for access to all nodes.
678
  if (user_access('bypass node access', $account)) {
679
    return TRUE;
680
  }
681
  if (!user_access('access content', $account)) {
682
    return FALSE;
683
  }
684
  if ($op == 'view' && node_access_view_all_nodes($account)) {
685
    return TRUE;
686
  }
687
  return FALSE;
688
}
689

    
690
/**
691
 * Access callback for the user entity.
692
 */
693
function entity_metadata_user_access($op, $entity = NULL, $account = NULL, $entity_type) {
694
  $account = isset($account) ? $account : $GLOBALS['user'];
695
  // Grant access to the users own user account and to the anonymous one.
696
  if (isset($entity) && $op != 'delete' && (($entity->uid == $account->uid && $entity->uid) || (!$entity->uid && $op == 'view'))) {
697
    return TRUE;
698
  }
699
  if (user_access('administer users', $account) || user_access('access user profiles', $account) && $op == 'view' && $entity->status) {
700
    return TRUE;
701
  }
702
  return FALSE;
703
}
704

    
705
/**
706
 * Access callback for restricted user properties.
707
 */
708
function entity_metadata_user_properties_access($op, $property, $entity = NULL, $account = NULL) {
709
  if (user_access('administer users', $account)) {
710
    return TRUE;
711
  }
712
  $account = isset($account) ? $account : $GLOBALS['user'];
713
  // Flag to indicate if this user entity is the own user account.
714
  $is_own_account = isset($entity) && $account->uid == $entity->uid;
715
  switch ($property) {
716
    case 'name':
717
      // Allow view access to anyone with access to the entity.
718
      if ($op == 'view') {
719
        return TRUE;
720
      }
721
      // Allow edit access for own user name if the permission is satisfied.
722
      return $is_own_account && user_access('change own username', $account);
723
    case 'mail':
724
      // Allow access to own mail address.
725
      return $is_own_account;
726
    case 'roles':
727
      // Allow view access for own roles.
728
      return ($op == 'view' && $is_own_account);
729
  }
730
  return FALSE;
731
}
732

    
733
/**
734
 * Access callback for the comment entity.
735
 */
736
function entity_metadata_comment_access($op, $entity = NULL, $account = NULL) {
737
  // When determining access to a comment, 'comment_access' does not take any
738
  // access restrictions to the comment's associated node into account. If a
739
  // comment has an associated node, the user must be able to view it in order
740
  // to access the comment.
741
  if (isset($entity->nid)) {
742
    if (!entity_access('view', 'node', node_load($entity->nid), $account)) {
743
      return FALSE;
744
    }
745
  }
746

    
747
  // Comment administrators are allowed to perform all operations on all
748
  // comments.
749
  if (user_access('administer comments', $account)) {
750
    return TRUE;
751
  }
752

    
753
  // Unpublished comments can never be accessed by non-admins.
754
  if (isset($entity->status) && $entity->status == COMMENT_NOT_PUBLISHED) {
755
    return FALSE;
756
  }
757

    
758
  if (isset($entity) && $op == 'update') {
759
    // Because 'comment_access' only checks the current user, we need to do our
760
    // own access checking if an account was specified.
761
    if (!isset($account)) {
762
      return comment_access('edit', $entity);
763
    }
764
    else {
765
      return $account->uid && $account->uid == $entity->uid && user_access('edit own comments', $account);
766
    }
767
  }
768
  if (user_access('access comments', $account) && $op == 'view') {
769
    return TRUE;
770
  }
771
  return FALSE;
772
}
773

    
774
/**
775
 * Access callback for restricted comment properties.
776
 */
777
function entity_metadata_comment_properties_access($op, $property, $entity = NULL, $account = NULL) {
778
  return user_access('administer comments', $account);
779
}
780

    
781
/**
782
 * Access callback for the taxonomy entities.
783
 */
784
function entity_metadata_taxonomy_access($op, $entity = NULL, $account = NULL, $entity_type) {
785
  if ($entity_type == 'taxonomy_vocabulary') {
786
    return user_access('administer taxonomy', $account);
787
  }
788
  if (isset($entity) && $op == 'update' && !isset($account) && taxonomy_term_edit_access($entity)) {
789
    return TRUE;
790
  }
791
  if (user_access('administer taxonomy', $account) || user_access('access content', $account) && $op == 'view') {
792
    return TRUE;
793
  }
794
  return FALSE;
795
}
796

    
797
/**
798
 * Access callback for file entities.
799
 */
800
function entity_metadata_file_access($op, $file = NULL, $account = NULL, $entity_type) {
801
  // We can only check access for the current user, so return FALSE on other accounts.
802
  global $user;
803
  if ($op == 'view' && isset($file) && (!isset($account) || $user->uid == $account->uid)) {
804
    // Invoke hook_file_download() to obtain access information.
805
    foreach (module_implements('file_download') as $module) {
806
      $result = module_invoke($module, 'file_download', $file->uri);
807
      if ($result == -1) {
808
        return FALSE;
809
      }
810
    }
811
    return TRUE;
812
  }
813
  return FALSE;
814
}
815

    
816

    
817
/**
818
 * Callback to determine access for properties which are fields.
819
 */
820
function entity_metadata_field_access_callback($op, $name, $entity = NULL, $account = NULL, $entity_type) {
821
  $field = field_info_field($name);
822
  return field_access($op, $field, $entity_type, $entity, $account);
823
}
824

    
825
/**
826
 * Callback to create entity objects.
827
 */
828
function entity_metadata_create_object($values = array(), $entity_type) {
829
  $info = entity_get_info($entity_type);
830
  // Make sure at least the bundle and label properties are set.
831
  if (isset($info['entity keys']['bundle']) && $key = $info['entity keys']['bundle']) {
832
    $values += array($key => NULL);
833
  }
834
  if (isset($info['entity keys']['label']) && $key = $info['entity keys']['label']) {
835
    $values += array($key => NULL);
836
  }
837
  $entity = (object) $values;
838
  $entity->is_new = TRUE;
839
  return $entity;
840
}
841

    
842
/**
843
 * Callback to create a new comment.
844
 */
845
function entity_metadata_create_comment($values = array()) {
846
  $comment = (object) ($values + array(
847
    'status' => COMMENT_PUBLISHED,
848
    'pid' => 0,
849
    'subject' => '',
850
    'uid' => 0,
851
    'language' => LANGUAGE_NONE,
852
    'node_type' => NULL,
853
    'is_new' => TRUE,
854
  ));
855
  $comment->cid = FALSE;
856
  return $comment;
857
}
858

    
859
/**
860
 * Callback to create a new node.
861
 */
862
function entity_metadata_create_node($values = array()) {
863
  $node = (object) array(
864
    'type' => $values['type'],
865
    'language' => LANGUAGE_NONE,
866
    'is_new' => TRUE,
867
  );
868
  // Set some defaults.
869
  $node_options = variable_get('node_options_' . $node->type, array('status', 'promote'));
870
  foreach (array('status', 'promote', 'sticky') as $key) {
871
    $node->$key = (int) in_array($key, $node_options);
872
  }
873
  if (module_exists('comment') && !isset($node->comment)) {
874
    $node->comment = variable_get("comment_$node->type", COMMENT_NODE_OPEN);
875
  }
876
  // Apply the given values.
877
  foreach ($values as $key => $value) {
878
    $node->$key = $value;
879
  }
880
  return $node;
881
}
882

    
883
/**
884
 * Callback to save a user account.
885
 */
886
function entity_metadata_user_save($account) {
887
  $edit = (array) $account;
888
  // Don't save the hashed password as password.
889
  unset($edit['pass']);
890
  user_save($account, $edit);
891
}
892

    
893
/**
894
 * Callback to delete a file.
895
 * Watch out to not accidentilly implement hook_file_delete().
896
 */
897
function entity_metadata_delete_file($fid) {
898
  file_delete(file_load($fid), TRUE);
899
}
900

    
901
/**
902
 * Callback to view nodes.
903
 */
904
function entity_metadata_view_node($entities, $view_mode = 'full', $langcode = NULL) {
905
  $result = node_view_multiple($entities, $view_mode, 0, $langcode);
906
  // Make sure to key the result with 'node' instead of 'nodes'.
907
  return array('node' => reset($result));
908
}
909

    
910
/**
911
 * Callback to view comments.
912
 */
913
function entity_metadata_view_comment($entities, $view_mode = 'full', $langcode = NULL) {
914
  $build = array();
915
  $nodes = array();
916
  // The comments, indexed by nid and then by cid.
917
  $nid_comments = array();
918
  foreach ($entities as $cid => $comment) {
919
    $nid = $comment->nid;
920
    $nodes[$nid] = $nid;
921
    $nid_comments[$nid][$cid] = $comment;
922
  }
923
  $nodes = node_load_multiple(array_keys($nodes));
924
  foreach ($nid_comments as $nid => $comments) {
925
    $node = isset($nodes[$nid]) ? $nodes[$nid] : NULL;
926
    $build += comment_view_multiple($comments, $node, $view_mode, 0, $langcode);
927
  }
928
  return array('comment' => $build);
929
}
930

    
931
/**
932
 * Callback to view an entity, for which just ENTITYTYPE_view() is available.
933
 */
934
function entity_metadata_view_single($entities, $view_mode = 'full', $langcode = NULL, $entity_type) {
935
  $function = $entity_type . '_view';
936
  $build = array();
937
  foreach ($entities as $key => $entity) {
938
    $build[$entity_type][$key] = $function($entity, $view_mode, $langcode);
939
  }
940
  return $build;
941
}
942

    
943
/**
944
 * Callback to get the form of a node.
945
 */
946
function entity_metadata_form_node($node) {
947
  // Pre-populate the form-state with the right form include.
948
  $form_state['build_info']['args'] = array($node);
949
  form_load_include($form_state, 'inc', 'node', 'node.pages');
950
  return drupal_build_form($node->type . '_node_form', $form_state);
951
}
952

    
953
/**
954
 * Callback to get the form of a comment.
955
 */
956
function entity_metadata_form_comment($comment) {
957
  if (!isset($comment->node_type)) {
958
    $node = node_load($comment->nid);
959
    $comment->node_type = 'comment_node_' . $node->type;
960
  }
961
  return drupal_get_form($comment->node_type . '_form', $comment);
962
}
963

    
964
/**
965
 * Callback to get the form of a user account.
966
 */
967
function entity_metadata_form_user($account) {
968
  // Pre-populate the form-state with the right form include.
969
  $form_state['build_info']['args'] = array($account);
970
  form_load_include($form_state, 'inc', 'user', 'user.pages');
971
  return drupal_build_form('user_profile_form', $form_state);
972
}
973

    
974
/**
975
 * Callback to get the form of a term.
976
 */
977
function entity_metadata_form_taxonomy_term($term) {
978
  // Pre-populate the form-state with the right form include.
979
  $form_state['build_info']['args'] = array($term);
980
  form_load_include($form_state, 'inc', 'taxonomy', 'taxonomy.admin');
981
  return drupal_build_form('taxonomy_form_term', $form_state);
982
}
983

    
984
/**
985
 * Callback to get the form of a vocabulary.
986
 */
987
function entity_metadata_form_taxonomy_vocabulary($vocab) {
988
  // Pre-populate the form-state with the right form include.
989
  $form_state['build_info']['args'] = array($vocab);
990
  form_load_include($form_state, 'inc', 'taxonomy', 'taxonomy.admin');
991
  return drupal_build_form('taxonomy_form_vocabulary', $form_state);
992
}
993

    
994
/**
995
 * Callback to get the form for entities using the entity API admin ui.
996
 */
997
function entity_metadata_form_entity_ui($entity, $entity_type) {
998
  $info = entity_get_info($entity_type);
999
  $form_state = form_state_defaults();
1000
  // Add in the include file as the form API does else with the include file
1001
  // specified for the active menu item.
1002
  if (!empty($info['admin ui']['file'])) {
1003
    $path = isset($info['admin ui']['file path']) ? $info['admin ui']['file path'] : drupal_get_path('module', $info['module']);
1004
    $form_state['build_info']['files']['entity_ui'] = $path . '/' . $info['admin ui']['file'];
1005
    // Also load the include file.
1006
    if (file_exists($form_state['build_info']['files']['entity_ui'])) {
1007
      require_once DRUPAL_ROOT . '/' . $form_state['build_info']['files']['entity_ui'];
1008
    }
1009
  }
1010
  return entity_ui_get_form($entity_type, $entity, $op = 'edit', $form_state);
1011
}
1012

    
1013
/**
1014
 * Callback for querying entity properties having their values stored in the
1015
 * entities main db table.
1016
 */
1017
function entity_metadata_table_query($entity_type, $property, $value, $limit) {
1018
  $properties = entity_get_all_property_info($entity_type);
1019
  $info = $properties[$property] + array('schema field' => $property);
1020

    
1021
  $query = new EntityFieldQuery();
1022
  $query->entityCondition('entity_type', $entity_type, '=')
1023
        ->propertyCondition($info['schema field'], $value, is_array($value) ? 'IN' : '=')
1024
        ->range(0, $limit);
1025

    
1026
  $result = $query->execute();
1027
  return !empty($result[$entity_type]) ? array_keys($result[$entity_type]) : array();
1028
}
1029

    
1030
/**
1031
 * Callback for querying entities by field values. This function just queries
1032
 * for the value of the first specified column. Also it is only suitable for
1033
 * fields that don't process the data, so it's stored the same way as returned.
1034
 */
1035
function entity_metadata_field_query($entity_type, $property, $value, $limit) {
1036
  $query = new EntityFieldQuery();
1037
  $field = field_info_field($property);
1038
  $columns = array_keys($field['columns']);
1039

    
1040
  $query->entityCondition('entity_type', $entity_type, '=')
1041
        ->fieldCondition($field, $columns[0], $value, is_array($value) ? 'IN' : '=')
1042
        ->range(0, $limit);
1043

    
1044
  $result = $query->execute();
1045
  return !empty($result[$entity_type]) ? array_keys($result[$entity_type]) : array();
1046
}
1047

    
1048
/**
1049
 * Implements entity_uri() callback for file entities.
1050
 */
1051
function entity_metadata_uri_file($file) {
1052
  return array(
1053
    'path' => file_create_url($file->uri),
1054
  );
1055
}