summaryrefslogtreecommitdiff
path: root/sites/all/modules/entity/includes/entity.inc
blob: 2f504f36ad2fcce72cba1c10ffbfc4f7ad7bb8d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
<?php

/**
 * @file
 * Provides a base class for entities.
 */

/**
 * Interface for class based entities.
 */
interface EntityInterface {

  /**
   * Returns the internal, numeric identifier.
   *
   * Returns the numeric identifier, even if the entity type has specified a
   * name key. In the latter case, the numeric identifier is supposed to be used
   * when dealing generically with entities or internally to refer to an entity,
   * i.e. in a relational database. If unsure, use Entity:identifier().
   */
  public function internalIdentifier();

  /**
   * Returns the entity identifier, i.e. the entities name or numeric id.
   *
   * @return
   *   The identifier of the entity. If the entity type makes use of a name key,
   *   the name is returned, else the numeric id.
   *
   * @see entity_id()
   */
  public function identifier();

  /**
   * Returns the info of the type of the entity.
   *
   * @see entity_get_info()
   */
  public function entityInfo();

  /**
   * Returns the type of the entity.
   */
  public function entityType();

  /**
   * Returns the bundle of the entity.
   *
   * @return
   *   The bundle of the entity. Defaults to the entity type if the entity type
   *   does not make use of different bundles.
   */
  public function bundle();

  /**
   * Returns the EntityMetadataWrapper of the entity.
   *
   * @return EntityDrupalWrapper
   *   An EntityMetadataWrapper containing the entity.
   */
  public function wrapper();

  /**
   * Returns the label of the entity.
   *
   * Modules may alter the label by specifying another 'label callback' using
   * hook_entity_info_alter().
   *
   * @see entity_label()
   */
  public function label();

  /**
   * Returns the uri of the entity just as entity_uri().
   *
   * Modules may alter the uri by specifying another 'uri callback' using
   * hook_entity_info_alter().
   *
   * @see entity_uri()
   */
  public function uri();

  /**
   * Checks if the entity has a certain exportable status.
   *
   * @param $status
   *   A status constant, i.e. one of ENTITY_CUSTOM, ENTITY_IN_CODE,
   *   ENTITY_OVERRIDDEN or ENTITY_FIXED.
   *
   * @return bool
   *   For exportable entities TRUE if the entity has the status, else FALSE.
   *   In case the entity is not exportable, NULL is returned.
   *
   * @see entity_has_status()
   */
  public function hasStatus($status);

  /**
   * Permanently saves the entity.
   *
   * @see entity_save()
   */
  public function save();

  /**
   * Permanently deletes the entity.
   *
   * @see entity_delete()
   */
  public function delete();

  /**
   * Exports the entity.
   *
   * @see entity_export()
   */
  public function export($prefix = '');

  /**
   * Generate an array for rendering the entity.
   *
   * @see entity_view()
   */
  public function view($view_mode = 'full', $langcode = NULL, $page = NULL);

  /**
   * Builds a structured array representing the entity's content.
   *
   * @see entity_build_content()
   */
  public function buildContent($view_mode = 'full', $langcode = NULL);

  /**
   * Gets the raw, translated value of a property or field.
   *
   * Supports retrieving field translations as well as i18n string translations.
   *
   * Note that this returns raw data values, which might not reflect what
   * has been declared for hook_entity_property_info() as no 'getter callbacks'
   * are invoked or no referenced entities are loaded. For retrieving values
   * reflecting the property info make use of entity metadata wrappers, see
   * entity_metadata_wrapper().
   *
   * @param $property
   *   The name of the property to return; e.g., 'title'.
   * @param $langcode
   *   (optional) The language code of the language to which the value should
   *   be translated. If set to NULL, the default display language is being
   *   used.
   *
   * @return
   *   The raw, translated property value; or the raw, un-translated value if no
   *   translation is available.
   *
   * @todo Implement an analogous setTranslation() method for updating.
   */
  public function getTranslation($property, $langcode = NULL);

  /**
   * Checks whether the entity is the default revision.
   *
   * @return Boolean
   *
   * @see entity_revision_is_default()
   */
  public function isDefaultRevision();

}

/**
 * A common class for entities.
 *
 * It's suggested, but not required, to extend this class and to override
 * __construct() in order to specify a fixed entity type.
 *
 * For providing an entity label and URI it is suggested to override the
 * defaultLabel() and defaultUri() methods, and to specify the
 * entity_class_label() and entity_class_uri() as respective callbacks in
 * hook_entity_info(). That way modules are able to override your defaults
 * by altering the hook_entity_info() callbacks, while $entity->label() and
 * $entity->uri() reflect this changes as well.
 *
 * Defaults for entity properties can be easily defined by adding class
 * properties, e.g.:
 * @code
 *   public $name = '';
 *   public $count = 0;
 * @endcode
 */
class Entity implements EntityInterface {

  protected $entityType;
  protected $entityInfo;
  protected $idKey, $nameKey, $statusKey;
  protected $defaultLabel = FALSE;
  protected $wrapper;

  /**
   * {@inheritdoc}
   */
  public function __construct(array $values = array(), $entityType = NULL) {
    if (empty($entityType)) {
      throw new Exception('Cannot create an instance of Entity without a specified entity type.');
    }
    $this->entityType = $entityType;
    $this->setUp();
    // Set initial values.
    foreach ($values as $key => $value) {
      $this->$key = $value;
    }
  }

  /**
   * Set up the object instance on construction or unserializiation.
   */
  protected function setUp() {
    $this->entityInfo = entity_get_info($this->entityType);
    $this->idKey = $this->entityInfo['entity keys']['id'];
    $this->nameKey = isset($this->entityInfo['entity keys']['name']) ? $this->entityInfo['entity keys']['name'] : $this->idKey;
    $this->statusKey = empty($this->entityInfo['entity keys']['status']) ? 'status' : $this->entityInfo['entity keys']['status'];
  }

