Projet

Général

Profil

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

root / htmltest / sites / all / modules / entity / includes / entity.property.inc @ dd54aff9

1
<?php
2

    
3
/**
4
 * @file
5
 * Provides API functions around hook_entity_property_info(). Also see
6
 * entity.info.inc, which cares for providing entity property info for all core
7
 * entity types.
8
 */
9

    
10
/**
11
 * Get the entity property info array of an entity type.
12
 *
13
 * @param $entity_type
14
 *   The entity type, e.g. node, for which the info shall be returned, or NULL
15
 *   to return an array with info about all types.
16
 *
17
 * @see hook_entity_property_info()
18
 * @see hook_entity_property_info_alter()
19
 */
20
function entity_get_property_info($entity_type = NULL) {
21
  // Use the advanced drupal_static() pattern, since this is called very often.
22
  static $drupal_static_fast;
23
  if (!isset($drupal_static_fast)) {
24
    $drupal_static_fast['info'] = &drupal_static(__FUNCTION__);
25
  }
26
  $info = &$drupal_static_fast['info'];
27

    
28
  // hook_entity_property_info() includes translated strings, so each language
29
  // is cached separately.
30
  $langcode = $GLOBALS['language']->language;
31

    
32
  if (empty($info)) {
33
    if ($cache = cache_get("entity_property_info:$langcode")) {
34
      $info = $cache->data;
35
    }
36
    else {
37
      $info = module_invoke_all('entity_property_info');
38
      // Let other modules alter the entity info.
39
      drupal_alter('entity_property_info', $info);
40
      cache_set("entity_property_info:$langcode", $info);
41
    }
42
  }
43
  return empty($entity_type) ? $info : (isset($info[$entity_type]) ? $info[$entity_type] : array());
44
}
45

    
46
/**
47
 * Returns the default information for an entity property.
48
 *
49
 * @return
50
 *   An array of optional property information keys mapped to their defaults.
51
 *
52
 * @see hook_entity_property_info()
53
 */
54
function entity_property_info_defaults() {
55
  return array(
56
    'type' => 'text',
57
    'getter callback' => 'entity_property_verbatim_get',
58
  );
59
}
60

    
61
/**
62
 * Gets an array of info about all properties of a given entity type.
63
 *
64
 * In contrast to entity_get_property_info(), this function returns info about
65
 * all properties the entity might have, thus it adds an all properties assigned
66
 * to entity bundles.
67
 *
68
 * @param $entity_type
69
 *   (optiona) The entity type to return properties for.
70
 *
71
 * @return
72
 *   An array of info about properties. If the type is ommitted, all known
73
 *   properties are returned.
74
 */
75
function entity_get_all_property_info($entity_type = NULL) {
76
  if (!isset($entity_type)) {
77
    // Retrieve all known properties.
78
    $properties = array();
79
    foreach (entity_get_info() as $entity_type => $info) {
80
      $properties += entity_get_all_property_info($entity_type);
81
    }
82
    return $properties;
83
  }
84
  // Else retrieve the properties of the given entity type only.
85
  $info = entity_get_property_info($entity_type);
86
  $info += array('properties' => array(), 'bundles' => array());
87
  // Add all bundle properties.
88
  foreach ($info['bundles'] as $bundle => $bundle_info) {
89
    $bundle_info += array('properties' => array());
90
    $info['properties'] += $bundle_info['properties'];
91
  }
92
  return $info['properties'];
93
}
94

    
95
/**
96
 * Queries for entities having the given property value.
97
 *
98
 * @param $entity_type
99
 *   The type of the entity.
100
 * @param $property
101
 *   The name of the property to query for.
102
 * @param $value
103
 *   A single property value or an array of possible values to query for.
104
 * @param $limit
105
 *   Limit the numer of results. Defaults to 30.
106
 *
107
 * @return
108
 *   An array of entity ids or NULL if there is no information how to query for
109
 *   the given property.
110
 */
