Projet

Général

Profil

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

root / drupal7 / sites / all / modules / rules / modules / entity.rules.inc @ 950416da

1
<?php
2

    
3
/**
4
 * @file
5
 * General entity related rules integration.
6
 *
7
 * @addtogroup rules
8
 *
9
 * @{
10
 */
11

    
12
/**
13
 * Implements hook_rules_file_info() on behalf of the entity module.
14
 *
15
 * @see rules_core_modules()
16
 */
17
function rules_entity_file_info() {
18
  return array('modules/entity.eval');
19
}
20

    
21
/**
22
 * Implements hook_rules_category_info() on behalf of the pseudo entity module.
23
 */
24
function rules_entity_category_info() {
25
  return array(
26
    'rules_entity' => array(
27
      'label' => t('Entities'),
28
      'equals group' => t('Entities'),
29
      'weight' => -50,
30
    ),
31
  );
32
}
33

    
34
/**
35
 * Implements hook_rules_action_info() on behalf of the entity module.
36
 *
37
 * @see rules_core_modules()
38
 */
39
function rules_entity_action_info() {
40
  if (rules_entity_action_type_options('entity_fetch')) {
41
    $return['entity_fetch'] = array(
42
      'label' => t('Fetch entity by id'),
43
      'parameter' => array(
44
        'type' => array(
45
          'type' => 'text',
46
          'label' => t('Entity type'),
47
          'options list' => 'rules_entity_action_type_options',
48
          'description' => t('Specifies the type of entity that should be fetched.'),
49
          'restriction' => 'input',
50
        ),
51
        'id' => array('type' => 'unknown', 'label' => t('Identifier')),
52
      ),
53
      'provides' => array(
54
        'entity_fetched' => array('type' => 'unknown', 'label' => t('Fetched entity')),
55
      ),
56
      'group' => t('Entities'),
57
      'access callback' => 'rules_entity_action_access',
58
      'base' => 'rules_action_entity_fetch',
59
      'callbacks' => array(
60
        'access' => 'rules_action_entity_createfetch_access',
61
        'form_alter' => 'rules_action_type_form_alter',
62
      ),
63
    );
64
    $return['entity_query'] = array(
65
      'label' => t('Fetch entity by property'),
66
      'parameter' => array(
67
        'type' => array(
68
          'type' => 'text',
69
          'label' => t('Entity type'),
70
          'options list' => 'rules_entity_action_type_options',
71
          'description' => t('Specifies the type of the entity that should be fetched.'),
72
          'restriction' => 'input',
73
        ),
74
        'property' => array(
75
          'type' => 'text',
76
          'label' => t('Property'),
77
          'description' => t('The property by which the entity is to be selected.'),
78
          'restriction' => 'input',
79
        ),
80
        'value' => array(
81
          'type' => 'unknown',
82
          'label' => t('Value'),
83
          'description' => t('The property value of the entity to be fetched.'),
84
        ),
85
        'limit' => array(
86
          'type' => 'integer',
87
          'label' => t('Limit result count'),
88
          'description' => t('Limit the maximum number of fetched entities.'),
89
          'optional' => TRUE,
90
          'default value' => '10',
91
        ),
92
      ),
93
      'provides' => array(
94
        'entity_fetched' => array('type' => 'list', 'label' => t('Fetched entity')),
95
      ),
96
      'group' => t('Entities'),
97
      'access callback' => 'rules_entity_action_access',
98
      'base' => 'rules_action_entity_query',
99
      'callbacks' => array(
100
        'form_alter' => 'rules_action_type_form_alter',
101
      ),
102
    );
103
  }
104

    
105
  if (rules_entity_action_type_options('entity_create')) {
106
    $return['entity_create'] = array(
107
      'label' => t('Create a new entity'),
108
      'named parameter' => TRUE,
109
      'parameter' => array(
110
        'type' => array(
111
          'type' => 'text',
112
          'label' => t('Entity type'),
113
          'options list' => 'rules_entity_action_type_options',
114
          'description' => t('Specifies the type of the entity that should be created.'),
115
          'restriction' => 'input',
116
        ),
117
        // Further needed parameter depends on the type.
118
      ),
119
      'provides' => array(
120
        'entity_created' => array(
121
          'type' => 'unknown',
122
          'label' => t('Created entity'),
123
          'save' => TRUE,
124
        ),
125
      ),
126
      'group' => t('Entities'),
127
      'access callback' => 'rules_entity_action_access',
128
      'base' => 'rules_action_entity_create',
129
      'callbacks' => array(
130
        'access' => 'rules_action_entity_createfetch_access',
131
        'form_alter' => 'rules_action_type_form_alter',
132
        'validate' => 'rules_action_create_type_validate',
133
      ),
134
    );
135
  }
136

    
137
  $return['entity_save'] = array(
138
    'label' => t('Save entity'),
139
    'parameter' => array(
140
      'data' => array(
141
        'type' => 'entity',
142
        'label' => t('Entity'),
143
        'description' => t('Specifies the entity, which should be saved permanently.'),
144
        'restriction' => 'selector',
145
        'wrapped' => TRUE,
146
      ),
147
      'immediate' => array(
148
        'type' => 'boolean',
149
        'label' => t('Force saving immediately'),
150
        'description' => t('Usually saving is postponed till the end of the evaluation, so that multiple saves can be fold into one. If this set, saving is forced to happen immediately.'),
151
        'default value' => FALSE,
152
        'optional' => TRUE,
153
        'restriction' => 'input',
154
      ),
155
    ),
156
    'group' => t('Entities'),
157
    'access callback' => 'rules_entity_action_access',
158
    'base' => 'rules_action_entity_save',
159
    'callbacks' => array(
160
      'access' => 'rules_action_entity_savedelete_access',
161
    ),
162
  );
163

    
164
  $return['entity_delete'] = array(
165
    'label' => t('Delete entity'),
166
    'parameter' => array(
167
      'data' => array(
168
        'type' => 'entity',
169
        'label' => t('Entity'),
170
        'description' => t('Specifies the entity, which should be deleted permanently.'),
171
        'restriction' => 'selector',
172
        'wrapped' => TRUE,
173
      ),
174
    ),
175
    'group' => t('Entities'),
176
    'access callback' => 'rules_entity_action_access',
177
    'base' => 'rules_action_entity_delete',
178
    'callbacks' => array(
179
      'access' => 'rules_action_entity_savedelete_access',
180
    ),
181
  );
182
  return $return;
183
}
184

    
185
/**
186
 * Custom access callback for data create and fetch action.
187
 */