  /**
   * {@inheritdoc}
   */
  public function internalIdentifier() {
    return isset($this->{$this->idKey}) ? $this->{$this->idKey} : NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function identifier() {
    return isset($this->{$this->nameKey}) ? $this->{$this->nameKey} : NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function entityInfo() {
    return $this->entityInfo;
  }

  /**
   * {@inheritdoc}
   */
  public function entityType() {
    return $this->entityType;
  }

  /**
   * {@inheritdoc}
   */
  public function bundle() {
    return !empty($this->entityInfo['entity keys']['bundle']) ? $this->{$this->entityInfo['entity keys']['bundle']} : $this->entityType;
  }

  /**
   * {@inheritdoc}
   */
  public function wrapper() {
    if (empty($this->wrapper)) {
      $this->wrapper = entity_metadata_wrapper($this->entityType, $this);
    }
    elseif ($this->wrapper->value() !== $this) {
      // Wrapper has been modified outside, so let's better create a new one.
      $this->wrapper = entity_metadata_wrapper($this->entityType, $this);
    }
    return $this->wrapper;
  }

  /**
   * {@inheritdoc}
   */
  public function label() {
    // If the default label flag is enabled, this is being invoked recursively.
    // In this case we need to use our default label callback directly. This may
    // happen if a module provides a label callback implementation different
    // from ours, but then invokes Entity::label() or entity_class_label() from
    // there.
    if ($this->defaultLabel || (isset($this->entityInfo['label callback']) && $this->entityInfo['label callback'] == 'entity_class_label')) {
      return $this->defaultLabel();
    }
    $this->defaultLabel = TRUE;
    $label = entity_label($this->entityType, $this);
    $this->defaultLabel = FALSE;
    return $label;
  }

  /**
   * Defines the entity label if the 'entity_class_label' callback is used.
   *
   * Specify 'entity_class_label' as 'label callback' in hook_entity_info() to
   * let the entity label point to this method. Override this in order to
   * implement a custom default label.
   */
  protected function defaultLabel() {
    // Add in the translated specified label property.
    return $this->getTranslation($this->entityInfo['entity keys']['label']);
  }

  /**
   * {@inheritdoc}
   */
  public function uri() {
    if (isset($this->entityInfo['uri callback']) && $this->entityInfo['uri callback'] == 'entity_class_uri') {
      return $this->defaultUri();
    }
    return entity_uri($this->entityType, $this);
  }

  /**
   * Override this in order to implement a custom default URI and specify
   * 'entity_class_uri' as 'uri callback' hook_entity_info().
   */
  protected function defaultUri() {
    return array('path' => 'default/' . $this->identifier());
  }

  /**
   * {@inheritdoc}
   */
  public function hasStatus($status) {
    if (!empty($this->entityInfo['exportable'])) {
      return isset($this->{$this->statusKey}) && ($this->{$this->statusKey} & $status) == $status;
    }
  }

  /**
   * {@inheritdoc}
   */
  public function save() {
    return entity_get_controller($this->entityType)->save($this);
  }

  /**
   * {@inheritdoc}
   */
  public function delete() {
    $id = $this->identifier();
    if (isset($id)) {
      entity_get_controller($this->entityType)->delete(array($id));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function export($prefix = '') {
    return entity_get_controller($this->entityType)->export($this, $prefix);
  }

  /**
   * {@inheritdoc}
   */
  public function view($view_mode = 'full', $langcode = NULL, $page = NULL) {
    return entity_get_controller($this->entityType)->view(array($this), $view_mode, $langcode, $page);
  }

  /**
   * {@inheritdoc}
   */
  public function buildContent($view_mode = 'full', $langcode = NULL) {
    return entity_get_controller($this->entityType)->buildContent($this, $view_mode, $langcode);
  }

  /**
   * {@inheritdoc}
   */
  public function getTranslation($property, $langcode = NULL) {
    $all_info = entity_get_all_property_info($this->entityType);
    // Assign by reference to avoid triggering notices if metadata is missing.
    $property_info = &$all_info[$property];

    if (!empty($property_info['translatable'])) {
      if (!empty($property_info['field'])) {
        return field_get_items($this->entityType, $this, $property, $langcode);
      }
      elseif (!empty($property_info['i18n string'])) {
        $name = $this->entityInfo['module'] . ':' . $this->entityType . ':' . $this->identifier() . ':' . $property;
        return entity_i18n_string($name, $this->$property, $langcode);
      }
    }
    return $this->$property;
  }

  /**
   * {@inheritdoc}
   */
  public function isDefaultRevision() {
    if (!empty($this->entityInfo['entity keys']['revision'])) {
      $key = !empty($this->entityInfo['entity keys']['default revision']) ? $this->entityInfo['entity keys']['default revision'] : 'default_revision';
      return !empty($this->$key);
    }
    return TRUE;
  }

  /**
   * Magic method to only serialize what's necessary.
   */
  public function __sleep() {
    $vars = get_object_vars($this);
    unset($vars['entityInfo'], $vars['idKey'], $vars['nameKey'], $vars['statusKey']);
    // Also key the returned array with the variable names so the method may
    // be easily overridden and customized.
    return drupal_map_assoc(array_keys($vars));
  }

  /**
   * Magic method to invoke setUp() on unserialization.
   */
  public function __wakeup() {
    $this->setUp();
  }
}

/**
 * These classes are deprecated by "Entity" and are only here for backward
 * compatibility reasons.
 */
class EntityDB extends Entity {}
class EntityExtendable extends Entity {}
class EntityDBExtendable extends Entity {}