111
function entity_property_query($entity_type, $property, $value, $limit = 30) {
112
  $properties = entity_get_all_property_info($entity_type);
113
  $info = $properties[$property] + array('type' => 'text', 'queryable' => !empty($properties[$property]['schema field']));
114

    
115
  // We still support the deprecated query callback, so just add in EFQ-based
116
  // callbacks in case 'queryable' is set to TRUE and make use of the callback.
117
  if ($info['queryable'] && empty($info['query callback'])) {
118
    $info['query callback'] = !empty($info['field']) ? 'entity_metadata_field_query' : 'entity_metadata_table_query';
119
  }
120

    
121
  $type = $info['type'];
122
  // Make sure an entity or a list of entities are passed on as identifiers
123
  // with the help of the wrappers. For that ensure the data type matches the
124
  // passed on value(s).
125
  if (is_array($value) && !entity_property_list_extract_type($type)) {
126
    $type = 'list<' . $type . '>';
127
  }
128
  elseif (!is_array($value) && entity_property_list_extract_type($type)) {
129
    $type = entity_property_list_extract_type($type);
130
  }
131

    
132
  $wrapper = entity_metadata_wrapper($type, $value);
133
  $value = $wrapper->value(array('identifier' => TRUE));
134

    
135
  if (!empty($info['query callback'])) {
136
    return $info['query callback']($entity_type, $property, $value, $limit);
137
  }
138
}
139

    
140
/**
141
 * Resets the cached information of hook_entity_property_info().
142
 */
143
function entity_property_info_cache_clear() {
144
  drupal_static_reset('entity_get_property_info');
145
  // Clear all languages.
146
  cache_clear_all('entity_property_info:', 'cache', TRUE);
147
}
148

    
149
/**
150
 * Implements hook_hook_info().
151
 */
152
function entity_hook_info() {
153
  $hook_info['entity_property_info'] = array(
154
    'group' => 'info',
155
  );
156
  $hook_info['entity_property_info_alter'] = array(
157
    'group' => 'info',
158
  );
159
  return $hook_info;
160
}
161

    
162
/**
163
 * Implements hook_field_info_alter().
164
 * Defines default property types for core field types.
165
 */
166
function entity_field_info_alter(&$field_info) {
167
  if (module_exists('number')) {
168
    $field_info['number_integer']['property_type'] = 'integer';
169
    $field_info['number_decimal']['property_type'] = 'decimal';
170
    $field_info['number_float']['property_type'] = 'decimal';
171
  }
172
  if (module_exists('text')) {
173
    $field_info['text']['property_type'] = 'text';
174
    $field_info['text']['property_callbacks'][] = 'entity_metadata_field_text_property_callback';
175
    $field_info['text_long']['property_type'] = 'text';
176
    $field_info['text_long']['property_callbacks'][] = 'entity_metadata_field_text_property_callback';
177
    $field_info['text_with_summary']['property_type'] = 'field_item_textsummary';
178
    $field_info['text_with_summary']['property_callbacks'][] = 'entity_metadata_field_text_property_callback';
179
  }
180
  if (module_exists('list')) {
181
    $field_info['list_integer']['property_type'] = 'integer';
182
    $field_info['list_boolean']['property_type'] = 'boolean';
183
    $field_info['list_float']['property_type'] = 'decimal';
184
    $field_info['list_text']['property_type'] = 'text';
185
  }
186
  if (module_exists('taxonomy')) {
187
    $field_info['taxonomy_term_reference']['property_type'] = 'taxonomy_term';
188
    $field_info['taxonomy_term_reference']['property_callbacks'][] = 'entity_metadata_field_term_reference_callback';
189
  }
190
  if (module_exists('file')) {
191
    // The callback specifies a custom data structure matching the file field
192
    // items. We introduce a custom type name for this data structure.
193
    $field_info['file']['property_type'] = 'field_item_file';
194
    $field_info['file']['property_callbacks'][] = 'entity_metadata_field_file_callback';
195
  }
196
  if (module_exists('image')) {
197
    // The callback specifies a custom data structure matching the image field
198
    // items. We introduce a custom type name for this data structure.
199
    $field_info['image']['property_type'] = 'field_item_image';
200
    $field_info['image']['property_callbacks'][] = 'entity_metadata_field_file_callback';
201
    $field_info['image']['property_callbacks'][] = 'entity_metadata_field_image_callback';
202
  }
203
}
204

    
205
/**
206
 * Implements hook_field_create_instance().
207
 * Clear the cache when a field instance changed.
208
 */