188
function rules_action_entity_createfetch_access(RulesAbstractPlugin $element) {
189
  $op = $element->getElementName() == 'entity_create' ? 'create' : 'view';
190
  return entity_access($op, $element->settings['type']);
191
}
192

    
193
/**
194
 * Custom access callback for the data query action.
195
 */
196
function rules_action_entity_query_access(RulesAbstractPlugin $element) {
197
  if (!rules_action_entity_createfetch_access($element)) {
198
    return FALSE;
199
  }
200
  $properties = entity_get_all_property_info($element->settings['type']);
201
  if (isset($element->settings['property']) && isset($properties[$element->settings['property']]['access callback'])) {
202
    return call_user_func($properties[$element->settings['property']]['access callback'], 'view', $element->settings['property'], $element->settings['type'], NULL, NULL);
203
  }
204
  return TRUE;
205
}
206

    
207
/**
208
 * Options list callback for a parameter of entity_create.
209
 */
210
function rules_action_entity_parameter_options_list(RulesPlugin $element, $param_name) {
211
  // Remove the parameter name prefix 'param_'.
212
  $property_name = substr($param_name, 6);
213
  $wrapper = entity_metadata_wrapper($element->settings['type']);
214
  // The possible values of the "value" parameter are those of the data param.
215
  return $wrapper->$property_name->optionsList();
216
}
217

    
218
/**
219
 * Custom access callback for data save and delete action.
220
 */
221
function rules_action_entity_savedelete_access(RulesAbstractPlugin $element) {
222
  if ($wrapper = $element->applyDataSelector($element->settings['data:select'])) {
223
    $op = $element->getElementName() == 'entity_save' ? 'save' : 'delete';
224
    return $wrapper instanceof EntityDrupalWrapper && $wrapper->entityAccess($op);
225
  }
226
  return FALSE;
227
}
228

    
229
/**
230
 * Returns the options list for choosing a property of an entity type.
231
 */
