$info) {
$sets['event_'. $name] = $info;
}
return $sets;
}
/**
* Gathers module definitions for the given name
* Used for collecting events, rules, actions and condtions from other modules
*
* @param $name The type of the data item to collect. This is also the name of the invoked hook.
* @param $key Whether to retrieve all definitions or only the one with the given key
* @param $alter Whether drupal_alter() should be invoked for this data
* @param $reset If the static cache should be reseted. Note that if set to true, nothing will be
* returned.
*/
function rules_gather_data($name, $key = 'all', $alter = TRUE, $reset = FALSE) {
static $data = array();
if ($reset) {
$data = array();
return $data;
}
if (!isset($data[$name])) {
rules_include('rules');
$data[$name] = module_invoke_all($name);
if ($alter) {
drupal_alter($name, $data[$name]);
}
}
if ($key != 'all') {
$data[$name] += array($key => NULL);
return $data[$name][$key];
}
return $data[$name];
}
/**
* Extracts the property with the given name while keeping the keys
*
* @param $key The name of the property to extract
* @param $elements An array of elements
*
* @return An array of extracted properties.
*/
function rules_extract_property($elements, $key) {
$data = array();
foreach ($elements as $name => $info) {
$data[$name] = $info[$key];
}
return $data;
}
/**
* Returns the rule set $set_name, which includes the set info and the rules.
* To improve performance rule sets are cached.
*
* @param $set_name The name of the set which should be returned.
* @param $reset May be set to true to clear the static $sets cache.
*
* @return Returns the set only containing active rules, ready for evaluation
*/
function rules_get_rule_set($set_name, $reset = FALSE) {
//We prevent a lot of queries by storing all sets with active rules with variable_set
static $sets;
if (!isset($sets) || $reset) {
$sets = array();
_rules_get_rule_set_initialize($sets);
}
if (isset($set_name) && !isset($sets[$set_name])) {
if (!$reset && $cache = cache_get('set_'. $set_name, 'cache_rules')) {
$sets[$set_name] = $cache->data;
}
else {
// Cache miss, so refresh the cache for all sets
$sets = _rules_get_rule_sets();
foreach ($sets as $name => $set) {
// Make sure the rules are sorted before writing to the cache.
rules_sort_children($set['rules']);
cache_set('set_'. $name, $set, 'cache_rules');
}
//get all inactive sets and store them to speed up later calls
variable_set('rules_inactive_sets', array_diff(array_keys(rules_get_rule_sets()), array_keys($sets)));
_rules_get_rule_set_initialize($sets);
}
}
return isset($set_name) && isset($sets[$set_name]) ? $sets[$set_name] : array();
}
/**
* Initializes inactive sets
*/
function _rules_get_rule_set_initialize(&$sets) {
foreach (variable_get('rules_inactive_sets', array()) as $name) {
$sets[$name] = array();
}
}
/**
* Actually retrieves all active rules bypassing the cache
*/
function _rules_get_rule_sets() {
$sets = array();
$rules = array_filter(rules_get_configured_items('rules'), '_rules_rule_is_active');
foreach ($rules as $name => $rule) {
$sets += array($rule['#set'] => array());
$sets[$rule['#set']]['info'] = rules_get_rule_sets($rule['#set']);
// Set the name for rules, so that it's avaialbe during evaluation
$rule['#name'] = $name;
$sets[$rule['#set']]['rules'][$name] = $rule;
}
return $sets;
}
/**
* Helper for array_filter()
*/
function _rules_rule_is_active($rule) {
_rules_element_defaults($rule);
return $rule['#active'];
}
/**
* Clears the rule set cache
*
* @param $immediate If FALSE, the static cache will be kept until the next page load.
* Might be dangerous, so only use if you know what you are doing.
*/
function rules_clear_cache($immediate = TRUE) {
cache_clear_all('*', 'cache_rules', TRUE);
variable_del('rules_inactive_sets');
if ($immediate) {
rules_get_rule_set(NULL, TRUE);
rules_gather_data('', 'all', FALSE, TRUE);
rules_get_configured_items(NULL, TRUE);
}
}
/**
* Implementation of hook_flush_caches().
*/
function rules_flush_caches() {
variable_del('rules_inactive_sets');
return array('cache_rules');
}
/**
* Invokes configured rules for the given event
*
* @param $event_name
* The events name
* @param $args
* Pass further arguments as defined in hook_rules_event_info() for this event.
* Arguments can be passed as usual, one by one, in the order as defined
* in hook_rules_event_info(). As an alternative the arguments can also
* be passed as an array, with the argument names as keys. See
* http://drupal.org/node/298549.
*/
function rules_invoke_event() {
$args = func_get_args();
$args[0] = 'event_'. $args[0];
call_user_func_array('rules_invoke_rule_set', $args);
}
/**
* Invokes configured rules for the given rule set
*
* @param $set_name The name of the rule set to invoke
* @param $args Further arguments as defined for the rule set
*/
function rules_invoke_rule_set() {
$args = func_get_args();
$set_name = array_shift($args);
if ($set = rules_get_rule_set($set_name)) {
rules_include('rules');
$state = array('set_info' => $set['info']);
_rules_initialize_variables($state, $args);
rules_evaluate_rule_set($set_name, $set, $state);
//only show the log, if this is no nested evaluation
if (rules_log_evaluation_finished()) {
rules_show_log();
}
}
}
/**
* Evaluates the configured rules for the given rule set and evaluation state.
* This is used, when rule sets are invoked by action. So the action can set up
* a new state, working with the same variables. So the original execution state
* can take over variable saving.
*
* @param $set_name The name of the rule set to invoke
* @param $set The rule set, as returned from rules_get_rule_set().
* @param $state The evaluation state.
* @param $skip_save An optional array of names of variables, for which saving should
* be skipped.
*/
function rules_evaluate_rule_set($set_name, $set, &$state, $skip_save = array()) {
_rules_log_set_invocation(t('%label has been invoked.', array('%label' => $state['set_info']['label'])), TRUE);
rules_evaluate_elements($set['rules'], $state);
foreach ($state['variables'] as $name => $variable) {
if (!in_array($name, $skip_save)) {
$variable->save_changes();
}
}
rules_log_evaluation_clear($set_name);
_rules_log_set_invocation(t('Evaluation of %label has been finished.', array('%label' => $state['set_info']['label'])), FALSE);
}
/**
* Evaluates the elements in a recursive way
* The elements are a tree of rules, conditions, actions and logical operations (AND, OR,..)
*
* Each element is executed by using rules_execute_element().
*
* Elements can use '#execute' to set their execution handler, which can be used to
* to customize the evaluation of the children. E.g. the element 'OR' does this and
* evaluates to TRUE if at least one of its children evaluate to TRUE.
*
* @param $elements An array of elements to evaluate
* @param $state The current evaluation state
*/
function rules_evaluate_elements($elements, &$state) {
$result = FALSE;
//Execute the current element if not yet executed
if (!isset($elements['#_executed'])) {
$elements['#_executed'] = TRUE;
_rules_element_defaults($elements);
$result = rules_execute_element($elements, $state);
}
// we default to evaluate like an AND, which means we stop as soon as one element evaluates to FALSE
// so if the element hasn't evaluated the children, start now
if ((!isset($elements['#_evaluated']) || $elements['#_evaluated'] == FALSE)) {
$elements['#_evaluated'] = TRUE;
$result = rules_execute_and($elements, $state);
}
return $result;
}
/**
* Sorts the children of the elements by maintaining the order of the elements
* if the weight is equal
*/
function rules_sort_children(&$element) {
$count = 0;
foreach (element_children($element) as $key) {
$element[$key] += array('#weight' => 0);
$element[$key]['#weight'] += $count / 1000;
$count++;
}
uasort($element, "element_sort");
foreach (element_children($element) as $key) {
$element[$key]['#weight'] = floor($element[$key]['#weight']);
}
}
/**
* Recursively sorts the elements with rules_sort_children().
*/
function rules_sort_elements(&$elements) {
rules_sort_children($elements);
foreach (element_children($elements) as $key) {
rules_sort_elements($elements[$key]);
}
}
/**
* Makes sure the element defaults are applied
*/
function _rules_element_defaults(&$element) {
if (!isset($element['#_defaults_applied'])) {
if ((!empty($element['#type'])) && ($info = _element_info($element['#type']))) {
// Overlay $info onto $element, retaining preexisting keys in $element.
$element += $info;
}
$element['#_defaults_applied'] = TRUE;
}
}
/**
* Executes the element by invoking the element type's execution handler
*
* @param $elements An array of elements to process
* @param $state The current evaluation state
*
* @return The execution result, or FALSE if there is no valid execution handler.
*/
function rules_execute_element(&$element, &$state) {
if (isset($element['#type']) && isset($element['#execute']) && function_exists($element['#execute'])) {
$element['#_evaluated'] = TRUE;
$result = $element['#execute']($element, $state);
return isset($element['#negate']) && $element['#negate'] == TRUE ? !$result : $result;
}
return FALSE;
}
/**
* Execution handler for rules
*/
function rules_execute_rule(&$element, &$state) {
if ($element['#active'] && !$element['#recursion'] && rules_log_rule_is_evaluated($element)) {
rules_log(t('Not executing the rule %name on rule set %set to prevent recursion.', array('%name' => $element['#label'], '%set' => $state['set_info']['label'])));
// Remember this, so the recursion count is still positive after this evaluation.
rules_log_evaluated_rule($element);
}
else if ($element['#active']) {
rules_log(t('Executing the rule %name on rule set %set', array('%name' => $element['#label'], '%set' => $state['set_info']['label'])));
// Remember that we are processing this rule to prevent recursion
rules_log_evaluated_rule($element);
$result = rules_evaluate_elements($element['#conditions'], $state);
if ($result) {
rules_evaluate_elements($element['#actions'], $state);
}
}
// Return true, so that the next rules are evaluated too
return TRUE;
}
/**
* Execution handler for the OR element
* Evaluates to TRUE if at least one children evaluate to TRUE..
*/
function rules_execute_or(&$elements, &$state) {
foreach (element_children($elements) as $key) {
$result = rules_evaluate_elements($elements[$key], $state);
if ($result) {
return TRUE;
}
}
return FALSE;
}
/**
* Execution handler for the AND element
* Evaluates to TRUE if all children evaluate to TRUE..
*/
function rules_execute_and(&$elements, &$state) {
foreach (element_children($elements) as $key) {
$result = rules_evaluate_elements($elements[$key], $state);
if ($result === FALSE) {
return FALSE;
}
}
return TRUE;
}
/**
* Execution handler for actions
*
* @param $element The action's configuration element
* @param $state The current evaluation state
*
* @return TRUE to let rules proceed wit executing actions, only FALSE if $result['#halt'] is set.
*/
function rules_execute_action($element, &$state) {
$exec_args = rules_get_execution_arguments($element, $state);
if ($exec_args !== FALSE) {
rules_log(t('Action execution: @name', array('@name' => rules_get_element_label($element))));
$result = rules_element_invoke($element, '', $exec_args);
//An action may return altered variables, which are saved automatically
if (isset($result) && is_array($result)) {
rules_save_variables($element, $result, $state);
}
}
return TRUE;
}
/**
* Execution handler for conditions
* Note: An condition may not alter arguments
*
* @param $element The condition's configuration element
* @param $state The current evaluation state
*
* @return The execution result of the condition, or if it is no valid condition FALSE.
*/
function rules_execute_condition($element, &$state) {
$exec_args = rules_get_execution_arguments($element, $state);
if ($exec_args !== FALSE) {
$result = rules_element_invoke($element, '', $exec_args);
rules_log(t('Condition %name evaluated to @bool.', array('%name' => rules_get_element_label($element), '@bool' => $result !== FALSE ? 'TRUE' : 'FALSE')));
return $result;
}
return FALSE;
}
/**
* Writes the message into the log
*/
function rules_log($message, $error = FALSE) {
global $_rules_log;
if (isset($_rules_log)) {
list($usec, $sec) = explode(" ", microtime());
$_rules_log[] = array('time' => array('sec' => $sec, 'usec' => $usec), 'msg' => $message, 'error' => $error);
}
}
/**
* Writes to the log and marks the entry to be the first one of a just started set
*/
function _rules_log_set_invocation($message, $start = TRUE) {
global $_rules_log;
if (!isset($_rules_log)) {
$_rules_log = array();
}
list($usec, $sec) = explode(" ", microtime());
$_rules_log[] = array('time' => array('sec' => $sec, 'usec' => $usec), 'msg' => $message, 'error' => FALSE, 'start' => $start);
}
/**
* Implementation of hook_elements()
* Defines default values for all available properties of rules's element types
*
* Note that the #process handlers are only used by the form API, but not by the rules engine.
*/
function rules_elements() {
$types = array();
$types['rule'] = array('#name' => '', '#set' => '', '#status' => 'default', '#categories' => array(), '#recursion' => FALSE, '#active' => TRUE, '#execute' => 'rules_execute_rule');
$types['condition'] = array('#name' => '', '#info' => array(), '#negate' => FALSE, '#settings' => array('#argument map' => array()), '#execute' => 'rules_execute_condition', '#suffix' => '
');
$types['action'] = array('#name' => '', '#info' => array(), '#settings' => array('#argument map' => array()), '#execute' => 'rules_execute_action', '#suffix' => '
');
$types['OR'] = array('#execute' => 'rules_execute_or', '#logical_op' => TRUE, '#negate' => FALSE, '#theme' => 'rules_operation', '#label' => t('OR'));
$types['AND'] = array('#execute' => 'rules_execute_and', '#logical_op' => TRUE, '#negate' => FALSE, '#theme' => 'rules_operation', '#label' => t('AND'));
return $types;
}
/**
* Initiates the element info property (#info) of an element (actions, conditions,..).
*/
function rules_init_element_info(&$element) {
if (empty($element['#info']) && ($info = rules_retrieve_element_info($element))) {
unset($info['help']);
$element['#info'] = &$info;
}
}
/**
* Retrieves the element (actions, conditions,..) info.
*/
function rules_retrieve_element_info(&$element) {
$element_copy = $element;
_rules_element_defaults($element_copy);
if (isset($element_copy['#info']) && isset($element['#name'])) {
if ($info = rules_gather_data('rules_'. $element['#type'] .'_info', $element['#name'])) {
return $info;
}
rules_error_missing_implementation($element);
}
}
/**
* Returns the cached element info of the element.
*/
function rules_get_element_info(&$element) {
rules_init_element_info($element);
if (isset($element['#info'])) {
return $element['#info'] + array(
'arguments' => array(),
'new variables' => array(),
'hidden' => FALSE,
'eval input' => array(),
'label callback' => $element['#name'] .'_label',
);
}
}
/**
* Gets the element's label
*/
function rules_get_element_label(&$element) {
foreach (array('#label', 'label') as $key) {
if (isset($element[$key])) {
return $element[$key];
}
}
if ($info = rules_get_element_info($element)) {
return isset($info['label']) ? $info['label'] : t('unlabelled');
}
}
/**
* Invokes an element specific function. E.g. this is used for invoking actions.
*
* @param $op The operation to invoke. If one is given, it will be appended to the
* function base name, separated by an underscore.
* @param $params An array of parameters which should be passed to the invoked
* function.
* @param $error Whether an error should be generated, when no implementation is found.
*
* @return FALSE, if no implementation is found. Else the return of the implementation will
* be passed through.
*/
function rules_element_invoke($element, $op = '', $params, $error = TRUE) {
$op = $op ? '_'. $op : '';
if (($info = rules_get_element_info($element)) && isset($info['base'])) {
if (function_exists($function = $info['base'] . $op)) {
return call_user_func_array($function, $params);
}
}
if (isset($element['#name']) && function_exists($function = $element['#name'] . $op)) {
return call_user_func_array($function, $params);
}
if ($error) {
rules_error_missing_implementation($element);
}
return FALSE;
}
/**
* A simple helping function, which eases the creation of rules
* Example use case: $conditions = rules_configure('OR', $condition1, conditions2);
*
* @param $op One supported operation like 'AND', 'OR'. If ommitted the passed elements
* will just be added to the first one.
* @param $elements The elements to configure.
*/
function rules_configure() {
$args = func_get_args();
$op = array_shift($args);
if (!is_string($op) && is_array($op)) {
//just add the elements to the first element
return array_merge($op, $args);
}
$op = strtoupper($op);
$element = rules_use_element($op);
$element += $args;
return $element;
}
/**
* Configures a condition for using in a rule
*
* @param $name The name of condition to create, as specified at hook_condition_info()
* @param $params An optional array of properties to add, e.g. #settings
* @param $label An optional label for the condition
*/
function rules_use_condition($name, $params = array(), $label = NULL) {
return _rules_element_set_label(rules_use_element('condition', array('#name' => $name) + $params), $label);
}
/**
* Configures an action for using in a rule
*
* @param $name The name of action to create, as specified at hook_action_info()
* @param $params An optional array of properties to add, e.g. #settings
* @param $label An optional label for the action
*/
function rules_use_action($name, $params = array(), $label = NULL) {
return _rules_element_set_label(rules_use_element('action', array('#name' => $name) + $params), $label);
}
function _rules_element_set_label($element, $label = NULL) {
if (!empty($element['#info'])) {
$info = isset($label) ? array('label' => $label) : array();
$element['#info'] = $info + $element['#info'];
}
return $element;
}
/**
* Configures an element of type $type with the further properties $params
*/
function rules_use_element($type, $params = array()) {
$element = array('#type' => $type);
//add in the element info to speed up execution
$element += $params;
rules_init_element_info($element);
return $element;
}
/**
* Shows the log and clears it afterwards
*/
function rules_show_log() {
global $_rules_log;
if (is_array($_rules_log) && count($_rules_log)) {
$i = 0;
$error = FALSE;
$msg = _rules_show_log($i, $_rules_log, $error);
$_rules_log = NULL;
if ($error) {
rules_handle_error_msg('An error occured during rule evaluation. It follows the evaluation log: !log', array('!log' => $msg));
}
else if (variable_get('rules_debug', FALSE)) {
drupal_set_message($msg);
}
}
}
function _rules_show_log(&$i, $data, &$error) {
$start = &$data[0]['time'];
$output = array();
while ($i < count($data)) {
if ($output && isset($data[$i]['start']) && $data[$i]['start']) {
//the next entry stems from another evaluated set, add in its log messages here
$output[] = _rules_show_log($i, $data, $error);
}
else {
$diff = ($data[$i]['time']['sec'] - $start['sec']) * 1000000 + $data[$i]['time']['usec'] - $start['usec'];
$formatted_diff = round($diff * 1000, 3) .' ms';
$msg = $formatted_diff .' '. $data[$i]['msg'];
if ($data[$i]['error']) {
$error = TRUE;
$msg = ''. $msg .'';
}
$output[] = $msg;
if (isset($data[$i]['start']) && !$data[$i]['start']) {
//this was the last log entry of this set
return theme('item_list', $output);
}
}
$i++;
}
return theme('item_list', $output);
}
/**
* Remembers the currently evaluated rules. With this information, recursion is prevented
*
* @param $rule The rule, which execution should be logged
*/
function rules_log_evaluated_rule($rule) {
global $_rules_exec_log;
if (!isset($_rules_exec_log)) {
$_rules_exec_log = array();
}
$count = isset($_rules_exec_log[$rule['#set']][$rule['#name']]) ? $_rules_exec_log[$rule['#set']][$rule['#name']] : 0;
$_rules_exec_log[$rule['#set']][$rule['#name']] = $count + 1;
}
/**
* Clears the rule evaluation log for the given rule set.
*/
function rules_log_evaluation_clear($set_name) {
global $_rules_exec_log;
foreach ($_rules_exec_log[$set_name] as $rule => $count) {
$_rules_exec_log[$set_name][$rule] = $count - 1;
}
$_rules_exec_log[$set_name] = array_filter($_rules_exec_log[$set_name]);
}
/**
* Checks if the given rule is currently evaluated.
*
* @param $name The name of the rule, which execution should be logged
*/
function rules_log_rule_is_evaluated($rule) {
global $_rules_exec_log;
return is_array($_rules_exec_log) && isset($_rules_exec_log[$rule['#set']][$rule['#name']]);
}
/**
* Checks whether every rule evaluation is finished
*/
function rules_log_evaluation_finished() {
global $_rules_exec_log;
$_rules_exec_log = array_filter($_rules_exec_log);
return !is_array($_rules_exec_log) || count($_rules_exec_log) == 0;
}
/**
* Gets all configured items, regardless if defined by the admin
* or by a module
*
* @param $items Which items to get, e.g. 'rules' or 'rule_sets'. Use NULL when clearing the cache.
* @param Whether the cache should be cleared
*
* @return An array of configured items, where the structure of the item configuration
* depends on the item
*/
function rules_get_configured_items($item_type = 'rules', $reset = FALSE) {
static $configurations = array();
if ($reset) {
$configurations = array();
}
if (isset($item_type) && !isset($configurations[$item_type])) {
$info = rules_get_items($item_type);
//get and add altered default items
$result = db_query("SELECT * FROM {". $info['db_table'] ."} ORDER by name");
$configurations[$item_type] = array();
while ($row = db_fetch_object($result)) {
$configurations[$item_type][$row->name] = unserialize(db_decode_blob($row->data));
}
//add not altered default items
$configurations[$item_type] += rules_get_item_defaults($item_type);
}
return isset($item_type) ? $configurations[$item_type] : array();
}
/**
* Saves the given item to the database
*/
function rules_item_save($item_type, $name, $item) {
if ($info = rules_get_items($item_type)) {
db_query("DELETE FROM {". $info['db_table'] ."} WHERE name = '%s'", $name);
db_query("INSERT INTO {". $info['db_table'] ."} (name, data) VALUES ('%s', %b)", $name, serialize($item));
}
}
/**
* Deletes the given item from the database
*/
function rules_item_delete($item_type, $name) {
if ($info = rules_get_items($item_type)) {
rules_item_type_invoke($item_type, 'delete', $name);
db_query("DELETE FROM {". $info['db_table'] ."} WHERE name = '%s'", $name);
}
}
/**
* Used to inform the rules engine about an added item type,
* so it can create the db table if necessary
*/
function rules_enable_items($item_type, $ret = array()) {
$info = rules_get_items($item_type);
if (!db_table_exists($info['db_table'])) {
$schema = drupal_get_schema($info['db_table'], TRUE);
db_create_table($ret, $info['db_table'], $schema);
}
}
/**
* Invoke an item type specific function, which will be item types
* base appended with _$op. The parameters given in $params will be
* passed to this function.
*/
function rules_item_type_invoke($item_type, $op, $params) {
$info = rules_get_items($item_type);
if (function_exists($function = $info['base'] .'_'. $op)) {
return call_user_func_array($function, $params);
}
}
/**
* Implementation of hook_rules_item_info
*/
function rules_rules_item_info() {
return array(
'rules' => array(
'label' => t('Rules'),
'db_table' => 'rules_rules',
'base' => 'rules_item_rule',
),
'rule_sets' => array(
'label' => t('Rule Sets'),
'db_table' => 'rules_sets',
'base' => 'rules_item_rule_set',
),
);
}
/**
* Shows an error message, that a module is missing.
*
* @param $element The element, for which the implementation is missing
*/
function rules_error_missing_implementation($element) {
if (isset($element['#info']) && $element['#info']) {
$msg = t('Unable to find %type of name %name with the label %label. Perhaps the according module has been deactivated.', array('%type' => $element['#type'], '%name' => $element['#name'], '%label' => rules_get_element_label($element)));
}
else {
$msg = t('Unable to find %type of name %name. Perhaps the according module has been deactivated.', array('%type' => $element['#type'], '%name' => $element['#name']));
}
rules_log($msg, TRUE);
}
/**
* Handles a error message. If the user has permission to administer the rules engine,
* show him the error. Otherwise just log it.
*/
function rules_handle_error_msg($message, $variables, $rule_name = NULL) {
if (user_access('administer rules')) {
drupal_set_message(t($message, $variables), 'error');
}
$link = (isset($rule_name)) ? l(t('Show rule configuration'), PATH .'/'. $rule_name) : NULL;
watchdog('rules', $message, $variables, WATCHDOG_ERROR, $link);
}
/**
* Own version of array_intersect_key for php < 5.1
*/
if (!function_exists('array_intersect_key')) {
function array_intersect_key() {
$arrs = func_get_args();
$result = array_shift($arrs);
foreach ($arrs as $array) {
foreach ($result as $key => $v) {
if (!array_key_exists($key, $array)) {
unset($result[$key]);
}
}
}
return $result;
}
}
/**
* Implementation of hook_form_alter()
* Clear the cache when a module is deactivated
*/
function rules_form_alter($form, $form_state, $form_id) {
if ($form_id == 'system_modules') {
rules_clear_cache();
}
}
/**
* Includes rules specific include files
*
* @param $type
* One of 'rules', 'rules_forms', 'rules_defaults' or 'rules_admin'.
*/
function rules_include($type = 'rules') {
static $included;
if (!isset($included)) {
$included = array();
}
if (!isset($included[$type])) {
$included[$type] = TRUE;
if ($type == 'rules_admin') {
$files = array(drupal_get_path('module', 'rules_admin') .'/rules_admin.inc');
}
elseif ($cache = cache_get('include_'. $type, 'cache_rules')) {
$files = $cache->data;
}
else {
$files = _rules_include_get_files($type);
cache_set('include_'. $type, $files, 'cache_rules');
}
foreach ($files as $file) {
include_once $file;
}
rules_log(t('Included @module.rules.inc files.', array('@module.rules.inc' => 'MODULE.'. $type .'.inc')));
}
}
function _rules_include_get_files($type) {
$files = array();
$rules_path = drupal_get_path('module', 'rules');
if ($type == 'rules') {
//make sure this is included before, as it contains some base classes
$files[] = $rules_path .'/rules.data_types.inc';
$files[] = $rules_path .'/rules.variables.inc';
$files[] = $rules_path .'/rules.input_evaluators.inc';
}
foreach (module_list() as $module) {
$module_path = drupal_get_path('module', $module);
if (file_exists("$module_path/$module.$type.inc")) {
$files[] = "./$module_path/$module.$type.inc";
}
else if (file_exists("$module_path/includes/$module.$type.inc")) {
$files[] = "./$module_path/includes/$module.$type.inc";
}
else if (file_exists("$rules_path/modules/$module.$type.inc")) {
$files[] = "./$rules_path/modules/$module.$type.inc";
}
}
return $files;
}
/**
* An form after build callback that can be used to include arbitrary
* files needed by the form.
*/
function rules_after_build_include_files($form, $form_state) {
static $files = array();
if (isset($form['#includes'])) {
foreach ($form['#includes'] as $file) {
if (!isset($files[$file])) {
include_once $file;
$files[$file] = TRUE;
}
}
}
return $form;
}
/**
* Makes sure the rule is in the latest format. If not it will be upgraded
* automatically.
*/
function rules_rule_format_upgrade($rule) {
static $included = FALSE;
$upgrades = array();
if (!isset($rule['#version'])) {
$upgrades[] = 'rules_rule_format_upgrade_6003';
}
if (!empty($upgrades) && !$included) {
module_load_include('install', 'rules');
$included = TRUE;
}
foreach ($upgrades as $upgrade) {
$rule = $upgrade($rule);
}
return $rule;
}