209
function entity_field_create_instance() {
210
  entity_property_info_cache_clear();
211
}
212

    
213
/**
214
 * Implements hook_field_delete_instance().
215
 * Clear the cache when a field instance changed.
216
 */
217
function entity_field_delete_instance() {
218
  entity_property_info_cache_clear();
219
}
220

    
221
/**
222
 * Implements hook_field_update_instance().
223
 * Clear the cache when a field instance changed.
224
 */
225
function entity_field_update_instance() {
226
  entity_property_info_cache_clear();
227
}
228

    
229
/**
230
 * Verifies that the given data can be safely used as the given type regardless
231
 * of the PHP variable type of $data. Example: the string "15" is a valid
232
 * integer, but "15nodes" is not.
233
 *
234
 * @return
235
 *   Whether the data is valid for the given type.
236
 */
237
function entity_property_verify_data_type($data, $type) {
238
  // As this may be called very often statically cache the entity info using
239
  // the fast pattern.
240
  static $drupal_static_fast;
241
  if (!isset($drupal_static_fast)) {
242
    // Make use of the same static as entity info.
243
    entity_get_info();
244
    $drupal_static_fast['entity_info'] = &drupal_static('entity_get_info');
245
  }
246
  $info = &$drupal_static_fast['entity_info'];
247

    
248
  // First off check for entities, which may be represented by their ids too.
249
  if (isset($info[$type])) {
250
    if (is_object($data)) {
251
      return TRUE;
252
    }
253
    elseif (isset($info[$type]['entity keys']['name'])) {
254
      // Read the data type of the name key from the metadata if available.
255
      $key = $info[$type]['entity keys']['name'];
256
      $property_info = entity_get_property_info($type);
257
      $property_type = isset($property_info['properties'][$key]['type']) ? $property_info['properties'][$key]['type'] : 'token';
258
      return entity_property_verify_data_type($data, $property_type);
259
    }
260
    return entity_property_verify_data_type($data, empty($info[$type]['fieldable']) ? 'text' : 'integer');
261
  }
262

    
263
  switch ($type) {
264
    case 'site':
265
    case 'unknown':
266
      return TRUE;
267
    case 'date':
268
    case 'duration':
269
    case 'integer':
270
      return is_numeric($data) && strpos($data, '.') === FALSE;
271
    case 'decimal':
272
      return is_numeric($data);
273
    case 'text':
274
      return is_scalar($data);
275
    case 'token':
276
      return is_scalar($data) && preg_match('!^[a-z][a-z0-9_]*$!', $data);
277
    case 'boolean':
278
      return is_scalar($data) && (is_bool($data) || $data == 0 || $data == 1);
279
    case 'uri':
280
      return valid_url($data, TRUE);
281
    case 'list':
282
      return (is_array($data) && array_values($data) == $data) || (is_object($data) && $data instanceof EntityMetadataArrayObject);
283
    case 'entity':
284
      return is_object($data) && $data instanceof EntityDrupalWrapper;
285
    default:
286
    case 'struct':
287
      return is_object($data) || is_array($data);
288
  }
289
}
290

    
291
/**
292
 * Creates the entity object for an array of given property values.
293
 *
294
 * @param $entity_type
295
 *   The entity type to create an entity for.
296
 * @param $values
297
 *   An array of values as described by the entity's property info. All entity
298
 *   properties of the given entity type that are marked as required, must be
299
 *   present.
300
 *   If the passed values have no matching property, their value will be
301
 *   assigned to the entity directly, without the use of the metadata-wrapper
302
 *   property.
303
 *
304
 * @return EntityDrupalWrapper
305
 *   An EntityDrupalWrapper wrapping the newly created entity or FALSE, if
306
 *   there were no information how to create the entity.
307
 */