232
function rules_action_entity_query_property_options_list(RulesAbstractPlugin $element) {
233
  $element->settings += array('type' => NULL);
234
  if ($element->settings['type']) {
235
    $properties = entity_get_all_property_info($element->settings['type']);
236
    return rules_extract_property($properties, 'label');
237
  }
238
}
239

    
240
/**
241
 * Returns the options list specified for the chosen property.
242
 */
243
function rules_action_entity_query_value_options_list(RulesAbstractPlugin $element) {
244
  // Get the possible values for the selected property.
245
  $element->settings += array('type' => NULL, 'property' => NULL);
246
  if ($element->settings['type'] && $element->settings['property']) {
247
    $wrapper = rules_get_entity_metadata_wrapper_all_properties($element);
248

    
249
    if (isset($wrapper->{$element->settings['property']}) && $property = $wrapper->{$element->settings['property']}) {
250
      return $property->optionsList('view');
251
    }
252
  }
253
}
254

    
255
/**
256
 * Options list callback for data actions.
257
 *
258
 * @param $element
259
 *   The element to return options for.
260
 * @param $param
261
 *   The name of the parameter to return options for.
262
 */
263
function rules_entity_action_type_options($element, $name = NULL) {
264
  // We allow calling this function with just the element name too. That way
265
  // we ease manual re-use.
266
  $name = is_object($element) ? $element->getElementName() : $element;
267
  return ($name == 'entity_create') ? rules_entity_type_options('create') : rules_entity_type_options();
268
}
269

    
270
/**
271
 * Returns options containing entity types having the given key set in the info.
272
 *
273
 * Additionally, we exclude all entity types that are marked as configuration.
274
 */
275
function rules_entity_type_options($key = NULL) {
276
  $info = entity_get_info();
277
  $types = array();
278
  foreach ($info as $type => $entity_info) {
279
    if (empty($entity_info['configuration']) && empty($entity_info['exportable'])) {
280
      if (!isset($key) || entity_type_supports($type, $key)) {
281
        $types[$type] = $entity_info['label'];
282
      }
283
    }
284
  }
285
  return $types;
286
}
287

    
288
/**
289
 * Options list callback for getting a list of possible entity bundles.
290
 *
291
 * @param $element
292
 *   The element to return options for.
293
 */
294
function rules_entity_bundle_options(RulesAbstractPlugin $element) {
295
  $bundles = array();
296
  if (isset($element->settings['type'])) {
297
    $entity_info = entity_get_info($element->settings['type']);
298
    foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
299
      $bundles[$bundle_name] = $bundle_info['label'];
300
    }
301
  }
302
  return $bundles;
303
}
304

    
305
/**
306
 * Entity actions access callback.
307
 *
308
 * Returns TRUE if at least one type is available for configuring the action.
309
 */
310
function rules_entity_action_access($type, $name) {
311
  if ($name == 'entity_fetch' || $name == 'entity_create' || $name == 'entity_query') {
312
    $types = array_keys(rules_entity_action_type_options($name));
313
    $op = $name == 'entity_create' ? 'create' : 'view';
314
  }
315
  elseif ($name == 'entity_save' || $name == 'entity_delete') {
316
    $types = array_keys(entity_get_info());
317
    $op = $name == 'entity_save' ? 'save' : 'delete';
318
  }
319
  foreach ($types as $key => $type) {
320
    if (!entity_access($op, $type)) {
321
      unset($types[$key]);
322
    }
323
  }
324
  return !empty($types);
325
}
326

    
327
/**
328
 * Implements hook_rules_condition_info() on behalf of the entity module.
329
 *
330
 * @see rules_core_modules()
331
 */
