Projet

Général

Profil

Paste
Télécharger (18,9 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / rules / modules / entity.rules.inc @ 76e2e7c3

1
<?php
2

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

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

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

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

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

    
133
  $return['entity_save'] = array(
134
    'label' => t('Save entity'),
135
    'parameter' => array(
136
      'data' => array(
137
        'type' => 'entity',
138
        'label' => t('Entity'),
139
        'description' => t('Specifies the entity, which should be saved permanently.'),
140
        'restriction' => 'selector',
141
        'wrapped' => TRUE,
142
      ),
143
      'immediate' => array(
144
        'type' => 'boolean',
145
        'label' => t('Force saving immediately'),
146
        '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.'),
147
        'default value' => FALSE,
148
        'optional' => TRUE,
149
        'restriction' => 'input',
150
      ),
151
    ),
152
    'group' => t('Entities'),
153
    'access callback' => 'rules_entity_action_access',
154
    'base' => 'rules_action_entity_save',
155
    'callbacks' => array(
156
      'access' => 'rules_action_entity_savedelete_access',
157
    ),
158
  );
159

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

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

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

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

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

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

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

    
245
    if (isset($wrapper->{$element->settings['property']}) && $property = $wrapper->{$element->settings['property']}) {
246
      return $property->optionsList('view');
247
    }
248
  }
249
}
250

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

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

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

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

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

    
447
/**
448
 * Help callback for condition entity_is_new.
449
 */
450
function rules_condition_entity_is_new_help() {
451
  return t('This condition determines whether the specified entity has just been created and has not yet been saved to the database.');
452
}
453

    
454
/**
455
 * Returns options for choosing a field for the selected entity.
456
 */
457
function rules_condition_entity_has_field_options(RulesAbstractPlugin $element) {
458
  $options = array();
459
  foreach (field_info_fields() as $field_name => $field) {
460
    $options[$field_name] = $field_name;
461
  }
462
  return $options;
463
}
464

    
465
/**
466
 * Returns options for choosing a field_access() operation.
467
 */
468
function rules_condition_entity_field_access_op_options(RulesAbstractPlugin $element) {
469
  return array(
470
    'view' => t('View'),
471
    'edit' => t('Edit'),
472
  );
473
}
474

    
475
/**
476
 * Assert that the entity has the field, if there is metadata for the field.
477
 */
478
function rules_condition_entity_has_field_assertions($element) {
479
  // Assert the field is there if the condition matches.
480
  if ($wrapper = $element->applyDataSelector($element->settings['entity:select'])) {
481
    $type = $wrapper->type();
482
    $field_property = $element->settings['field'];
483
    // Get all possible properties and check whether we have one for the field.
484
    $properties = entity_get_all_property_info($type == 'entity' ? NULL : $type);
485

    
486
    if (isset($properties[$field_property])) {
487
      $assertion = array('property info' => array($field_property => $properties[$field_property]));
488
      return array($element->settings['entity:select'] => $assertion);
489
    }
490
  }
491
}
492

    
493
/**
494
 * Assert the selected entity type.
495
 */
496
function rules_condition_entity_is_of_type_assertions($element) {
497
  if ($type = $element->settings['type']) {
498
    return array('entity' => array('type' => $type));
499
  }
500
}
501

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

    
514
/**
515
 * Process callback for the condition entity_is_of_bundle.
516
 */
517
function rules_condition_entity_is_of_bundle_process(RulesAbstractPlugin $element) {
518
  // If we know the entity type, auto-populate it.
519
  if (($info = $element->getArgumentInfo('entity')) && $info['type'] != 'entity') {
520
    $element->settings['type'] = $info['type'];
521
  }
522
}
523

    
524
/**
525
 * Form alter callback for the condition entity_is_of_bundle.
526
 *
527
 * Use multiple steps to configure the condition as the needed bundle field list
528
 * depends on the selected entity type.
529
 */
530
function rules_condition_entity_is_of_bundle_form_alter(&$form, &$form_state, $options, RulesAbstractPlugin $element) {
531
  if (empty($element->settings['entity:select'])) {
532
    $step = 1;
533
  }
534
  elseif (empty($element->settings['type'])) {
535
    $step = 2;
536
  }
537
  else {
538
    $step = 3;
539
  }
540

    
541
  $form['reload'] = array(
542
    '#weight' => $form['submit']['#weight'] + 1,
543
    '#type' => 'submit',
544
    '#name' => 'reload',
545
    '#value' => $step != 3 ? t('Continue') : t('Reload form'),
546
    '#limit_validation_errors' => array(array('parameter', 'entity'), array('parameter', 'type')),
547
    '#submit' => array('rules_form_submit_rebuild'),
548
    '#ajax' => rules_ui_form_default_ajax('fade'),
549
    '#attributes' => array('class' => array('rules-hide-js')),
550
  );
551
  // Use ajax and trigger as the reload button.
552
  $form['parameter']['type']['settings']['type']['#ajax'] = $form['reload']['#ajax'] + array(
553
    'event' => 'change',
554
    'trigger_as' => array('name' => 'reload'),
555
  );
556

    
557
  switch ($step) {
558
    case 1:
559
      $form['reload']['#limit_validation_errors'] = array(array('parameter', 'entity'));
560
      unset($form['parameter']['type']);
561
      unset($form['reload']['#attributes']['class']);
562
      // NO break;
563
    case 2:
564
      $form['negate']['#access'] = FALSE;
565
      unset($form['parameter']['bundle']);
566
      unset($form['submit']);
567
      break;
568
    case 3:
569
      if (($info = $element->getArgumentInfo('entity')) && $info['type'] != 'entity') {
570
        // Hide the entity type parameter if not needed.
571
        unset($form['parameter']['type']);
572
      }
573
      break;
574
  }
575
}
576

    
577
/**
578
 * @}
579
 */