rules_core.rules.inc 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. <?php
  2. /**
  3. * @file
  4. * Rules integration with Drupal core.
  5. *
  6. * Provides data types, conditions, and actions to invoke configured components.
  7. *
  8. * @addtogroup rules
  9. *
  10. * @{
  11. */
  12. /**
  13. * Implements hook_rules_category_info() on behalf of the rules_core.
  14. */
  15. function rules_rules_core_category_info() {
  16. return array(
  17. 'rules_components' => array(
  18. 'label' => t('Components'),
  19. 'equals group' => t('Components'),
  20. 'weight' => 50,
  21. ),
  22. );
  23. }
  24. /**
  25. * Implements hook_rules_file_info() on behalf of the pseudo rules_core module.
  26. *
  27. * @see rules_core_modules()
  28. */
  29. function rules_rules_core_file_info() {
  30. return array('modules/rules_core.eval');
  31. }
  32. /**
  33. * Implements hook_rules_data_info() on behalf of the pseudo rules_core module.
  34. *
  35. * @see rules_core_modules()
  36. */
  37. function rules_rules_core_data_info() {
  38. $return = array(
  39. 'text' => array(
  40. 'label' => t('text'),
  41. 'ui class' => 'RulesDataUIText',
  42. 'token type' => 'rules_text',
  43. ),
  44. 'token' => array(
  45. 'label' => t('text token'),
  46. 'parent' => 'text',
  47. 'ui class' => 'RulesDataUITextToken',
  48. 'token type' => 'rules_token',
  49. ),
  50. // A formatted text as used by entity metadata.
  51. 'text_formatted' => array(
  52. 'label' => t('formatted text'),
  53. 'ui class' => 'RulesDataUITextFormatted',
  54. 'wrap' => TRUE,
  55. 'property info' => entity_property_text_formatted_info(),
  56. ),
  57. 'decimal' => array(
  58. 'label' => t('decimal number'),
  59. 'parent' => 'text',
  60. 'ui class' => 'RulesDataUIDecimal',
  61. 'token type' => 'rules_decimal',
  62. ),
  63. 'integer' => array(
  64. 'label' => t('integer'),
  65. 'class' => 'RulesIntegerWrapper',
  66. 'parent' => 'decimal',
  67. 'ui class' => 'RulesDataUIInteger',
  68. 'token type' => 'rules_integer',
  69. ),
  70. 'date' => array(
  71. 'label' => t('date'),
  72. 'ui class' => 'RulesDataUIDate',
  73. 'token type' => 'rules_date',
  74. ),
  75. 'duration' => array(
  76. 'label' => t('duration'),
  77. 'parent' => 'integer',
  78. 'ui class' => 'RulesDataUIDuration',
  79. 'token type' => 'rules_duration',
  80. ),
  81. 'boolean' => array(
  82. 'label' => t('truth value'),
  83. 'ui class' => 'RulesDataUIBoolean',
  84. 'token type' => 'rules_boolean',
  85. ),
  86. 'uri' => array(
  87. 'label' => t('URI'),
  88. 'parent' => 'text',
  89. // Clean inserted tokens with "rawurlencode".
  90. 'cleaning callback' => 'rawurlencode',
  91. 'ui class' => 'RulesDataUIURI',
  92. 'token type' => 'rules_uri',
  93. ),
  94. 'list' => array(
  95. 'label' => t('list', array(), array('context' => 'data_types')),
  96. 'wrap' => TRUE,
  97. 'group' => t('List', array(), array('context' => 'data_types')),
  98. ),
  99. 'list<text>' => array(
  100. 'label' => t('list of text'),
  101. 'ui class' => 'RulesDataUIListText',
  102. 'wrap' => TRUE,
  103. 'group' => t('List', array(), array('context' => 'data_types')),
  104. ),
  105. 'list<integer>' => array(
  106. 'label' => t('list of integer'),
  107. 'ui class' => 'RulesDataUIListInteger',
  108. 'wrap' => TRUE,
  109. 'group' => t('List', array(), array('context' => 'data_types')),
  110. ),
  111. 'list<token>' => array(
  112. 'label' => t('list of text tokens'),
  113. 'ui class' => 'RulesDataUIListToken',
  114. 'wrap' => TRUE,
  115. 'group' => t('List', array(), array('context' => 'data_types')),
  116. ),
  117. 'entity' => array(
  118. 'label' => t('any entity'),
  119. 'group' => t('Entity'),
  120. 'is wrapped' => TRUE,
  121. ),
  122. 'ip_address' => array(
  123. 'label' => t('IP Address'),
  124. 'parent' => 'text',
  125. 'ui class' => 'RulesDataUIIPAddress',
  126. 'token type' => 'rules_text',
  127. ),
  128. );
  129. foreach (entity_get_info() as $type => $info) {
  130. if (!empty($info['label'])) {
  131. $return[$type] = array(
  132. 'label' => strtolower($info['label'][0]) . substr($info['label'], 1),
  133. 'parent' => 'entity',
  134. 'wrap' => TRUE,
  135. 'group' => t('Entity'),
  136. 'ui class' => empty($info['exportable']) ? 'RulesDataUIEntity' : 'RulesDataUIEntityExportable',
  137. );
  138. // If this entity type serves as bundle for another one, provide an
  139. // options list for selecting a bundle entity.
  140. if (!empty($info['bundle of'])) {
  141. $return[$type]['ui class'] = 'RulesDataUIBundleEntity';
  142. }
  143. }
  144. }
  145. if (module_exists('taxonomy')) {
  146. // For exportability identify vocabularies by name.
  147. $return['taxonomy_vocabulary']['wrapper class'] = 'RulesTaxonomyVocabularyWrapper';
  148. $return['taxonomy_vocabulary']['ui class'] = 'RulesDataUITaxonomyVocabulary';
  149. }
  150. return $return;
  151. }
  152. /**
  153. * Implements hook_rules_data_info_alter() on behalf of the pseudo rules_core module.
  154. *
  155. * Makes sure there is a list<type> data type for each type registered.
  156. *
  157. * @see rules_rules_data_info_alter()
  158. */
  159. function rules_rules_core_data_info_alter(&$data_info) {
  160. foreach ($data_info as $type => $info) {
  161. if (!entity_property_list_extract_type($type)) {
  162. $list_type = "list<$type>";
  163. if (!isset($data_info[$list_type])) {
  164. $data_info[$list_type] = array(
  165. 'label' => t('list of @type_label items', array('@type_label' => $info['label'])),
  166. 'wrap' => TRUE,
  167. 'group' => t('List', array(), array('context' => 'data_types')),
  168. );
  169. if (isset($info['parent']) && $info['parent'] == 'entity') {
  170. $data_info[$list_type]['ui class'] = 'RulesDataUIListEntity';
  171. }
  172. }
  173. }
  174. }
  175. }
  176. /**
  177. * Implements hook_rules_evaluator_info() on behalf of the pseudo rules_core
  178. * module.
  179. *
  180. * @see rules_core_modules()
  181. */
  182. function rules_rules_core_evaluator_info() {
  183. return array(
  184. // Process strtotime() inputs to timestamps.
  185. 'date' => array(
  186. 'class' => 'RulesDateInputEvaluator',
  187. 'type' => 'date',
  188. 'weight' => -10,
  189. ),
  190. // Post-process any input value to absolute URIs.
  191. 'uri' => array(
  192. 'class' => 'RulesURIInputEvaluator',
  193. 'type' => 'uri',
  194. 'weight' => 50,
  195. ),
  196. );
  197. }
  198. /**
  199. * Implements hook_rules_data_processor_info() on behalf of the pseudo
  200. * rules_core module.
  201. *
  202. * @see rules_core_modules()
  203. */
  204. function rules_rules_core_data_processor_info() {
  205. return array(
  206. 'date_offset' => array(
  207. 'class' => 'RulesDateOffsetProcessor',
  208. 'type' => 'date',
  209. 'weight' => -2,
  210. ),
  211. 'num_offset' => array(
  212. 'class' => 'RulesNumericOffsetProcessor',
  213. 'type' => array('integer', 'decimal'),
  214. 'weight' => -2,
  215. ),
  216. );
  217. }
  218. /**
  219. * Implements hook_rules_condition_info() on behalf of the pseudo rules_core
  220. * module.
  221. *
  222. * @see rules_core_modules()
  223. */
  224. function rules_rules_core_condition_info() {
  225. $defaults = array(
  226. 'group' => t('Components'),
  227. 'base' => 'rules_element_invoke_component',
  228. 'named parameter' => TRUE,
  229. 'access callback' => 'rules_element_invoke_component_access_callback',
  230. );
  231. $items = array();
  232. foreach (rules_get_components(FALSE, 'condition') as $name => $config) {
  233. $items['component_' . $name] = $defaults + array(
  234. 'label' => $config->plugin() . ': ' . drupal_ucfirst($config->label()),
  235. 'parameter' => $config->parameterInfo(),
  236. );
  237. $items['component_' . $name]['#config_name'] = $name;
  238. }
  239. return $items;
  240. }
  241. /**
  242. * Implements hook_rules_action_info() on behalf of the pseudo rules_core
  243. * module.
  244. *
  245. * @see rules_core_modules()
  246. */
  247. function rules_rules_core_action_info() {
  248. $defaults = array(
  249. 'group' => t('Components'),
  250. 'base' => 'rules_element_invoke_component',
  251. 'named parameter' => TRUE,
  252. 'access callback' => 'rules_element_invoke_component_access_callback',
  253. );
  254. $items = array();
  255. foreach (rules_get_components(FALSE, 'action') as $name => $config) {
  256. $items['component_' . $name] = $defaults + array(
  257. 'label' => $config->plugin() . ': ' . drupal_ucfirst($config->label()),
  258. 'parameter' => $config->parameterInfo(),
  259. 'provides' => $config->providesVariables(),
  260. );
  261. $items['component_' . $name]['#config_name'] = $name;
  262. }
  263. return $items;
  264. }
  265. /**
  266. * Implements RulesPluginUIInterface::operations() for the action.
  267. */
  268. function rules_element_invoke_component_operations(RulesPlugin $element) {
  269. $defaults = $element->extender('RulesPluginUI')->operations();
  270. $info = $element->info();
  271. // Add an operation for editing the component.
  272. $defaults['#links']['component'] = array(
  273. 'title' => t('edit component'),
  274. 'href' => RulesPluginUI::path($info['#config_name']),
  275. );
  276. return $defaults;
  277. }
  278. /**
  279. * Validate callback to make sure the invoked component exists and is not dirty.
  280. *
  281. * @see rules_scheduler_action_schedule_validate()
  282. */
  283. function rules_element_invoke_component_validate(RulesPlugin $element) {
  284. $info = $element->info();
  285. $component = rules_config_load($info['#config_name']);
  286. // Check if a component exists.
  287. if (!$component) {
  288. throw new RulesIntegrityException(t('The component %config does not exist.', array('%config' => $info['#config_name'])), $element);
  289. }
  290. // Check if a component is marked as dirty.
  291. rules_config_update_dirty_flag($component);
  292. if (!empty($component->dirty)) {
  293. throw new RulesIntegrityException(t('The utilized component %config fails the integrity check.', array('%config' => $info['#config_name'])), $element);
  294. }
  295. }
  296. /**
  297. * Implements the features export callback of the RulesPluginFeaturesIntegrationInterface.
  298. */
  299. function rules_element_invoke_component_features_export(&$export, &$pipe, $module_name = '', $element) {
  300. // Add the used component to the pipe.
  301. $info = $element->info();
  302. $pipe['rules_config'][] = $info['#config_name'];
  303. }
  304. /**
  305. * Access callback for the invoke component condition/action.
  306. */
  307. function rules_element_invoke_component_access_callback($type, $name) {
  308. // Cut of the leading 'component_' from the action name.
  309. $component = rules_config_load(substr($name, 10));
  310. if (!$component) {
  311. // Missing component.
  312. return FALSE;
  313. }
  314. // If access is not exposed for this component, default to component access.
  315. if (empty($component->access_exposed)) {
  316. return $component->access();
  317. }
  318. // Apply the permissions.
  319. return user_access('bypass rules access') || user_access("use Rules component $component->name");
  320. }
  321. /**
  322. * @}
  323. */