332
function rules_entity_condition_info() {
333
  return array(
334
    'entity_is_new' => array(
335
      'label' => t('Entity is new'),
336
      'parameter' => array(
337
        'entity' => array(
338
          'type' => 'entity',
339
          'label' => t('Entity'),
340
          'description' => t('Specifies the entity for which to evaluate the condition.'),
341
          'restriction' => 'selector',
342
        ),
343
      ),
344
      'group' => t('Entities'),
345
      'base' => 'rules_condition_entity_is_new',
346
    ),
347
    'entity_has_field' => array(
348
      'label' => t('Entity has field'),
349
      'parameter' => array(
350
        'entity' => array(
351
          'type' => 'entity',
352
          'label' => t('Entity'),
353
          'description' => t('Specifies the entity for which to evaluate the condition.'),
354
          'restriction' => 'selector',
355
        ),
356
        'field' => array(
357
          'type' => 'text',
358
          'label' => t('Field'),
359
          'description' => t('The name of the field to check for.'),
360
          'options list' => 'rules_condition_entity_has_field_options',
361
          'restriction' => 'input',
362
        ),
363
      ),
364
      'group' => t('Entities'),
365
      'base' => 'rules_condition_entity_has_field',
366
    ),
367
    'entity_is_of_type' => array(
368
      'label' => t('Entity is of type'),
369
      'parameter' => array(
370
        'entity' => array(
371
          'type' => 'entity',
372
          'label' => t('Entity'),
373
          'description' => t('Specifies the entity for which to evaluate the condition.'),
374
        ),
375
        'type' => array(
376
          'type' => 'token',
377
          'label' => t('Entity type'),
378
          'description' => t('The entity type to check for.'),
379
          'options list' => 'rules_entity_action_type_options',
380
          'restriction' => 'input',
381
        ),
382
      ),
383
      'group' => t('Entities'),
384
      'base' => 'rules_condition_entity_is_of_type',
385
    ),
386
    'entity_is_of_bundle' => array(
387
      'label' => t('Entity is of bundle'),
388
      'parameter' => array(
389
        'entity' => array(
390
          'type' => 'entity',
391
          'label' => t('Entity'),
392
          'description' => t('Specifies the entity for which to evaluate the condition.'),
393
        ),
394
        'type' => array(
395
          'type' => 'token',
396
          'label' => t('Entity type'),
397
          'description' => t('The type of the checked entity.'),
398
          'options list' => 'rules_entity_action_type_options',
399
          'restriction' => 'input',
400
        ),
401
        'bundle' => array(
402
          'type' => 'list<text>',
403
          'label' => t('Entity bundle'),
404
          'description' => t('The condition is met if the entity is of one of the selected bundles.'),
405
          'options list' => 'rules_entity_bundle_options',
406
          'restriction' => 'input',
407
        ),
408
      ),
409
      'group' => t('Entities'),
410
      'base' => 'rules_condition_entity_is_of_bundle',
411
    ),
412
    'entity_field_access' => array(
413
      'label' => t('User has field access'),
414
      'parameter' => array(
415
        'entity' => array(
416
          'type' => 'entity',
417
          'label' => t('Entity'),
418
          'description' => t('Specifies the entity for which to evaluate the condition.'),
419
          'restriction' => 'selector',
420
          'wrapped' => TRUE,
421
        ),
422
        'field' => array(
423
          'type' => 'token',
424
          'label' => t('Field name'),
425
          'description' => t('The name of the field to check for.'),
426
          'options list' => 'rules_condition_entity_has_field_options',
427
          'restriction' => 'input',
428
        ),
429
        'op' => array(
430
          'type' => 'text',
431
          'label' => t('Access operation'),
432
          'options list' => 'rules_condition_entity_field_access_op_options',
433
          'restriction' => 'input',
434
          'optional' => TRUE,
435
          'default value' => 'view',
436
        ),
437
        'account' => array(
438
          'type' => 'user',
439
          'label' => t('User account'),
440
          'description' => t('Specifies the user account for which to check access. If left empty, the currently logged in user will be used.'),
441
          'restriction' => 'selector',
442
          'optional' => TRUE,
443
          'default value' => NULL,
444
        ),
445
      ),
446
      'group' => t('Entities'),
447
      'base' => 'rules_condition_entity_field_access',
448
    ),
449
  );
450
}
451

    
452
/**
453
 * Help callback for condition entity_is_new.
454
 */
455
function rules_condition_entity_is_new_help() {
456
  return t('This condition determines whether the specified entity has just been created and has not yet been saved to the database.');
457
}
458

    
459
/**
460
 * Returns options for choosing a field for the selected entity.
461
 */
462
function rules_condition_entity_has_field_options(RulesAbstractPlugin $element) {
463
  // The field_info_field_map() function was introduced in Drupal 7.22. See
464
  // https://www.drupal.org/node/1915646.
465
  if (function_exists('field_info_field_map')) {
466
    $fields = field_info_field_map();
467
  }
468
  else {
469
    $fields = field_info_fields();
470
  }
471
  $field_list = drupal_map_assoc(array_keys($fields));
472
  ksort($field_list);
473
  return $field_list;
474
}
475

    
476
/**
477
 * Returns options for choosing a field_access() operation.
478
 */