308
function entity_property_values_create_entity($entity_type, $values = array()) {
309
  if (entity_type_supports($entity_type, 'create')) {
310
    $info = entity_get_info($entity_type);
311
    // Create the initial entity by passing the values for all 'entity keys'
312
    // to entity_create().
313
    $entity_keys = array_filter($info['entity keys']);
314
    $creation_values = array_intersect_key($values, array_flip($entity_keys));
315

    
316
    // In case the bundle key does not match the property that sets it, ensure
317
    // the bundle key is initialized somehow, so entity_extract_ids()
318
    // does not bail out during wrapper creation.
319
    if (!empty($info['entity keys']['bundle'])) {
320
      $creation_values += array($info['entity keys']['bundle'] => FALSE);
321
    }
322
    $entity = entity_create($entity_type, $creation_values);
323

    
324
    // Now set the remaining values using the wrapper.
325
    $wrapper = entity_metadata_wrapper($entity_type, $entity);
326
    foreach ($values as $key => $value) {
327
      if (!in_array($key, $info['entity keys'])) {
328
        if (isset($wrapper->$key)) {
329
          $wrapper->$key->set($value);
330
        }
331
        else {
332
          $entity->$key = $value;
333
        }
334
      }
335
    }
336
    // @todo: Once we require Drupal 7.7 or later, verify the entity has
337
    // now a valid bundle and throw the EntityMalformedException if not.
338
    return $wrapper;
339
  }
340
  return FALSE;
341
}
342

    
343

    
344
/**
345
 * Extracts the contained type for a list type string like list<date>.
346
 *
347
 * @return
348
 *   The contained type or FALSE, if the given type string is no list.
349
 */
350
function entity_property_list_extract_type($type) {
351
  if (strpos($type, 'list<') === 0 && $type[strlen($type)-1] == '>') {
352
    return substr($type, 5, -1);
353
  }
354
  return FALSE;
355
}
356

    
357
/**
358
 * Extracts the innermost type for a type string like list<list<date>>.
359
 *
360
 * @param $type
361
 *   The type to examine.
362
 *
363
 * @return
364
 *   For list types, the innermost type. The type itself otherwise.
365
 */
366
function entity_property_extract_innermost_type($type) {
367
  while (strpos($type, 'list<') === 0 && $type[strlen($type)-1] == '>') {
368
    $type = substr($type, 5, -1);
369
  }
370
  return $type;
371
}
372

    
373
/**
374
 * Gets the property just as it is set in the data.
375
 */
376
function entity_property_verbatim_get($data, array $options, $name, $type, $info) {
377
  $name = isset($info['schema field']) ? $info['schema field'] : $name;
378
  if ((is_array($data) || (is_object($data) && $data instanceof ArrayAccess)) && isset($data[$name])) {
379
    return $data[$name];
380
  }
381
  elseif (is_object($data) && isset($data->$name)) {
382
    // Incorporate i18n_string translations. We may rely on the entity class
383
    // here as its usage is required by the i18n integration.
384
    if (isset($options['language']) && !empty($info['i18n string'])) {
385
      return $data->getTranslation($name, $options['language']->language);
386
    }
387
    else {
388
      return $data->$name;
389
    }
390
  }
391
  return NULL;
392
}
393

    
394
/**
395
 * Date values are converted from ISO strings to timestamp if needed.
396
 */
397
function entity_property_verbatim_date_get($data, array $options, $name, $type, $info) {
398
  $name = isset($info['schema field']) ? $info['schema field'] : $name;
399
  if (is_array($data) || (is_object($data) && $data instanceof ArrayAccess)) {
400
    return is_numeric($data[$name]) ? $data[$name] : strtotime($data[$name], REQUEST_TIME);
401
  }
402
  elseif (is_object($data)) {
403
    return is_numeric($data->$name) ? $data->$name : strtotime($data->$name, REQUEST_TIME);
404
  }
405
}
406

    
407
/**
408
 * Sets the property to the given value. May be used as 'setter callback'.
409
 */
