Projet

Général

Profil

Paste
Télécharger (16,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / uuid / uuid.entity.inc @ 87dbc3bf

1
<?php
2

    
3
/**
4
 * @file
5
 * Entity related functions for UUID module.
6
 */
7

    
8
/**
9
 * Entity UUID exception class.
10
 */
11
class UuidEntityException extends Exception {}
12

    
13
/**
14
 * Helper function that returns entity info for all supported core modules,
15
 * relevant for UUID functionality.
16
 *
17
 * @see uuid_entity_info()
18
 * @see uuid_schema_alter()
19
 * @see uuid_install()
20
 * @see uuid_uninstall()
21
 */
22
function uuid_get_core_entity_info() {
23
  $info = array();
24
  $info['user'] = array(
25
    'base table' => 'users',
26
    'entity keys' => array(
27
      'uuid' => 'uuid',
28
    ),
29
  );
30
  $info['node'] = array(
31
    'base table' => 'node',
32
    'revision table' => 'node_revision',
33
    'entity keys' => array(
34
      'uuid' => 'uuid',
35
      'revision uuid' => 'vuuid',
36
    ),
37
  );
38
  if (module_exists('comment')) {
39
    $info['comment'] = array(
40
      'base table' => 'comment',
41
      'entity keys' => array(
42
        'uuid' => 'uuid',
43
      ),
44
    );
45
  }
46
  if (module_exists('file')) {
47
    $info['file'] = array(
48
      'base table' => 'file_managed',
49
      'entity keys' => array(
50
        'uuid' => 'uuid',
51
      ),
52
    );
53
  }
54
  if (module_exists('taxonomy')) {
55
    $info['taxonomy_term'] = array(
56
      'base table' => 'taxonomy_term_data',
57
      'entity keys' => array(
58
        'uuid' => 'uuid',
59
      ),
60
    );
61
  }
62
  if (module_exists('field_collection')) {
63
    $info['field_collection_item'] = array(
64
      'base table' => 'field_collection_item',
65
      'entity keys' => array(
66
        'uuid' => 'uuid',
67
      ),
68
    );
69
  }
70
  return $info;
71
}
72

    
73
/**
74
 * @defgroup uuid_entity_hooks UUID implementation of Entity API
75
 * @{
76
 */
77

    
78
/**
79
 * Implements of hook_entity_info_alter().
80
 *
81
 * @see uuid_core_entity_info().
82
 */
83
function uuid_entity_info_alter(&$info) {
84
  foreach (uuid_get_core_entity_info() as $entity_type => $core_info) {
85
    $info[$entity_type]['uuid'] = TRUE;
86
    $info[$entity_type]['entity keys']['uuid'] = $core_info['entity keys']['uuid'];
87
    if (!empty($core_info['entity keys']['revision uuid'])) {
88
      $info[$entity_type]['entity keys']['revision uuid'] = $core_info['entity keys']['revision uuid'];
89
    }
90
  }
91
}
92

    
93
/**
94
 * Implements of hook_entity_property_info_alter().
95
 *
96
 * This adds the UUID as an entity property for all UUID-enabled entities
97
 * which automatically gives us token and Rules integration.
98
 */
99
function uuid_entity_property_info_alter(&$info) {
100
  foreach (entity_get_info() as $entity_type => $entity_info) {
101
    if (isset($entity_info['uuid']) && $entity_info['uuid'] == TRUE && !empty($entity_info['entity keys']['uuid'])) {
102
      $info[$entity_type]['properties'][$entity_info['entity keys']['uuid']] = array(
103
        'label' => t('UUID'),
104
        'type' => 'text',
105
        'description' => t('The universally unique ID.'),
106
        'schema field' => $entity_info['entity keys']['uuid'],
107
      );
108
      if (!empty($entity_info['entity keys']['revision uuid'])) {
109
        $info[$entity_type]['properties'][$entity_info['entity keys']['revision uuid']] = array(
110
          'label' => t('Revision UUID'),
111
          'type' => 'text',
112
          'description' => t("The revision's universally unique ID."),
113
          'schema field' => $entity_info['entity keys']['revision uuid'],
114
        );
115
      }
116
    }
117
  }
118
}
119

    
120
/**
121
 * Implements of hook_entity_presave().
122
 *
123
 * This is where all UUID-enabled entities get their UUIDs.
124
 */
125
function uuid_entity_presave($entity, $entity_type) {
126
  $info = entity_get_info($entity_type);
127
  if (isset($info['uuid']) && $info['uuid'] == TRUE && !empty($info['entity keys']['uuid'])) {
128
    $uuid_key = $info['entity keys']['uuid'];
129
    if (empty($entity->{$uuid_key})) {
130
      $entity->{$uuid_key} = uuid_generate();
131
    }
132
    if (!empty($info['entity keys']['revision uuid'])) {
133
      $vuuid_key = $info['entity keys']['revision uuid'];
134
      if ((isset($entity->revision) && $entity->revision == TRUE) || empty($entity->{$vuuid_key})) {
135
        $entity->{$vuuid_key} = uuid_generate();
136
      }
137
    }
138
  }
139
}
140

    
141
/**
142
 * @} End of "UUID implementation of Entity API"
143
 */
144

    
145
/**
146
 * @defgroup uuid_entity_support UUID support for Entity API
147
 * @{
148
 * Functions that extends the Entity API with UUID support.
149
 */
150

    
151
/**
152
 * Load entities by their UUID, that only should containing UUID references.
153
 *
154
 * This function is mostly useful if you want to load an entity from the local
155
 * database that only should contain UUID references.
156
 *
157
 * @see entity_load()
158
 */
159
function entity_uuid_load($entity_type, $uuids = array(), $conditions = array(), $reset = FALSE) {
160
  $ids = entity_get_id_by_uuid($entity_type, $uuids);
161
  $results = entity_load($entity_type, $ids, $conditions, $reset);
162
  $entities = array();
163

    
164
  // We need to do this little magic here, because objects are passed by
165
  // reference. And because hook_entity_uuid_load() has the intention changing
166
  // primary properties and fields from local IDs to UUIDs it will also change
167
  // DrupalDefaultEntityController::entityCache by reference which is a static
168
  // cache of entities. And that is not something we want.
169
  foreach ($results as $key => $entity) {
170
    // This will avoid passing our loaded entities by reference.
171
    $entities[$key] = clone $entity;
172
  }
173

    
174
  entity_make_entity_universal($entity_type, $entities);
175

    
176
  return $entities;
177
}
178

    
179
/**
180
 * Helper function to make an entity universal (i.e. only global references).
181
 */
182
function entity_make_entity_universal($entity_type, $entities) {
183
  // Let other modules transform local ID references to UUID references.
184
  if (!empty($entities)) {
185
    $hook = 'entity_uuid_load';
186
    foreach (module_implements($hook) as $module) {
187
      $function = $module . '_' . $hook;
188
      if (function_exists($function)) {
189
        $function($entities, $entity_type);
190
      }
191
    }
192
  }
193
}
194

    
195
/**
196
 * Permanently saves an entity by its UUID.
197
 *
198
 * This function depends on the Entity API module to provide the
199
 * 'entity_save()' function.
200
 *
201
 * This function is mostly useful if you want to save an entity into the local
202
 * database that only contains UUID references.
203
 *
204
 * @see entity_save()
205
 */
206
function entity_uuid_save($entity_type, $entity) {
207
  // This function, and this function only, depends on the entity module.
208
  if (!module_exists('entity')) {
209
    throw new UuidEntityException(t('Calling %function requires the Entity API module (!link).', array('%function' => __FUNCTION__, '!link' => 'http://drupal.org/project/entity')));
210
  }
211

    
212
  entity_make_entity_local($entity_type, $entity);
213

    
214
  // Save the entity.
215
  entity_save($entity_type, $entity);
216

    
217
  $hook = 'entity_uuid_save';
218
  foreach (module_implements($hook) as $module) {
219
    $function = $module . '_' . $hook;
220
    if (function_exists($function)) {
221
      $function($entity, $entity_type);
222
    }
223
  }
224
}
225

    
226
/**
227
 * Helper function to make an entity local (i.e. only local references).
228
 */
229
function entity_make_entity_local($entity_type, $entity) {
230
  $info = entity_get_info($entity_type);
231
  if (isset($info['uuid']) && $info['uuid'] == TRUE && !empty($info['entity keys']['uuid'])) {
232
    // Get the keys for local ID and UUID.
233
    $id_key = $info['entity keys']['id'];
234
    $uuid_key = $info['entity keys']['uuid'];
235

    
236
    // UUID entites must always provide a valid UUID when saving in order to do
237
    // the correct mapping between local and global IDs.
238
    if (empty($entity->{$uuid_key}) || !uuid_is_valid($entity->{$uuid_key})) {
239
      throw new UuidEntityException(t('Trying to save a @type entity with empty or invalid UUID.', array('@type' => $info['label'])));
240
    }
241

    
242
    // Fetch the local ID by its UUID.
243
    $ids = entity_get_id_by_uuid($entity_type, array($entity->{$uuid_key}));
244
    $id = reset($ids);
245
    // Set the correct local ID.
246
    if (empty($id)) {
247
      unset($entity->{$id_key});
248
      $entity->is_new = TRUE;
249
    }
250
    else {
251
      $entity->{$id_key} = $id;
252
      $entity->is_new = FALSE;
253
    }
254

    
255
    if (!empty($info['entity keys']['revision uuid'])) {
256
      // Get the keys for local revison ID and revision UUID.
257
      $vid_key = $info['entity keys']['revision'];
258
      $vuuid_key = $info['entity keys']['revision uuid'];
259
      $vid = NULL;
260
      // Fetch the local revision ID by its UUID.
261
      if (isset($entity->{$vuuid_key})) {
262
        $vids = entity_get_id_by_uuid($entity_type, array($entity->{$vuuid_key}), TRUE);
263
        $vid = reset($vids);
264
      }
265
      if (empty($vid) && isset($entity->{$vid_key})) {
266
        unset($entity->{$vid_key});
267
      }
268
      elseif (!empty($vid)) {
269
        $entity->{$vid_key} = $vid;
270
      }
271
      // Nodes need this when trying to save an existing node without a vid.
272
      if ($entity_type == 'node' && !isset($entity->vid) && !$entity->is_new) {
273
        $entity->revision = 0;
274
        $entity->vid = db_select('node', 'n')
275
          ->condition('n.nid', $entity->nid)
276
          ->fields('n', array('vid'))
277
          ->execute()
278
          ->fetchField();
279
      }
280
    }
281

    
282
    // Let other modules transform UUID references to local ID references.
283
    $hook = 'entity_uuid_presave';
284
    foreach (module_implements($hook) as $module) {
285
      $function = $module . '_' . $hook;
286
      if (function_exists($function)) {
287
        $function($entity, $entity_type);
288
      }
289
    }
290
  }
291
  else {
292
    throw new UuidEntityException(t('Trying to operate on a @type entity, which doesn\'t support UUIDs.', array('@type' => $info['label'])));
293
  }
294
}
295

    
296
/**
297
 * Permanently delete the given entity by its UUID.
298
 *
299
 * This function depends on the Entity API module to provide the
300
 * 'entity_delete()' function.
301
 *
302
 * @see entity_delete()
303
 */
304
function entity_uuid_delete($entity_type, $uuid) {
305
  // This function, and this function only, depends on the entity module.
306
  if (!module_exists('entity')) {
307
    throw new UuidEntityException(t('Calling %function requires the Entity API module (!link).', array('%function' => __FUNCTION__, '!link' => 'http://drupal.org/project/entity')));
308
  }
309

    
310
  $info = entity_get_info($entity_type);
311
  if (isset($info['uuid']) && $info['uuid'] == TRUE) {
312
    // Fetch the local ID by its UUID.
313
    $ids = entity_get_id_by_uuid($entity_type, array($uuid));
314
    $id = reset($ids);
315

    
316
    // Let other modules transform UUID references to local ID references.
317
    $hook = 'entity_uuid_delete';
318
    foreach (module_implements($hook) as $module) {
319
      $function = $module . '_' . $hook;
320
      if (function_exists($function)) {
321
        $function($entity, $entity_type);
322
      }
323
    }
324

    
325
    // Delete the entity.
326
    return entity_delete($entity_type, $id);
327
  }
328
  else {
329
    throw new UuidEntityException(t('Trying to delete a @type entity, which doesn\'t support UUIDs.', array('@type' => $info['label'])));
330
  }
331
}
332

    
333
/**
334
 * Helper function that retrieves entity IDs by their UUIDs.
335
 *
336
 * @todo
337
 *   Statically cache as many IDs as possible and limit the query.
338
 *
339
 * @param $entity_type
340
 *   The entity type we should be dealing with.
341
 * @param $uuids
342
 *   An array of UUIDs for which we should find their entity IDs. If $revision
343
 *   is TRUE this should be revision UUIDs instead.
344
 * @param $revision
345
 *   If TRUE the revision IDs is returned instead.
346
 * @return
347
 *   Array of entity IDs keyed by their UUIDs. If $revision is TRUE revision
348
 *   IDs and UUIDs are returned instead.
349
 */
350
function entity_get_id_by_uuid($entity_type, $uuids, $revision = FALSE) {
351
  if (empty($uuids)) {
352
    return array();
353
  }
354
  $info = entity_get_info($entity_type);
355
  // Find out what entity keys to use.
356
  if (!$revision) {
357
    $table = $info['base table'];
358
    $id_key = $info['entity keys']['id'];
359
    $uuid_key = $info['entity keys']['uuid'];
360
  }
361
  elseif (isset($info['revision table'])) {
362
    $table = $info['revision table'];
363
    $id_key = $info['entity keys']['revision'];
364
    $uuid_key = $info['entity keys']['revision uuid'];
365
  }
366
  // If we want revision IDs, but the entity doesn't support it. Return empty.
367
  else {
368
    return array();
369
  }
370

    
371
  // Get all UUIDs in one query.
372
  return db_select($table, 't')
373
    ->fields('t', array($uuid_key, $id_key))
374
    ->condition($uuid_key, array_values($uuids), 'IN')
375
    ->execute()
376
    ->fetchAllKeyed();
377
}
378

    
379
/**
380
 * Helper function that retrieves UUIDs by their entity IDs.
381
 *
382
 * @todo
383
 *   Statically cache as many IDs as possible and limit the query.
384
 *
385
 * @param $entity_type
386
 *   The entity type we should be dealing with.
387
 * @param $ids
388
 *   An array of entity IDs for which we should find their UUIDs. If $revision
389
 *   is TRUE this should be revision IDs instead.
390
 * @param $revision
391
 *   If TRUE the revision UUIDs is returned instead.
392
 * @return
393
 *   Array of entity UUIDs keyed by their IDs. If $revision is TRUE revision
394
 *   IDs and UUIDs are returned instead.
395
 */
396
function entity_get_uuid_by_id($entity_type, $ids, $revision = FALSE) {
397
  if (empty($ids)) {
398
    return array();
399
  }
400
  $info = entity_get_info($entity_type);
401
  // Find out what entity keys to use.
402
  if (!$revision) {
403
    $table = $info['base table'];
404
    $id_key = $info['entity keys']['id'];
405
    $uuid_key = $info['entity keys']['uuid'];
406
  }
407
  elseif (isset($info['revision table'])) {
408
    $table = $info['revision table'];
409
    $id_key = $info['entity keys']['revision'];
410
    $uuid_key = $info['entity keys']['revision uuid'];
411
  }
412
  // If we want revision UUIDs, but the entity doesn't support it. Return empty.
413
  else {
414
    return array();
415
  }
416

    
417
  // Get all UUIDs in one query.
418
  return db_select($table, 't')
419
    ->fields('t', array($id_key, $uuid_key))
420
    ->condition($id_key, array_values($ids), 'IN')
421
    ->execute()
422
    ->fetchAllKeyed();
423
}
424

    
425
/**
426
 * Helper function to change entity properties from ID to UUID.
427
 *
428
 * We never change user UID 0 or 1 to UUIDs. Those are low level user accounts
429
 * ("anonymous" and "root") that needs to be identified consistently across
430
 * any system.
431
 *
432
 * @todo
433
 *   Add tests for this function.
434
 *
435
 * @param $objects
436
 *   An array of objects that should get $properties changed. Can be either an
437
 *   entity object or a field items array.
438
 * @param $entity_type
439
 *   The type of entity that all $properties refers to.
440
 * @param $properties
441
 *   An array of properties that should be changed. All properties must refer to
442
 *   the same type of entity (the one referenced in $entity_type).
443
 */
444
function entity_property_id_to_uuid(&$objects, $entity_type, $properties) {
445
  if (!is_array($objects)) {
446
    $things = array(&$objects);
447
  }
448
  else {
449
    $things = &$objects;
450
  }
451
  if (!is_array($properties)) {
452
    $properties = array($properties);
453
  }
454
  $ids = array();
455
  $values = array();
456
  $i = 0;
457
  foreach ($things as &$object) {
458
    foreach ($properties as $property) {
459
      // This is probably an entity object.
460
      if (is_object($object) && isset($object->{$property})) {
461
        $values[$i] = &$object->{$property};
462
      }
463
      // This is probably a field items array.
464
      elseif (is_array($object) && isset($object[$property])) {
465
        $values[$i] = &$object[$property];
466
      }
467
      else {
468
        $i++;
469
        continue;
470
      }
471
      if (!($entity_type == 'user' && ($values[$i] == 0 || $values[$i] == 1))) {
472
        $ids[] = $values[$i];
473
      }
474
      $i++;
475
    }
476
  }
477
  $uuids = entity_get_uuid_by_id($entity_type, $ids);
478
  foreach ($values as $i => $value) {
479
    if (isset($uuids[$value])) {
480
      $values[$i] = $uuids[$value];
481
    }
482
  }
483
}
484

    
485
/**
486
 * Helper function to change entity properties from UUID to ID.
487
 *
488
 * @todo
489
 *   Add tests for this function.
490
 *
491
 * @param $objects
492
 *   An array of objects that should get $properties changed. Can be either an
493
 *   entity object or a field items array.
494
 * @param $entity_type
495
 *   The type of entity that all $properties refers to.
496
 * @param $properties
497
 *   An array of properties that should be changed. All properties must refer to
498
 *   the same type of entity (the one referenced in $entity_type).
499
 */
500
function entity_property_uuid_to_id(&$objects, $entity_type, $properties) {
501
  if (!is_array($objects)) {
502
    $things = array(&$objects);
503
  }
504
  else {
505
    $things = &$objects;
506
  }
507
  if (!is_array($properties)) {
508
    $properties = array($properties);
509
  }
510
  $uuids = array();
511
  $values = array();
512
  $i = 0;
513
  foreach ($things as &$object) {
514
    foreach ($properties as $property) {
515
      // This is probably an entity object.
516
      if (is_object($object) && isset($object->{$property})) {
517
        $values[$i] = &$object->{$property};
518
      }
519
      // This is probably a field items array.
520
      elseif (is_array($object) && isset($object[$property])) {
521
        $values[$i] = &$object[$property];
522
      }
523
      else {
524
        $i++;
525
        continue;
526
      }
527
      if (uuid_is_valid($values[$i])) {
528
        $uuids[] = $values[$i];
529
      }
530
      $i++;
531
    }
532
  }
533
  $ids = entity_get_id_by_uuid($entity_type, $uuids);
534
  foreach ($values as $i => $value) {
535
    if (isset($ids[$value])) {
536
      $values[$i] = $ids[$value];
537
    }
538
  }
539
}
540

    
541
/**
542
 * @} End of "UUID support for Entity API"
543
 */