479
function rules_condition_entity_field_access_op_options(RulesAbstractPlugin $element) {
480
  return array(
481
    'view' => t('View'),
482
    'edit' => t('Edit'),
483
  );
484
}
485

    
486
/**
487
 * Assert that the entity has the field, if there is metadata for the field.
488
 */
489
function rules_condition_entity_has_field_assertions($element) {
490
  // Assert the field is there if the condition matches.
491
  if ($wrapper = $element->applyDataSelector($element->settings['entity:select'])) {
492
    $type = $wrapper->type();
493
    $field_property = $element->settings['field'];
494
    // Get all possible properties and check whether we have one for the field.
495
    $properties = entity_get_all_property_info($type == 'entity' ? NULL : $type);
496

    
497
    if (isset($properties[$field_property])) {
498
      $assertion = array('property info' => array($field_property => $properties[$field_property]));
499
      return array($element->settings['entity:select'] => $assertion);
500
    }
501
  }
502
}
503

    
504
/**
505
 * Assert the selected entity type.
506
 */
507
function rules_condition_entity_is_of_type_assertions($element) {
508
  if ($type = $element->settings['type']) {
509
    return array('entity' => array('type' => $type));
510
  }
511
}
512

    
513
/**
514
 * Assert the selected entity type and bundle.
515
 */
516
function rules_condition_entity_is_of_bundle_assertions($element) {
517
  if ($bundle = $element->settings['bundle']) {
518
    $assertions = array();
519
    $assertions['entity']['type'] = $element->settings['type'];
520
    $assertions['entity']['bundle'] = $bundle;
521
    return $assertions;
522
  }
523
}
524

    
525
/**
526
 * Process callback for the condition entity_is_of_bundle.
527
 */
528
function rules_condition_entity_is_of_bundle_process(RulesAbstractPlugin $element) {
529
  // If we know the entity type, auto-populate it.
530
  if (($info = $element->getArgumentInfo('entity')) && $info['type'] != 'entity') {
531
    $element->settings['type'] = $info['type'];
532
  }
533
}
534

    
535
/**
536
 * Form alter callback for the condition entity_is_of_bundle.
537
 *
538
 * Use multiple steps to configure the condition as the needed bundle field list
539
 * depends on the selected entity type.
540
 */
541
function rules_condition_entity_is_of_bundle_form_alter(&$form, &$form_state, $options, RulesAbstractPlugin $element) {
542
  if (empty($element->settings['entity:select'])) {
543
    $step = 1;
544
  }
545
  elseif (empty($element->settings['type'])) {
546
    $step = 2;
547
  }
548
  else {
549
    $step = 3;
550
  }
551

    
552
  $form['reload'] = array(
553
    '#weight' => $form['submit']['#weight'] + 1,
554
    '#type' => 'submit',
555
    '#name' => 'reload',
556
    '#value' => $step != 3 ? t('Continue') : t('Reload form'),
557
    '#limit_validation_errors' => array(array('parameter', 'entity'), array('parameter', 'type')),
558
    '#submit' => array('rules_form_submit_rebuild'),
559
    '#ajax' => rules_ui_form_default_ajax('fade'),
560
    '#attributes' => array('class' => array('rules-hide-js')),
561
  );
562
  // Use ajax and trigger as the reload button.
563
  $form['parameter']['type']['settings']['type']['#ajax'] = $form['reload']['#ajax'] + array(
564
    'event' => 'change',
565
    'trigger_as' => array('name' => 'reload'),
566
  );
567

    
568
  switch ($step) {
569
    case 1:
570
      $form['reload']['#limit_validation_errors'] = array(array('parameter', 'entity'));
571
      unset($form['parameter']['type']);
572
      unset($form['reload']['#attributes']['class']);
573
      // NO break.
574
    case 2:
575
      $form['negate']['#access'] = FALSE;
576
      unset($form['parameter']['bundle']);
577
      unset($form['submit']);
578
      break;
579

    
580
    case 3:
581
      if (($info = $element->getArgumentInfo('entity')) && $info['type'] != 'entity') {
582
        // Hide the entity type parameter if not needed.
583
        unset($form['parameter']['type']);
584
      }
585
      break;
586
  }
587
}
588

    
589
/**
590
 * @}
591
 */