410
function entity_property_verbatim_set(&$data, $name, $value, $langcode, $type, $info) {
411
  $name = isset($info['schema field']) ? $info['schema field'] : $name;
412
  if (is_array($data) || (is_object($data) && $data instanceof ArrayAccess)) {
413
    $data[$name] = $value;
414
  }
415
  elseif (is_object($data)) {
416
    $data->$name = $value;
417
  }
418
}
419

    
420
/**
421
 * Gets the property using the getter method (named just like the property).
422
 */
423
function entity_property_getter_method($object, array $options, $name) {
424
  // Remove any underscores as classes are expected to use CamelCase.
425
  $method = strtr($name, array('_' => ''));
426
  return $object->$method();
427
}
428

    
429
/**
430
 * Sets the property to the given value using the setter method. May be used as
431
 * 'setter callback'.
432
 */
433
function entity_property_setter_method($object, $name, $value) {
434
  // Remove any underscores as classes are expected to use CamelCase.
435
  $method = 'set' . strtr($name, array('_' => ''));
436
  // Invoke the setProperty() method where 'Property' is the property name.
437
  $object->$method($value);
438
}
439

    
440
/**
441
 * Getter callback for getting an array. Makes sure it's numerically indexed.
442
 */
443
function entity_property_get_list($data, array $options, $name) {
444
  return isset($data->$name) ? array_values($data->$name) : array();
445
}
446

    
447
/**
448
 * A validation callback ensuring the passed integer is positive.
449
 */
450
function entity_property_validate_integer_positive($value) {
451
  return $value > 0;
452
}
453

    
454
/**
455
 * A validation callback ensuring the passed integer is non-negative.
456
 */
457
function entity_property_validate_integer_non_negative($value) {
458
  return $value >= 0;
459
}
460

    
461
/**
462
 * A simple auto-creation callback for array based data structures.
463
 */
464
function entity_property_create_array($property_name, $context) {
465
  return array();
466
}
467

    
468
/**
469
 * Flattens the given options in single dimensional array.
470
 * We don't depend on options module, so we cannot use options_array_flatten().
471
 *
472
 * @see options_array_flatten()
473
 */
474
function entity_property_options_flatten($options) {
475
  $result = array();
476
  foreach ($options as $key => $value) {
477
    if (is_array($value)) {
478
      $result += $value;
479
    }
480
    else {
481
      $result[$key] = $value;
482
    }
483
  }
484
  return $result;
485
}
486

    
487
/**
488
 * Defines info for the properties of the text_formatted data structure.
489
 */
490
function entity_property_text_formatted_info() {
491
  return array(
492
    'value' => array(
493
      'type' => 'text',
494
      'label' => t('Text'),
495
      'sanitized' => TRUE,
496
      'getter callback' => 'entity_metadata_field_text_get',
497
      'setter callback' => 'entity_property_verbatim_set',
498
      'setter permission' => 'administer nodes',
499
      'raw getter callback' => 'entity_property_verbatim_get',
500
    ),
501
    'summary' => array(
502
      'type' => 'text',
503
      'label' => t('Summary'),
504
      'sanitized' => TRUE,
505
      'getter callback' => 'entity_metadata_field_text_get',
506
      'setter callback' => 'entity_property_verbatim_set',
507
      'setter permission' => 'administer nodes',
508
      'raw getter callback' => 'entity_property_verbatim_get',
509
    ),
510
    'format' => array(
511
      'type' => 'token',
512
      'label' => t('Text format'),
513
      'options list' => 'entity_metadata_field_text_formats',
514
      'getter callback' => 'entity_property_verbatim_get',
515
      'setter callback' => 'entity_property_verbatim_set',
516
      'setter permissions' => 'administer filters',
517
    ),
518
  );
519
}
520

    
521
/**
522
 * Defines info for the properties of the field_item_textsummary data structure.
523
 */
524
function entity_property_field_item_textsummary_info() {
525
  return array(
526
    'value' => array(
527
      'type' => 'text',
528
      'label' => t('Text'),
529
      'setter callback' => 'entity_property_verbatim_set',
530
    ),
531
    'summary' => array(
532
      'type' => 'text',
533
      'label' => t('Summary'),
534
      'setter callback' => 'entity_property_verbatim_set',
535
    ),
536
  );
537
}
538

    
539
/**
540
 * Defines info for the properties of the file-field item data structure.
541
 */
