ca.module in Ubercart 6.2
This is a demonstration module for the new conditional actions API.
File
ca/ca.moduleView source
<?php
/**
* @file
* This is a demonstration module for the new conditional actions API.
*/
/**
* The Drupal menu path to Conditional Actions pages.
*/
define('CA_UI_PATH', 'admin/store/ca');
require_once 'ca.ca.inc';
/*******************************************************************************
* Drupal Hooks
******************************************************************************/
/**
* Implements hook_menu().
*/
function ca_menu() {
$items = array();
$items[CA_UI_PATH] = array(
'title' => 'Conditional actions',
'description' => 'Administer the predicates setup to automate your store.',
'page callback' => 'ca_admin',
'access arguments' => array(
'administer conditional actions',
),
'file' => 'ca.admin.inc',
'weight' => 5,
);
$items[CA_UI_PATH . '/overview'] = array(
'title' => 'Overview',
'weight' => 0,
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items[CA_UI_PATH . '/overview/trigger'] = array(
'title' => 'By trigger',
'description' => 'Administer the predicates setup to automate your store.',
'weight' => 0,
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items[CA_UI_PATH . '/overview/class'] = array(
'title' => 'By class',
'description' => 'Administer the predicates setup to automate your store.',
'page callback' => 'ca_admin',
'page arguments' => array(
'class',
),
'access arguments' => array(
'administer conditional actions',
),
'type' => MENU_LOCAL_TASK,
'weight' => 5,
'file' => 'ca.admin.inc',
);
$items[CA_UI_PATH . '/add'] = array(
'title' => 'Add a predicate',
'description' => 'Allows an administrator to create a new predicate.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'ca_predicate_meta_form',
'0',
),
'access arguments' => array(
'administer conditional actions',
),
'type' => MENU_LOCAL_TASK,
'weight' => 5,
'file' => 'ca.admin.inc',
);
$items[CA_UI_PATH . '/convert'] = array(
'title' => 'Convert configurations',
'description' => 'Convert Workflow-ng configurations into Conditional Actions predicates.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'ca_conversion_form',
),
'access callback' => 'ca_convert_configurations_access',
'type' => MENU_LOCAL_TASK,
'weight' => 10,
'file' => 'ca.admin.inc',
);
$items[CA_UI_PATH . '/%/edit'] = array(
'title' => 'Edit predicate',
'description' => "Edit a predicate's meta data, conditions, and actions.",
'page callback' => 'drupal_get_form',
'page arguments' => array(
'ca_predicate_meta_form',
3,
),
'access arguments' => array(
'administer conditional actions',
),
'file' => 'ca.admin.inc',
'type' => MENU_CALLBACK,
);
$items[CA_UI_PATH . '/%/edit/meta'] = array(
'title' => 'Meta data',
'description' => 'Edit the meta data for a predicate like title, trigger, etc.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'ca_predicate_meta_form',
3,
),
'access arguments' => array(
'administer conditional actions',
),
'file' => 'ca.admin.inc',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items[CA_UI_PATH . '/%/edit/conditions'] = array(
'title' => 'Conditions',
'description' => 'Edit the conditions for a predicate.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'ca_conditions_form',
3,
),
'access arguments' => array(
'administer conditional actions',
),
'file' => 'ca.admin.inc',
'type' => MENU_LOCAL_TASK,
'weight' => -5,
);
$items[CA_UI_PATH . '/%/edit/actions'] = array(
'title' => 'Actions',
'description' => 'Edit the actions for a predicate.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'ca_actions_form',
3,
),
'access arguments' => array(
'administer conditional actions',
),
'file' => 'ca.admin.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 0,
);
$items[CA_UI_PATH . '/%/reset'] = array(
'title' => 'Reset a predicate',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'ca_predicate_delete_form',
3,
),
'access arguments' => array(
'administer conditional actions',
),
'file' => 'ca.admin.inc',
'type' => MENU_CALLBACK,
);
$items[CA_UI_PATH . '/%/delete'] = array(
'title' => 'Delete a predicate',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'ca_predicate_delete_form',
3,
),
'access arguments' => array(
'administer conditional actions',
),
'file' => 'ca.admin.inc',
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Determine access to the configuration conversion form.
*/
function ca_convert_configurations_access() {
return user_access('administer conditional actions') && variable_get('ca_show_conversion_tab', TRUE);
}
/**
* Implements hook_perm().
*/
function ca_perm() {
return array(
'administer conditional actions',
);
}
/*******************************************************************************
* Module and Helper Functions
******************************************************************************/
/**
* Pull a trigger and evaluate any predicates associated with that trigger.
*
* @param ...
* Accepts a variable number of arguments. The first should always be the
* string name of the trigger to pull with any additional arguments being
* the arguments expected by the trigger and used for evaluation.
* @return
* TRUE or FALSE indicating if at least one predicate was evaluated.
*/
function ca_pull_trigger() {
$args = func_get_args();
$trigger = array_shift($args);
// Load the data for the specified trigger.
$trigger_data = ca_load_trigger($trigger);
// Fail if the specified trigger doesn't exist.
if (!$trigger_data) {
return FALSE;
}
// Load any predicates associated with the trigger.
$predicates = ca_load_trigger_predicates($trigger);
// Fail if we didn't find any predicates.
if (!$predicates || count($predicates) == 0) {
return FALSE;
}
// Prepare the arguments for evaluation.
$arguments = ca_parse_trigger_args($trigger_data, $args);
// Fail if we didn't receive the right type of or enough arguments.
if (!$arguments) {
return FALSE;
}
// Loop through the predicates and evaluate them one by one.
foreach ($predicates as $pid => $predicate) {
// If all of a predicate's conditions evaluate to TRUE...
if (ca_evaluate_conditions($predicate, $arguments)) {
// Then perform its actions.
ca_perform_actions($predicate, $arguments);
}
}
return TRUE;
}
/**
* Parse the argument array into a CA friendly array for the trigger.
*
* @param $trigger
* The name of the trigger for which we are parsing the arguments.
* @param $args
* An array of arguments to check against the expected arguments.
* @return
* The array of arguments keyed according to the trigger's argument names.
*/
function ca_parse_trigger_args($trigger, $args) {
// Fail if we didn't receive enough arguments for this trigger.
if (count($args) < count($trigger['#arguments'])) {
return FALSE;
}
// Load all the entity information.
$entities = module_invoke_all('ca_entity');
// Loop through the expected arguments.
foreach ($trigger['#arguments'] as $key => $value) {
// Grab for comparison the next argument passed to the trigger.
$arg = array_shift($args);
// Check the type and fail if it is incorrect.
if (gettype($arg) != $entities[$value['#entity']]['#type']) {
return FALSE;
}
// Add the entity to the arguments array along with its meta data.
$arguments[$key] = array(
'#entity' => $value['#entity'],
'#title' => $value['#title'],
'#data' => $arg,
);
}
return $arguments;
}
/**
* Load predicates based on the specified parameters.
*
* @param $trigger
* The name of the trigger for which to search when loading the predicates.
* @param $all
* FALSE by default, specifies whether we want to load all possible predicates
* or only those that are active (status > 0).
* @return
* An array of predicates.
*/
function ca_load_trigger_predicates($trigger, $all = FALSE) {
// Load all the module defined predicates.
$predicates = module_invoke_all('ca_predicate');
drupal_alter('ca_predicate', $predicates);
// Loop through the module defined predicates to prepare the data - unsets
// inactive predicates if $all == FALSE and adds a default weight if need be.
foreach ($predicates as $key => $value) {
// Unset the predicate if it doesn't use the specified trigger.
if ($value['#trigger'] != $trigger) {
unset($predicates[$key]);
continue;
}
if (!$all && $value['#status'] <= 0) {
unset($predicates[$key]);
}
elseif (!isset($value['#weight'])) {
$predicates[$key]['#weight'] = 0;
}
}
// Load and loop through the predicates from the database for this trigger.
$result = db_query("SELECT * FROM {ca_predicates} WHERE ca_trigger = '%s'", $trigger);
while ($data = db_fetch_array($result)) {
// Module defined predicates have string IDs. When a user modifies one of
// these, we unset the module defined predicate and reconsider adding it in.
if (!is_numeric($data['pid'])) {
unset($predicates[$data['pid']]);
}
// Add predicates from the database to our return array if $all == TRUE or
// if the predicate is active.
if ($all || $data['status'] > 0) {
$predicate = ca_prepare_db_predicate($data);
// Set the actions' weight if necessary and sort actions by their weight.
for ($i = 0; $i < count($predicate['#actions']); $i++) {
if (!isset($predicate['#actions'][$i]['#weight'])) {
$predicate['#actions'][$i]['#weight'] = 0;
}
}
usort($predicate['#actions'], 'ca_weight_sort');
$predicates[$data['pid']] = $predicate;
}
}
uasort($predicates, 'ca_weight_sort');
return $predicates;
}
/**
* Prepare predicate data from the database into a full predicate array.
*
* @param $data
* An array of data representing a row in the predicates table.
* @return
* A predicate array.
*/
function ca_prepare_db_predicate($data) {
$predicate = array();
foreach ($data as $key => $value) {
switch ($key) {
// Condition and action data needs to be unserialized.
case 'conditions':
case 'actions':
$predicate['#' . $key] = unserialize($value);
break;
case 'ca_trigger':
$predicate['#trigger'] = $value;
break;
default:
$predicate['#' . $key] = $value;
break;
}
}
return $predicate;
}
/**
* Evaluate a predicate's conditions.
*
* @param $predicate
* A fully loaded predicate array.
* @param $arguments
* The array of parsed arguments for the trigger.
* @return
* TRUE or FALSE indicating the success or failure of the evaluation.
*/
function ca_evaluate_conditions($predicate, $arguments) {
// Automatically pass if there are no conditions.
if (!isset($predicate['#conditions']) || count($predicate['#conditions']) == 0) {
return TRUE;
}
// Load the data for the conditions as defined by modules.
$condition_data = module_invoke_all('ca_condition');
// Recurse through the predicate's conditions for evaluation.
$result = _ca_evaluate_conditions_tree($predicate['#conditions'], $arguments, $condition_data);
if (is_null($result)) {
$result = FALSE;
}
return $result;
}
/**
* Recursively evaluate conditions to accommodate nested logical groups.
*/
function _ca_evaluate_conditions_tree($condition, $arguments, $condition_data) {
if (isset($condition['#operator']) && is_array($condition['#conditions'])) {
// Default to TRUE for cases of empty conditions arrays.
$result = TRUE;
foreach ($condition['#conditions'] as $sub_condition) {
$result = _ca_evaluate_conditions_tree($sub_condition, $arguments, $condition_data);
// Invalid conditions return NULL. Skip it and go to the next one.
if (is_null($result)) {
continue;
}
// Save the processors! Apply Boolean shortcutting if we can.
if ($condition['#operator'] == 'OR' && $result) {
return TRUE;
}
elseif ($condition['#operator'] == 'AND' && !$result) {
return FALSE;
}
}
return $result;
}
else {
return _ca_evaluate_condition($condition, $arguments, $condition_data);
}
}
/**
* Evaluate a single condition.
*/
function _ca_evaluate_condition($condition, $arguments, $condition_data) {
$args = array();
// Make sure the condition tree is sane.
if (!is_array($condition_data[$condition['#name']])) {
return NULL;
}
// Get the callback function for the current condition.
$callback = $condition_data[$condition['#name']]['#callback'];
// Skip this condition if the function does not exist.
if (!function_exists($callback)) {
return NULL;
}
// Loop through the expected arguments for a condition.
// Cast to an array to accommodate conditions that need no arguments.
foreach ((array) $condition_data[$condition['#name']]['#arguments'] as $key => $value) {
// Using the argument map for the condition on this predicate, fetch the
// argument that was passed to the trigger that matches to the argument
// needed to evaluate this condition.
if (isset($condition['#argument_map'][$key])) {
if ($value['#entity'] == 'arguments') {
$args[] = $arguments;
}
else {
$args[] = $arguments[$condition['#argument_map'][$key]]['#data'];
}
}
else {
// Skip this condition of the predicate didn't map the arguments needed.
return NULL;
}
}
// Add the condition settings to the argument list.
$args[] = $condition['#settings'];
// Call the condition's function with the appropriate arguments.
$result = call_user_func_array($callback, $args);
// If the negate operator is TRUE, then switch the result!
if (isset($condition['#settings']['negate']) && $condition['#settings']['negate']) {
$result = !$result;
}
return $result;
}
/**
* Perform a predicate's actions in order, preserving changes to the arguments.
*
* @param $predicate
* A fully loaded predicate array.
* @param $arguments
* The array of parsed arguments for the trigger.
* @return
* An array of results, if any, that were returned by the actions.
*/
function ca_perform_actions($predicate, $arguments) {
// Exit now if we don't have any actions.
if (count($predicate['#actions']) == 0) {
return;
}
$results = array();
// Load the data for the actions as defined by modules.
$action_data = module_invoke_all('ca_action');
foreach ($predicate['#actions'] as $i => $action) {
$args = array();
// Get the callback function for the current action.
$callback = $action_data[$action['#name']]['#callback'];
// Do not perform the action if the function does not exist.
if (!function_exists($callback)) {
continue;
}
// Loop through the expected arguments for an action.
foreach ($action_data[$action['#name']]['#arguments'] as $key => $value) {
// Using the argument map for the action on this predicate, fetch the
// argument that was passed to the trigger that matches to the argument
// needed to perform this action.
if (isset($action['#argument_map'][$key])) {
// Adding the arguments as references so action functions can update the
// arguments here when they make changes to the argument data.
if ($value['#entity'] == 'arguments') {
$args[] =& $arguments;
}
else {
$args[] =& $arguments[$action['#argument_map'][$key]]['#data'];
}
}
else {
// Skip this action of the predicate didn't map the arguments needed.
continue 2;
}
}
// Add the condition settings to the argument list.
$args[] = isset($action['#settings']) && is_array($action['#settings']) ? $action['#settings'] : array();
// Call the action's function with the appropriate arguments.
$results[$i] = call_user_func_array($callback, $args);
}
return $results;
}
/**
* Load triggers defined in modules via hook_ca_trigger().
*
* @param $trigger
* Defaults to 'all'; may instead be the name of the trigger to load.
* @return
* An array of data for the specified trigger or an array of all the trigger
* data if 'all' was specified. Returns FALSE if a specified trigger is
* non-existent.
*/
function ca_load_trigger($trigger = 'all') {
static $triggers;
// Load the triggers defined in enabled modules to a cached variable.
if (empty($triggers)) {
$triggers = module_invoke_all('ca_trigger');
}
// Return the whole array if the trigger specified is 'all'.
if ($trigger === 'all') {
return $triggers;
}
// If the specified trigger is non-existent, return FALSE.
if (!isset($triggers[$trigger])) {
return FALSE;
}
return $triggers[$trigger];
}
/**
* Return a trigger's arguments formatted for select element options.
*
* @param $trigger
* The name of the trigger to load arguments for.
* @param $entity
* The name of the entity type we must restrict our returned arguments to.
* @return
* An array of arguments in FAPI options format.
*/
function ca_load_trigger_arguments($trigger, $entity) {
static $arguments = array();
// Load the arguments if we can't find a cached version.
if (!isset($arguments[$trigger][$entity])) {
$arguments[$trigger][$entity] = array();
// Handle the arguments entity specially, as it should never be specified
// in a trigger.
if ($entity == 'arguments') {
$arguments[$trigger][$entity]['arguments'] = t('Arguments');
}
else {
// Load the trigger data.
$trigger_data = ca_load_trigger($trigger);
// Add the trigger's arguments to the options array if the entity matches.
foreach ((array) $trigger_data['#arguments'] as $key => $value) {
if ($value['#entity'] == $entity) {
$arguments[$trigger][$entity][$key] = $value['#title'];
}
}
}
}
return $arguments[$trigger][$entity];
}
/**
* Load conditions defined in modules via hook_ca_condition().
*
* @param $condition
* Defaults to 'all'; may instead be the name of the condition to load.
* @return
* An array of data for the specified condition or an array of all the
* condition data if 'all' was specified. Returns FALSE if a specified
* condition is non-existent.
*/
function ca_load_condition($condition = 'all') {
static $conditions;
// Load the conditions defined in enabled modules to a cached variable.
if (empty($conditions)) {
$conditions = module_invoke_all('ca_condition');
}
// Return the whole array if the trigger specified is 'all'.
if ($condition === 'all') {
return $conditions;
}
// If the specified trigger is non-existent, return FALSE.
if (!isset($conditions[$condition])) {
return FALSE;
}
return $conditions[$condition];
}
/**
* Return an array of conditions available for the specified trigger.
*
* @param $trigger
* The name of a trigger to find conditions for; if left empty, the function
* returns conditions for the previously specified trigger.
* @return
* A nested array of names/titles for the conditions available for the
* trigger; in the format required by select elements in FAPI.
*/
function ca_load_trigger_conditions($trigger = '') {
static $options = array();
if (!empty($trigger)) {
// Load the specified trigger.
$trigger = ca_load_trigger($trigger);
$trigger_entities = array();
// Organize trigger arguments by entity.
foreach ($trigger['#arguments'] as $argument) {
$trigger_entities[$argument['#entity']] = $argument;
}
// Load and loop through all the conditions defined by modules.
$conditions = ca_load_condition();
foreach ($conditions as $name => $condition) {
// Check through each argument needed for the condition.
// Cast to an array to accommodate conditions that need no arguments.
foreach ((array) $condition['#arguments'] as $argument) {
$entity = $argument['#entity'];
// If the condition requires an entity the trigger doesn't provide,
// then skip to the next condition.
if ($entity != 'arguments' && !isset($trigger_entities[$entity])) {
continue 2;
}
}
// Getting this far means that all of the condition's arguments have
// the same entity types as the trigger's. Add it to the options,
// and group them by category for usability.
$options[$condition['#category']][$name] = $condition['#title'];
}
// Alphabetically sort the groups and their options.
foreach ($options as $group => $conditions) {
asort($conditions);
$options[$group] = $conditions;
}
ksort($options);
}
return $options;
}
/**
* Load actions defined in modules via hook_ca_action().
*
* @param $action
* Defaults to 'all'; may instead be the name of the action to load.
* @return
* An array of data for the specified action or an array of all the action
* data if 'all' was specified. Returns FALSE if a specified action is
* non-existent.
*/
function ca_load_action($action = 'all') {
static $actions;
// Load the actions defined in enabled modules to a cached variable.
if (empty($actions)) {
$actions = module_invoke_all('ca_action');
}
// Return the whole array if the trigger specified is 'all'.
if ($action === 'all') {
return $actions;
}
// If the specified trigger is non-existent, return FALSE.
if (!isset($actions[$action])) {
return FALSE;
}
return $actions[$action];
}
/**
* Return an array of actions available for the specified trigger.
*
* @param $trigger
* The name of a trigger to find actions for; if left empty, the function
* returns conditions for the previously specified trigger.
* @return
* A nested array of names/titles for the actions available for the trigger;
* in the format required by select elements in FAPI.
*/
function ca_load_trigger_actions($trigger = '') {
static $options = array();
if (!empty($trigger)) {
// Load the specified trigger.
$trigger = ca_load_trigger($trigger);
$trigger_entities = array();
// Organize trigger arguments by entity.
foreach ($trigger['#arguments'] as $argument) {
$trigger_entities[$argument['#entity']] = $argument;
}
// Load and loop through all the actions defined by modules.
$actions = ca_load_action();
foreach ($actions as $name => $action) {
// Check through each argument needed for the condition.
foreach ($action['#arguments'] as $argument) {
$entity = $argument['#entity'];
// If the action requires an entity the trigger doesn't provide,
// then skip to the next action.
if ($entity != 'arguments' && !isset($trigger_entities[$entity])) {
continue 2;
}
}
// Getting this far means that all of the condition's arguments have
// the same entity types as the trigger's. Add it to the options,
// and group them by category for usability.
$options[$action['#category']][$name] = $action['#title'];
}
// Alphabetically sort the groups and their options.
foreach ($options as $group => $actions) {
asort($actions);
$options[$group] = $actions;
}
ksort($options);
}
return $options;
}
/**
* Return a default conditions array for use on new predicates or in the UI.
*/
function ca_new_conditions() {
return array(
'#operator' => 'AND',
'#conditions' => array(
array(
'#operator' => 'AND',
'#conditions' => array(),
),
),
);
}
/**
* Add a new condition group to a predicate.
*
* @param $pid
* The ID of the predicate to add the condition group to.
* @return
* An array representing the full, updated predicate.
*/
function ca_add_condition_group($pid) {
// Load the predicate.
$predicate = ca_load_predicate($pid);
// Add the condition group to the conditions array in the appropriate place.
if (empty($predicate['#conditions'])) {
$predicate['#conditions'] = ca_new_conditions();
}
else {
$predicate['#conditions']['#conditions'][] = array(
'#operator' => 'AND',
'#conditions' => array(),
);
}
// Save the changes.
ca_save_predicate($predicate);
return $predicate;
}
/**
* Remove a condition group from a predicate.
*
* @param $pid
* The ID of the predicate to remove the condition group from.
* @param $group_key
* The key of the condition group to remove.
* @return
* An array representing the full, updated predicate.
*/
function ca_remove_condition_group($pid, $group_key) {
// Load the predicate as it is now.
$predicate = ca_load_predicate($pid);
// Update, save, and return the predicate.
unset($predicate['#conditions']['#conditions'][$group_key]);
ca_save_predicate($predicate);
return $predicate;
}
/**
* Add a new condition to a predicate.
*
* @param $pid
* The ID of the predicate to add the condition to.
* @param $name
* The name of the condition to add.
* @param $group_key
* The key of the condition group we're adding the condition to.
* @param $mark_expanded
* If set to TRUE marks the condition so that it will be expanded next time it
* displays in the UI so the user can adjust its settings.
* @return
* An array representing the full, updated predicate.
*/
function ca_add_condition($pid, $name, $group_key, $mark_expanded = TRUE) {
// Load the predicate.
$predicate = ca_load_predicate($pid);
// Load the condition we want to add to the predicate.
$data = ca_load_condition($name);
// If the condition exists...
if ($data) {
// Build the condition array.
$condition = array(
'#name' => $name,
'#title' => $data['#title'],
'#argument_map' => array(),
'#settings' => array(),
);
// Mark it for expansion in the form if specified.
if ($mark_expanded) {
$condition['#expanded'] = TRUE;
}
// Add the condition to the predicate.
$predicate['#conditions']['#conditions'][$group_key]['#conditions'][] = $condition;
}
ca_save_predicate($predicate);
return $predicate;
}
/**
* Remove a condition from a predicate.
*
* @param $pid
* The ID of the predicate to remove the condition group from.
* @param $group_key
* The key of the condition group the condition is in.
* @param $cond_key
* The key of the condition to remove.
* @return
* An array representing the full, updated predicate.
*/
function ca_remove_condition($pid, $group_key, $cond_key) {
// Load the predicate as it is now.
$predicate = ca_load_predicate($pid);
// Update, save, and return the predicate.
unset($predicate['#conditions']['#conditions'][$group_key]['#conditions'][$cond_key]);
ca_save_predicate($predicate);
return $predicate;
}
/**
* Add a new action to a predicate.
*
* @param $pid
* The ID of the predicate to add the action to.
* @param $name
* The name of the action to add.
* @return
* An array representing the full, updated predicate.
*/
function ca_add_action($pid, $name) {
// Load the predicate as it is now.
$predicate = ca_load_predicate($pid);
// Load the action.
$action = ca_load_action($name);
// Abort if it did not exist.
if (empty($action)) {
return $predicate;
}
// Add the name to the action array so it's saved in the predicate.
$action['#name'] = $name;
// Add the action to the predicate's actions array.
$predicate['#actions'][] = $action;
// Save and return the updated predicate.
ca_save_predicate($predicate);
return $predicate;
}
/**
* Remove an action from a predicate.
*
* @param $pid
* The ID of the predicate to remove the action from.
* @param $index
* The index of the action to remove.
* @return
* An array representing the full, updated predicate.
*/
function ca_remove_action($pid, $index) {
$actions = array();
// Load the predicate as it is now.
$predicate = ca_load_predicate($pid);
// Build a new actions array, leaving out the one marked for removal.
foreach ($predicate['#actions'] as $key => $action) {
if ($key != $index) {
$actions[] = $action;
}
}
// Update, save, and return the predicate.
$predicate['#actions'] = $actions;
ca_save_predicate($predicate);
return $predicate;
}
/**
* Load a predicate by its ID.
*
* @param $pid
* The ID of the predicate to load.
* @return
* A fully loaded predicate array.
*/
function ca_load_predicate($pid) {
$predicate = array();
// First attempt to load the predicate from the database.
$result = db_query("SELECT * FROM {ca_predicates} WHERE pid = '%s'", $pid);
if ($predicate = db_fetch_array($result)) {
$predicate = ca_prepare_db_predicate($predicate);
}
else {
// Otherwise look for it in the module defined predicates.
$predicates = module_invoke_all('ca_predicate');
drupal_alter('ca_predicate', $predicates);
if (!empty($predicates[$pid])) {
$predicate = $predicates[$pid];
}
}
// Add the pid to the predicate so it can be resaved later.
if (!empty($predicate)) {
$predicate['#pid'] = $pid;
}
return $predicate;
}
/**
* Save a predicate array to the database.
*
* @param $predicate
* A fully loaded predicate array.
*/
function ca_save_predicate($predicate) {
// Check to see if the predicate has been previously saved to the database.
$result = db_result(db_query("SELECT COUNT(*) FROM {ca_predicates} WHERE pid = '%s'", $predicate['#pid']));
if (!$result) {
// If not, then insert it.
db_query("INSERT INTO {ca_predicates} (pid, title, description, class, status, weight, uid, ca_trigger, conditions, actions, created, modified) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s', '%s', %d, %d)", $predicate['#pid'], $predicate['#title'], $predicate['#description'], $predicate['#class'], $predicate['#status'], $predicate['#weight'], $predicate['#uid'], $predicate['#trigger'], serialize($predicate['#conditions']), serialize($predicate['#actions']), time(), time());
}
else {
// Otherwise, update it.
db_query("UPDATE {ca_predicates} SET title = '%s', description = '%s', class = '%s', status = %d, weight = %d, uid = %d, ca_trigger = '%s', conditions = '%s', actions = '%s', modified = %d WHERE pid = '%s'", $predicate['#title'], $predicate['#description'], $predicate['#class'], $predicate['#status'], $predicate['#weight'], $predicate['#uid'], $predicate['#trigger'], serialize($predicate['#conditions']), serialize($predicate['#actions']), time(), $predicate['#pid']);
}
}
/**
* Delete a predicate from the database.
*
* @param $pid
* The ID of the predicate to delete.
*/
function ca_delete_predicate($pid) {
db_query("DELETE FROM {ca_predicates} WHERE pid = '%s'", $pid);
}
/**
* Compare two conditional action arrays to sort them by #weight.
*/
function ca_weight_sort($a, $b) {
if ($a['#weight'] == $b['#weight']) {
return 0;
}
return $a['#weight'] > $b['#weight'] ? 1 : -1;
}
/**
* Configure the #parents and #id field of any child filter_forms.
*
* Unfortunately, FAPI doesn't give us any way to know we have a filter
* element, so we require all filters to have an #is_format element.
*/
function filter_configure_form(&$form) {
// Grab all the filters, and search for the formats.
$formats = filter_formats();
_filter_configure_form_recur($form, $formats, array());
}
/**
* Recursive filter configuration.
*/
function _filter_configure_form_recur(&$form, &$formats, $parents) {
// Look for our special element, then search the children.
if (isset($form['#is_format']) ? $form['#is_format'] : FALSE) {
foreach (element_children($form) as $key) {
// Found a filter.
if (array_key_exists($key, $formats)) {
// Configure the parents and ID so FAPI is happy.
$form[$key] = array(
'#parents' => $parents,
'#id' => form_clean_id('edit-' . implode('-', array_merge($parents, array(
$key,
)))),
) + $form[$key];
}
}
}
else {
// Keep looking.
foreach (element_children($form) as $key) {
_filter_configure_form_recur($form[$key], $formats, array_merge($parents, array(
$key,
)));
}
}
}
Functions
Name | Description |
---|---|
ca_add_action | Add a new action to a predicate. |
ca_add_condition | Add a new condition to a predicate. |
ca_add_condition_group | Add a new condition group to a predicate. |
ca_convert_configurations_access | Determine access to the configuration conversion form. |
ca_delete_predicate | Delete a predicate from the database. |
ca_evaluate_conditions | Evaluate a predicate's conditions. |
ca_load_action | Load actions defined in modules via hook_ca_action(). |
ca_load_condition | Load conditions defined in modules via hook_ca_condition(). |
ca_load_predicate | Load a predicate by its ID. |
ca_load_trigger | Load triggers defined in modules via hook_ca_trigger(). |
ca_load_trigger_actions | Return an array of actions available for the specified trigger. |
ca_load_trigger_arguments | Return a trigger's arguments formatted for select element options. |
ca_load_trigger_conditions | Return an array of conditions available for the specified trigger. |
ca_load_trigger_predicates | Load predicates based on the specified parameters. |
ca_menu | Implements hook_menu(). |
ca_new_conditions | Return a default conditions array for use on new predicates or in the UI. |
ca_parse_trigger_args | Parse the argument array into a CA friendly array for the trigger. |
ca_perform_actions | Perform a predicate's actions in order, preserving changes to the arguments. |
ca_perm | Implements hook_perm(). |
ca_prepare_db_predicate | Prepare predicate data from the database into a full predicate array. |
ca_pull_trigger | Pull a trigger and evaluate any predicates associated with that trigger. |
ca_remove_action | Remove an action from a predicate. |
ca_remove_condition | Remove a condition from a predicate. |
ca_remove_condition_group | Remove a condition group from a predicate. |
ca_save_predicate | Save a predicate array to the database. |
ca_weight_sort | Compare two conditional action arrays to sort them by #weight. |
filter_configure_form | Configure the #parents and #id field of any child filter_forms. |
_ca_evaluate_condition | Evaluate a single condition. |
_ca_evaluate_conditions_tree | Recursively evaluate conditions to accommodate nested logical groups. |
_filter_configure_form_recur | Recursive filter configuration. |
Constants
Name | Description |
---|---|
CA_UI_PATH | The Drupal menu path to Conditional Actions pages. |