View source
<?php
define('RULES_DATE_REGEX_LOOSE', '/^(\\d{4})-?(\\d{2})-?(\\d{2})([T\\s]?(\\d{2}):?(\\d{2}):?(\\d{2})?)?$/');
module_load_include('inc', 'rules', 'modules/rules.events');
function rules_get_actions($key = 'all') {
return rules_gather_data('rules_action_info', $key);
}
function rules_get_conditions($key = 'all') {
return rules_gather_data('rules_condition_info', $key);
}
function rules_get_items($key = 'all') {
if (module_exists('rules')) {
return rules_gather_data('rules_item_info', $key);
}
else {
$info = rules_rules_item_info();
return $key == 'all' ? $info : $info[$key];
}
}
function rules_get_data_types($key = 'all') {
return rules_gather_data('rules_data_type_info', $key);
}
function rules_get_item_defaults($item_type = 'rules') {
rules_include('rules_defaults');
$defaults = rules_gather_data('rules_defaults', 'all', FALSE);
if ($item_type == 'rules' && isset($defaults[$item_type])) {
$items = array_map('rules_rule_format_upgrade', $defaults[$item_type]);
$items = array_map('rules_import_hook', $items);
return $items;
}
return isset($defaults[$item_type]) ? $defaults[$item_type] : array();
}
function rules_get_events($key = 'all') {
return rules_gather_data('rules_event_info', $key);
}
function rules_get_rule_sets($key = NULL) {
$sets = rules_get_event_sets() + rules_get_configured_items('rule_sets');
return isset($key) ? isset($sets[$key]) ? $sets[$key] : NULL : $sets;
}
function rules_get_event_sets() {
$sets = array();
foreach (rules_get_events() as $name => $info) {
$sets['event_' . $name] = $info;
}
return $sets;
}
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];
}
function rules_extract_property($elements, $key) {
$data = array();
foreach ($elements as $name => $info) {
$data[$name] = $info[$key];
}
return $data;
}
function rules_get_rule_set($set_name, $reset = FALSE) {
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 {
$sets = _rules_get_rule_sets();
foreach ($sets as $name => $set) {
rules_sort_children($set['rules']);
cache_set('set_' . $name, $set, 'cache_rules');
}
$inactive_sets = array_diff(array_keys(rules_get_rule_sets()), array_keys($sets));
if ($inactive_sets != variable_get('rules_inactive_sets', array())) {
variable_set('rules_inactive_sets', $inactive_sets);
}
_rules_get_rule_set_initialize($sets);
}
}
return isset($set_name) && isset($sets[$set_name]) ? $sets[$set_name] : array();
}
function _rules_get_rule_set_initialize(&$sets) {
foreach (variable_get('rules_inactive_sets', array()) as $name) {
$sets[$name] = array();
}
}
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']);
$rule['#name'] = $name;
$sets[$rule['#set']]['rules'][$name] = $rule;
}
return $sets;
}
function _rules_rule_is_active($rule) {
_rules_element_defaults($rule);
return $rule['#active'];
}
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);
}
}
function rules_flush_caches() {
variable_del('rules_inactive_sets');
return array(
'cache_rules',
);
}
function rules_invoke_event() {
$args = func_get_args();
$args[0] = 'event_' . $args[0];
call_user_func_array('rules_invoke_rule_set', $args);
}
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);
if (rules_log_evaluation_finished()) {
rules_show_log();
}
}
}
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);
}
function rules_evaluate_elements($elements, &$state) {
$result = FALSE;
if (!isset($elements['#_executed'])) {
$elements['#_executed'] = TRUE;
_rules_element_defaults($elements);
$result = rules_execute_element($elements, $state);
}
if (!isset($elements['#_evaluated']) || $elements['#_evaluated'] == FALSE) {
$elements['#_evaluated'] = TRUE;
$result = rules_execute_and($elements, $state);
}
return $result;
}
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']);
}
}
function rules_sort_elements(&$elements) {
rules_sort_children($elements);
foreach (element_children($elements) as $key) {
rules_sort_elements($elements[$key]);
}
}
function _rules_element_defaults(&$element) {
if (!isset($element['#_defaults_applied'])) {
if (!empty($element['#type']) && ($info = _element_info($element['#type']))) {
$element += $info;
}
$element['#_defaults_applied'] = TRUE;
}
}
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;
}
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'],
)));
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'],
)));
rules_log_evaluated_rule($element);
$result = rules_evaluate_elements($element['#conditions'], $state);
if ($result) {
rules_evaluate_elements($element['#actions'], $state);
}
}
}
return 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;
}
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;
}
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);
if (isset($result) && is_array($result)) {
rules_save_variables($element, $result, $state);
}
}
return TRUE;
}
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;
}
function rules_log($message, $error = FALSE) {
global $_rules_log, $_rules_log_error;
if (isset($_rules_log)) {
list($usec, $sec) = explode(" ", microtime());
$_rules_log[] = array(
'time' => array(
'sec' => $sec,
'usec' => $usec,
),
'msg' => $message,
'error' => $error,
);
$_rules_log_error = !empty($_rules_log_error) || $error;
}
}
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,
);
}
function rules_elements() {
$types = array();
$types['rule'] = array(
'#name' => '',
'#set' => '',
'#status' => 'default',
'#categories' => array(),
'#recursion' => FALSE,
'#active' => TRUE,
'#execute' => 'rules_execute_rule',
'#conditions' => array(),
'#actions' => array(),
);
$types['condition'] = array(
'#name' => '',
'#info' => array(),
'#negate' => FALSE,
'#settings' => array(
'#argument map' => array(),
),
'#execute' => 'rules_execute_condition',
'#suffix' => '<br clear="all" />',
);
$types['action'] = array(
'#name' => '',
'#info' => array(),
'#settings' => array(
'#argument map' => array(),
),
'#execute' => 'rules_execute_action',
'#suffix' => '<br clear="all" />',
);
$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;
}
function rules_init_element_info(&$element) {
if (empty($element['#info']) && ($info = rules_retrieve_element_info($element))) {
unset($info['help']);
$element['#info'] =& $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);
}
}
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',
);
}
}
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');
}
}
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;
}
function rules_configure() {
$args = func_get_args();
$op = array_shift($args);
if (!is_string($op) && is_array($op)) {
return array_merge($op, $args);
}
$op = strtoupper($op);
$element = rules_use_element($op);
$element += $args;
return $element;
}
function rules_use_condition($name, $params = array(), $label = NULL) {
return _rules_element_set_label(rules_use_element('condition', array(
'#name' => $name,
) + $params), $label);
}
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;
}
function rules_use_element($type, $params = array()) {
$element = array(
'#type' => $type,
);
$element += $params;
rules_init_element_info($element);
return $element;
}
function rules_show_log() {
global $_rules_log, $_rules_log_error;
if (!empty($_rules_log) && (!empty($_rules_log_error) || variable_get('rules_debug', FALSE))) {
$i = 0;
$msg = _rules_show_log($i, $_rules_log, $error);
if ($_rules_log_error) {
rules_handle_error_msg('An error occured during rule evaluation. It follows the evaluation log: !log', array(
'!log' => $msg,
));
}
else {
drupal_set_message($msg);
}
$_rules_log = NULL;
$_rules_log_error = NULL;
}
}
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']) {
$output[] = _rules_show_log($i, $data, $error);
}
else {
$diff = $data[$i]['time']['sec'] - $start['sec'] + $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 = '<strong>' . $msg . '</strong>';
}
$output[] = $msg;
if (isset($data[$i]['start']) && !$data[$i]['start']) {
return theme('item_list', $output);
}
}
$i++;
}
return theme('item_list', $output);
}
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;
}
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]);
}
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']]);
}
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;
}
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);
$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));
}
$configurations[$item_type] += rules_get_item_defaults($item_type);
}
return isset($item_type) ? $configurations[$item_type] : array();
}
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));
}
}
function rules_item_change_name($item_type, $old_name, $new_name) {
if ($info = rules_get_items($item_type)) {
db_query("UPDATE {" . $info['db_table'] . "} SET name = '%s' WHERE name = '%s' ", $new_name, $old_name);
}
}
function rules_item_delete($item_type, $name) {
if ($info = rules_get_items($item_type)) {
rules_item_type_invoke($item_type, 'delete', array(
$name,
));
db_query("DELETE FROM {" . $info['db_table'] . "} WHERE name = '%s'", $name);
}
}
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);
}
}
function rules_item_type_invoke($item_type, $op, $params = array()) {
$info = rules_get_items($item_type);
if (function_exists($function = $info['base'] . '_' . $op)) {
return call_user_func_array($function, $params);
}
}
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',
),
);
}
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);
}
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);
}
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;
}
}
function rules_form_alter($form, $form_state, $form_id) {
if ($form_id == 'system_modules') {
rules_clear_cache();
}
}
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') {
$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;
}
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;
}
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;
}
function rules_token_list($type = 'all') {
$tokens = array();
if ($type == 'string' || $type == 'all') {
$tokens['string']['string'] = t("The sanitized string.");
$tokens['string']['string-raw'] = t("The string, WARNING - raw user input");
}
if ($type == 'number' || $type == 'all') {
$tokens['number']['number'] = t("The number.");
}
return $tokens;
}
function rules_token_values($type, $object = NULL, $options = array()) {
$values = array();
if ($type == 'string') {
$string = $object;
$values['string'] = check_plain($string);
$values['string-raw'] = $string;
}
if ($type == 'number') {
$values['number'] = (double) $object;
}
return $values;
}
function rules_gmstrtotime($time) {
if (preg_match(RULES_DATE_REGEX_LOOSE, $time)) {
return strtotime($time . ' UTC');
}
$value = strtotime($time);
$date = gmdate('Y-m-d H:i:s', $value);
return strtotime($date . ' UTC');
}
function rules_features_api() {
return array(
'rules_categories' => array(
'name' => t('Rule configurations by category'),
'feature_source' => TRUE,
'default_hook' => 'rules_defaults',
'file' => drupal_get_path('module', 'rules') . '/rules.export.inc',
),
);
}
function rules_import_hook($rule) {
foreach (module_implements('rules_import') as $module) {
$function = $module . '_rules_import';
$function($rule);
}
return $rule;
}