542
function entity_property_field_item_file_info() {
543
  $properties['file'] = array(
544
    'type' => 'file',
545
    'label' => t('The file.'),
546
    'getter callback' => 'entity_metadata_field_file_get',
547
    'setter callback' => 'entity_metadata_field_file_set',
548
    'required' => TRUE,
549
  );
550
  $properties['description'] = array(
551
    'type' => 'text',
552
    'label' => t('The file description'),
553
    'setter callback' => 'entity_property_verbatim_set',
554
  );
555
  $properties['display'] = array(
556
    'type' => 'boolean',
557
    'label' => t('Whether the file is being displayed.'),
558
    'setter callback' => 'entity_property_verbatim_set',
559
  );
560
  return $properties;
561
}
562

    
563
/**
564
 * Defines info for the properties of the image-field item data structure.
565
 */
566
function entity_property_field_item_image_info() {
567
  $properties['file'] = array(
568
    'type' => 'file',
569
    'label' => t('The image file.'),
570
    'getter callback' => 'entity_metadata_field_file_get',
571
    'setter callback' => 'entity_metadata_field_file_set',
572
    'required' => TRUE,
573
  );
574
  $properties['alt'] = array(
575
    'type' => 'text',
576
    'label' => t('The "Alt" attribute text'),
577
    'setter callback' => 'entity_property_verbatim_set',
578
  );
579
  $properties['title'] = array(
580
    'type' => 'text',
581
    'label' => t('The "Title" attribute text'),
582
    'setter callback' => 'entity_property_verbatim_set',
583
  );
584
  return $properties;
585
}
586

    
587

    
588
/**
589
 * Previously, hook_entity_property_info() has been provided by the removed
590
 * entity metadata module. To provide backward compatibility for provided
591
 * helpers that may be specified in hook_entity_property_info(), the following
592
 * (deprecated) functions are provided.
593
 */
594

    
595
/**
596
 * Deprecated.
597
 * Do not make use of this function, instead use the new one.
598
 */
599
function entity_metadata_verbatim_get($data, array $options, $name) {
600
  return entity_property_verbatim_get($data, $options, $name);
601
}
602

    
603
/**
604
 * Deprecated.
605
 * Do not make use of this function, instead use the new one.
606
 */
607
function entity_metadata_verbatim_set($data, $name, $value) {
608
  return entity_property_verbatim_set($data, $name, $value);
609
}
610

    
611
/**
612
 * Deprecated.
613
 * Do not make use of this function, instead use the new one.
614
 */
615
function entity_metadata_getter_method($object, array $options, $name) {
616
  return entity_property_getter_method($object, $options, $name);
617
}
618

    
619
/**
620
 * Deprecated.
621
 * Do not make use of this function, instead use the new one.
622
 */
623
function entity_metadata_setter_method($object, $name, $value) {
624
  entity_property_setter_method($object, $name, $value);
625
}
626

    
627
/**
628
 * Deprecated.
629
 * Do not make use of this function, instead use the new one.
630
 */
631
function entity_metadata_get_list($data, array $options, $name) {
632
  return entity_property_get_list($data, $options, $name);
633
}
634

    
635
/**
636
 * Deprecated.
637
 * Do not make use of this function, instead use the new one.
638
 */
639
function entity_metadata_validate_integer_positive($value) {
640
  return entity_property_validate_integer_positive($value);
641
}
642

    
643
/**
644
 * Deprecated.
645
 * Do not make use of this function, instead use the new one.
646
 */
647
function entity_metadata_validate_integer_non_negative($value) {
648
  return entity_property_validate_integer_non_negative($value);
649
}
650

    
651
/**
652
 * Deprecated.
653
 * Do not make use of this function, instead use the new one.
654
 */
655
function entity_metadata_text_formatted_properties() {
656
  return entity_property_text_formatted_info();
657
}