$value) {
$temp[$key]['#pid'] = $key;
if (!isset($value['#weight'])) {
$temp[$key]['#weight'] = 0;
}
}
// Load and loop through all the database stored predicates.
$result = db_query("SELECT * FROM {ca_predicates}");
while ($predicate = db_fetch_array($result)) {
// Prepare the database data into a predicate.
$predicate = ca_prepare_db_predicate($predicate);
// Overrides the module defined predicate if it's been modified by a user.
$temp[$predicate['#pid']] = $predicate;
}
usort($temp, 'ca_weight_sort');
// Copy the temporary array of predicates into a keyed array.
$predicates = array();
foreach ($temp as $predicate) {
$predicates[$predicate['#pid']] = $predicate;
}
// Load up the trigger data so we can display them by title.
$triggers = module_invoke_all('ca_trigger');
// Build the header for the predicate tables based on the grouping type.
if ($groupby == 'trigger') {
$header = array(
array('data' => t('Title'), 'class' => 'col-title'),
t('Class'),
t('Status'),
t('Weight'),
t('Operations'),
);
$table_class = 'ca-predicate-trigger';
$table_label = ''. t('Trigger') .': ';
}
elseif ($groupby == 'class') {
$header = array(
array('data' => t('Title'), 'class' => 'col-title'),
t('Trigger'),
t('Status'),
t('Weight'),
t('Operations'),
);
$table_class = 'ca-predicate-class';
$table_label = ''. t('Class') .': ';
}
$rows = array();
foreach ($predicates as $key => $value) {
// Build the basic operation links for each predicate.
$ops = array(
l(t('edit'), CA_UI_PATH .'/'. $key .'/edit'),
);
// Add the reset link if a module defined predicate has been modified.
if (!is_numeric($key) && isset($value['#modified'])) {
$ops[] = l(t('reset'), CA_UI_PATH .'/'. $key .'/reset');
}
// Add a delete link if displaying a custom predicate.
if (is_numeric($key)) {
$ops[] = l(t('delete'), CA_UI_PATH .'/'. $key .'/delete');
}
// Add the predicate's row to the table based on the grouping type.
if ($groupby == 'trigger') {
$tables[$triggers[$value['#trigger']]['#title']]['rows'][] = array(
check_plain($value['#title']),
strpos($value['#class'], 'custom') === 0 ? check_plain(substr($value['#class'], 7)) : $value['#class'],
$value['#status'] == 0 ? t('Disabled') : t('Enabled'),
array('data' => $value['#weight'], 'class' => 'ca-predicate-table-weight'),
array('data' => implode(' ', $ops), 'class' => 'ca-predicate-table-ops'),
);
}
elseif ($groupby == 'class') {
$class = strpos($value['#class'], 'custom') === 0 ? check_plain(substr($value['#class'], 7)) : $value['#class'];
$tables[$class]['rows'][] = array(
check_plain($value['#title']),
check_plain($triggers[$value['#trigger']]['#title']),
$value['#status'] == 0 ? t('Disabled') : t('Enabled'),
array('data' => $value['#weight'], 'class' => 'ca-predicate-table-weight'),
array('data' => implode(' ', $ops), 'class' => 'ca-predicate-table-ops'),
);
}
}
// Put the tables in alphabetical order.
ksort($tables);
// Add the tables for each trigger to the output.
foreach ($tables as $key => $value) {
// Accommodate empty class names.
if (empty($key)) {
$key = t('- None -');
}
$output .= theme('table', $header, $value['rows'], array('class' => $table_class), $table_label . check_plain($key));
}
$output .= l(t('Add a predicate'), CA_UI_PATH .'/add');
return $output;
}
/**
* Landing page for converting Workflow-ng configurations.
*
* From this page, the user can begin the batch processing of any Workflow-ng
* configurations in the site's database into Conditional Actions predicates.
*/
function ca_conversion_page() {
$output = t('TODO: Fill this page out. :)');
// TODO: Figure out if the conversion needs to be done
// Generally, it should only happen when someone upgrades from Drupal 5 to
// Drupal 6.
// TODO: Do batch processing because I can imagine some people having a lot
// of Ubercart-related Workflow-ng configurations.
return $output;
}
/**
* Batch API callback (that's the plan, anyway).
*
*
*/
function _ca_convert_configurations() {
global $user;
if (db_table_exists('workflow_ng_cfgs')) {
$result = db_query("SELECT name, data FROM {workflow_ng_cfgs} WHERE altered = 1");
$predicates = array();
while ($configuration_row = db_fetch_object($result)) {
$predicate = array('#pid' => $configuration_row->name);
$conditions = array();
$actions = array();
if ($configuration = unserialize($configuration_row->data)) {
$predicate['#class'] = $configuration['#module'];
$predicate['#title'] = $configuration['#label'];
switch ($configuration['#event']) {
case 'order_status_update':
$trigger = 'uc_order_status_update';
break;
case 'payment_entered':
$trigger = 'uc_payment_entered';
break;
case 'checkout_complete':
$trigger = 'uc_checkout_complete';
break;
default:
$trigger = $configuration['#event'];
break;
}
if (strpos($trigger, 'calculate_tax_') === 0) {
$tax_id = substr($trigger, 14);
$trigger = 'calculate_taxes';
}
$predicate['#trigger'] = $trigger;
$predicate['#weight'] = $configuration['#weight'];
$predicate['#status'] = $configuration['#active'];
for ($i = 0; isset($configuration[$i]); $i++) {
if ($configuration[$i]['#type'] == 'action') {
$action = _ca_convert_actions($configuration[$i], $tax_id);
if ($action) {
$actions[] = $action;
}
}
else {
$condition = _ca_convert_conditions($configuration[$i]);
if ($condition) {
$conditions[] = $condition;
}
}
}
if ($conditions) {
$predicate['#conditions'] = array(
'#operator' => 'AND',
'#conditions' => $conditions,
);
}
$predicate['#uid'] = $user->uid;
ca_save_predicate($predicate);
}
}
}
}
/**
* Helper function for converting Ubercart's Workflow-ng conditions.
*/
function _ca_convert_conditions($condition_tree) {
$ca_condition = array();
if ($condition_tree['#type'] == 'AND' || $condition_tree['#type'] == 'OR') {
$ca_condition['#operator'] = $condition_tree['#type'];
$ca_condition['#conditions'] = array();
for ($i = 0; isset($condition_tree[$i]); $i++) {
$condition = _ca_convert_conditions($condition_tree[$i]);
if ($condition) {
$ca_condition['#conditions'][] = $condition;
}
}
}
else if ($condition_tree['#type'] == 'condition') {
switch ($condition_tree['#name']) {
case 'uc_payment_condition_balance':
$ca_condition['#name'] = 'uc_payment_condition_order_balance';
break;
default:
$ca_condition['#name'] = $condition_tree['#name'];
break;
}
$ca_condition['#title'] = $condition_tree['#label'];
$ca_condition['#argument_map'] = $condition_tree['#argument map'];
$ca_condition['#settings'] = $condition_tree['#settings'];
if (isset($condition_tree['#negate'])) {
$ca_condition['#settings']['negate'] = $condition_tree['#negate'];
}
}
return $ca_condition;
}
/**
* Helper function for converting Ubercart's Workflow-ng actions.
*/
function _ca_convert_actions($wf_action, $tax_id = NULL) {
$action = $wf_action;
switch ($action['#name']) {
case 'uc_order_action_update_status':
$action['#name'] = 'uc_order_update_status';
break;
case 'uc_taxes_action_apply_tax':
$action['#name'] = 'uc_taxes_action_apply_tax_'. $tax_id;
break;
}
if (isset($action['#label'])) {
$action['#title'] = $action['#label'];
unset($action['#label']);
}
else {
$action['#title'] = $action['#name'];
}
}
// Form to allow the creation and editing of conditional action predicates.
function ca_predicate_meta_form($form_state, $pid) {
// Load the predicate if an ID is passed in.
if (!empty($pid) && $pid !== 0) {
$predicate = ca_load_predicate($pid);
// Fail out if we didn't find a predicate for that ID.
if (empty($predicate)) {
drupal_set_message(t('That predicate does not exist.'), 'error');
drupal_goto(CA_UI_PATH);
}
drupal_set_title($predicate['#title']);
}
$form['predicate_pid'] = array(
'#type' => 'value',
'#value' => $pid,
);
$form['predicate_title'] = array(
'#type' => 'textfield',
'#title' => t('Title'),
'#description' => t('Enter a title used for display on the overview tables.'),
'#default_value' => $pid ? $predicate['#title'] : '',
'#required' => TRUE,
);
// Create an array of triggers for the select box.
$triggers = module_invoke_all('ca_trigger');
foreach ($triggers as $key => $value) {
$options[$value['#category']][$key] = $value['#title'];
}
$form['predicate_trigger'] = array(
'#type' => 'select',
'#title' => t('Trigger'),
'#description' => t('Select the trigger for this predicate.
Cannot be modified if the predicate has conditions or actions.'),
'#options' => $options,
'#default_value' => $pid ? $predicate['#trigger'] : '',
'#disabled' => empty($predicate['#conditions']) && empty($predicate['#actions']) ? FALSE : TRUE,
'#required' => TRUE,
);
$form['predicate_description'] = array(
'#type' => 'textarea',
'#title' => t('Description'),
'#description' => t('Enter a description that summarizes the use and intent of the predicate.'),
'#default_value' => $pid ? $predicate['#description'] : '',
);
// Accommodate the mandatory custom prefix for predicate classes.
$class = $predicate['#class'];
if (strpos($class, 'custom') === 0) {
$class = ltrim(substr($class, 6), ':');
}
if (is_numeric($pid)) {
$form['predicate_class'] = array(
'#type' => 'textfield',
'#title' => t('Class'),
'#description' => t('Classes let you categorize your predicates based on the type of functionality they provide.'),
'#field_prefix' => 'custom:',
'#default_value' => $class,
);
}
else {
$form['predicate_class'] = array(
'#type' => 'value',
'#value' => $class,
);
}
$form['predicate_status'] = array(
'#type' => 'radios',
'#title' => t('Status'),
'#description' => t('Disabled predicates will not be processed when their trigger is pulled.'),
'#options' => array(
1 => t('Enabled'),
0 => t('Disabled'),
),
'#default_value' => $pid ? $predicate['#status'] : 1,
);
$form['predicate_weight'] = array(
'#type' => 'weight',
'#title' => t('Weight'),
'#description' => t('Predicates will be sorted by weight and processed sequentially.'),
'#default_value' => ($pid && isset($predicate['#weight'])) ? $predicate['#weight'] : 0,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save predicate'),
'#suffix' => l(t('Cancel'), CA_UI_PATH),
);
return $form;
}
function ca_predicate_meta_form_submit($form, &$form_state) {
$form_state['redirect'] = CA_UI_PATH;
$save = FALSE;
// Load the original predicate.
if ($form_state['values']['pid'] !== 0) {
$predicate = ca_load_predicate($form_state['values']['predicate_pid']);
$predicate['#pid'] = $form_state['values']['predicate_pid'];
}
// Setup a list of fields to check for and apply changes.
$fields = array('title', 'trigger', 'description', 'class', 'status', 'weight');
// Compare the values from the form submission with what is already set.
foreach ($fields as $field) {
if ($form_state['values']['predicate_'. $field] != $predicate['#'. $field]) {
$predicate['#'. $field] = $form_state['values']['predicate_'. $field];
$save = TRUE;
}
}
// Add empty conditions and actions arrays if this is a new predicate.
if (empty($predicate['#pid'])) {
$predicate['#pid'] = variable_get('ca_predicates_pid', 1);
variable_set('ca_predicates_pid', $predicate['#pid'] + 1);
$predicate['#conditions'] = array();
$predicate['#actions'] = array();
// For new predicates, redirect to the conditions tab.
$form_state['redirect'] = CA_UI_PATH .'/'. $predicate['#pid'] .'/edit/conditions';
}
// Check to see if any changes were made and save if necessary.
if ($save) {
ca_save_predicate($predicate);
}
drupal_set_message(t('Predicate meta data saved.'));
}
// Form to reset a modified module defined predicate to its original state.
function ca_predicate_delete_form($form_state, $pid) {
$predicate = ca_load_predicate($pid);
// Fail if we received an invalid predicate ID.
if (empty($predicate)) {
drupal_set_message(t('That predicate does not exist.'), 'error');
drupal_goto(CA_UI_PATH);
}
$form['predicate_pid'] = array(
'#type' => 'value',
'#value' => $pid,
);
$form['predicate_title'] = array(
'#type' => 'value',
'#value' => $predicate['#title'],
);
$description = '
'. check_plain($predicate['#title']) .'
'
. check_plain($predicate['#description']) .'
' . t('This action cannot be undone.') .'
'; return confirm_form($form, t('Are you sure you want to !op this predicate?', array('!op' => is_numeric($pid) ? t('delete') : t('reset'))), CA_UI_PATH, $description); } function ca_predicate_delete_form_submit($form, &$form_state) { ca_delete_predicate($form_state['values']['predicate_pid']); drupal_set_message(t('Predicate %title !op.', array('%title' => $form_state['values']['predicate_title'], '!op' => is_numeric($form_state['values']['predicate_pid']) ? t('deleted') : t('reset')))); $form_state['redirect'] = CA_UI_PATH; } /** * Builds a form for adding and editing actions on a predicate. * * @param $form_state * Used by FAPI; the current state of the form as it processes. * @param $pid * The ID of the predicate whose actions are being modified. * @param $title * TRUE or FALSE to specify whether or not to set the predicate's title to be * the title of the page. * @return * The form array for the actions form. */ function ca_actions_form($form_state, $pid, $title = TRUE) { // Locate the specified predicate. $predicate = ca_load_predicate($pid); // Return an empty form if the predicate does not exist. if (empty($predicate)) { return array(); } // Include the JS for conditional actions forms. drupal_add_js(drupal_get_path('module', 'ca') .'/ca.js'); // Display the title if appropriate. if ($title) { drupal_set_title($predicate['#title']); } // Load up any actions that could possibly be on this predicate. $action_data = ca_load_action(); $form['pid'] = array( '#type' => 'value', '#value' => $pid, ); $form['actions'] = array( '#type' => 'fieldset', '#title' => t('Actions'), '#description' => t('These actions will be performed in order when this predicate passes the conditions evaluation.'), '#tree' => TRUE, ); // Loop through the actions and add them to the form if valid. $i = 0; foreach ($predicate['#actions'] as $key => $action) { // Add it to the form if the action's callback exists. $callback = $action_data[$action['#name']]['#callback']; if (function_exists($callback)) { $form['actions'][$i] = array( '#type' => 'fieldset', '#title' => t('Action: @title', array('@title' => $action_data[$action['#name']]['#title'])), '#description' => $action_data[$action['#name']]['#description'], '#collapsible' => TRUE, '#collapsed' => isset($_SESSION['ca_action_focus']) && $i == $_SESSION['ca_action_focus'] ? FALSE : TRUE, ); $form['actions'][$i]['name'] = array( '#type' => 'value', '#value' => $action['#name'], ); $form['actions'][$i]['title'] = array( '#type' => 'textfield', '#title' => t('Title'), '#default_value' => $action['#title'], ); $form['actions'][$i]['argument_map'] = array( '#type' => 'fieldset', '#title' => t('Arguments'), '#description' => t('Some triggers pass in multiple options for arguments related to a particular action, so you must specify which options to use in the fields below.'), '#collapsible' => TRUE, ); // Setup a variable to decide if we can collapse the arguments fieldset. $collapsed = TRUE; foreach ($action_data[$action['#name']]['#arguments'] as $key => $value) { // Load the available arguments for each entity as received by the // trigger when it was pulled. $options = ca_load_trigger_arguments($predicate['#trigger'], $value['#entity']); // If we have more than one option for any argument, do not collapse. if (count($options) > 1) { $collapsed = FALSE; } $form['actions'][$i]['argument_map'][$key] = array( '#type' => 'select', '#title' => check_plain($value['#title']), '#options' => $options, '#default_value' => $action['#argument_map'][$key], ); } $form['actions'][$i]['argument_map']['#collapsed'] = $collapsed; // Add the action's form elements if any exist. $callback .= '_form'; if (function_exists($callback)) { $form['actions'][$i]['settings'] = $callback(array(), $action['#settings']); } $form['actions'][$i]['remove'] = array( '#type' => 'submit', '#value' => t('Remove this action'), '#name' => 'ca_remove_action_'. $i, '#submit' => array('ca_actions_form_remove_action_submit'), '#attributes' => array('class' => 'ca-remove-confirm'), ); $i++; } } // Unset the session variable used to focus on the new action. unset($_SESSION['ca_action_focus']); $form['actions']['add_action'] = array( '#type' => 'select', '#title' => t('Available actions'), '#options' => ca_load_trigger_actions($predicate['#trigger']), ); $form['actions']['add'] = array( '#type' => 'submit', '#value' => t('Add action'), '#submit' => array('ca_actions_form_add_action_submit'), ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Save changes'), '#submit' => array('ca_actions_form_save_changes_submit'), ); return $form; } // Remove action submit handler. function ca_actions_form_remove_action_submit($form, &$form_state) { // Save the existing actions to preserve any changes. ca_actions_form_update_actions($form_state['values']['pid'], $form_state['values']['actions']); // Remove the appropriate action from the predicate and save it. ca_remove_action($form_state['values']['pid'], $form_state['clicked_button']['#parents'][1]); drupal_set_message(t('Action removed.')); } // Add action submit handler. function ca_actions_form_add_action_submit($form, &$form_state) { // Save the existing actions to preserve any changes. $predicate = ca_actions_form_update_actions($form_state['values']['pid'], $form_state['values']['actions']); // Store the presumed key of the new action. $_SESSION['ca_action_focus'] = count($predicate['#actions']); // Add the specified action to the predicate. ca_add_action($form_state['values']['pid'], $form_state['values']['actions']['add_action']); drupal_set_message(t('Action added.')); } // Save changes submit handler for the actions form. function ca_actions_form_save_changes_submit($form, &$form_state) { // Save the existing actions to preserve any changes. ca_actions_form_update_actions($form_state['values']['pid'], $form_state['values']['actions']); drupal_set_message(t('Actions saved.')); } /** * Updates a predicate's actions based on the values from an actions form. * * @param $pid * The ID of the predicate whose actions should be updated. * @param $data * The actions values from the form state that should be used to update the * predicate; normally $form_state['values']['actions']. * @return * An array representing the full, updated predicate. */ function ca_actions_form_update_actions($pid, $data) { $actions = array(); // Unset top level components we don't want to get in the way. unset($data['add_action'], $data['add']); // Loop through the actions from the form and add them to our temporary array. foreach ((array) $data as $key => $value) { $actions[] = array( '#name' => $value['name'], '#title' => $value['title'], '#argument_map' => $value['argument_map'], '#settings' => empty($value['settings']) ? array() : $value['settings'], ); } // Load the predicate as it is now. $predicate = ca_load_predicate($pid); // Update the actions and save the result. $predicate['#actions'] = $actions; ca_save_predicate($predicate); return $predicate; } // Builds a form for adding and editing conditions on a predicate. function ca_conditions_form($form_state, $pid, $title = TRUE) { // Locate the specified predicate. $predicate = ca_load_predicate($pid); // Return an empty form if the predicate does not exist. if (empty($predicate)) { return array(); } // Include the JS for conditional actions forms. drupal_add_js(drupal_get_path('module', 'ca') .'/ca.js'); // Display the title if appropriate. if ($title) { drupal_set_title($predicate['#title']); } // Initialize the conditions available for this predicate. ca_load_trigger_conditions($predicate['#trigger']); // Add the predicate ID to the form array. $form['pid'] = array( '#type' => 'value', '#value' => $pid, ); // If the predicate conditions array isn't already a container of containers, // make it so. i.e. group => array('group' => array('cond', 'cond')) if (empty($predicate['#conditions'])) { $predicate['#conditions'] = ca_new_conditions(); } else { $key = array_shift(array_keys($predicate['#conditions']['#conditions'])); if (empty($predicate['#conditions']['#conditions'][$key]['#operator'])) { $predicate['#conditions'] = array( '#operator' => 'AND', '#conditions' => array( $predicate['#conditions'], ), ); } } // Recurse through the predicate's conditions to build the form. $form['conditions'] = _ca_conditions_form_tree($predicate['#conditions'], $predicate['#trigger']); $form['conditions'] = $form['conditions'][0]; // Always remove the top level condition group controls. unset($form['conditions']['condition']); unset($form['conditions']['add_condition']); unset($form['conditions']['remove_condition_group']); // If there are more than one top level condition groups... if (count($form['conditions']['conditions']) > 1) { // Update the top level fieldset. $form['conditions']['#title'] = t('Condition groups'); $form['conditions']['#collapsible'] = FALSE; // Adjust the titles of the operator options to be more explicit. $form['conditions']['operator']['#options'] = array( 'AND' => t('AND. If all of these condition groups are TRUE.'), 'OR' => t('OR. If any of these condition groups are TRUE.'), ); } else { // Otherwise remove the top level fieldset and operator. unset($form['conditions']['#type']); unset($form['conditions']['operator']); // Adjust the second level conditions group to not collapse. $form['conditions']['conditions'][0]['#collapsible'] = FALSE; } // Set the conditions array to a tree so the submitted form values mirror the // structure of a predicate's #conditions array. $form['conditions']['#tree'] = TRUE; $form['add_condition_group'] = array( '#type' => 'submit', '#value' => t('Add condition group'), '#submit' => array('ca_conditions_form_add_condition_group_submit'), ); $form['save'] = array( '#type' => 'submit', '#value' => t('Save changes'), '#submit' => array('ca_conditions_form_save_changes_submit'), ); return $form; } // Recursively adds logical groups to the conditions form as fieldsets. function _ca_conditions_form_tree($condition, $trigger) { // We need an index so condition group fieldsets have unique keys. static $index = 0; $form = array(); // If we're dealing with a conditions group and not a single condition. if (isset($condition['#operator']) && is_array($condition['#conditions'])) { $level = $index; $form[$level] = array( '#type' => 'fieldset', '#title' => t('Conditions group'), '#collapsible' => TRUE, ); // Add an operator radio select for the group. $form[$level]['operator'] = array( '#type' => 'radios', '#title' => t('Operator'), '#options' => array( 'AND' => t('AND. If all of these conditions are TRUE.'), 'OR' => t('OR. If any of these conditions are TRUE.'), ), '#default_value' => $condition['#operator'], ); $form[$level]['conditions'] = array(); // For each condition in #conditions, add a condition fieldset to the form. foreach ($condition['#conditions'] as $sub_condition) { $result = _ca_conditions_form_tree($sub_condition, $trigger); if (is_array($result)) { $form[$level]['conditions'] = array_merge($form[$level]['conditions'], $result); } } $form[$level]['condition'] = array( '#type' => 'select', '#title' => t('Available conditions'), '#options' => ca_load_trigger_conditions(), ); $form[$level]['add_condition'] = array( '#type' => 'submit', '#value' => t('Add condition'), '#submit' => array('ca_conditions_form_add_condition_submit'), '#name' => 'add_condition_'. $level, ); $form[$level]['remove_condition_group'] = array( '#type' => 'submit', '#value' => t('Remove group'), '#submit' => array('ca_conditions_form_remove_condition_group_submit'), '#attributes' => array('class' => 'ca-remove-confirm'), '#name' => 'remove_condition_group_'. $level, ); $index++; return $form; } elseif (!empty($condition)) { // Load the data for the conditions as defined by modules. $condition_data = ca_load_condition(); // Otherwise add a fieldset for the individual condition. $form[0] = array( '#type' => 'fieldset', '#title' => t('Condition: @title', array('@title' => $condition_data[$condition['#name']]['#title'])), '#description' => t('@description', array('@description' => $condition_data[$condition['#name']]['#description'])), '#collapsible' => TRUE, '#collapsed' => isset($condition['#expanded']) ? FALSE : TRUE, ); // Add form elements to the fieldset to adjust the condition's settings. $form[0] += _ca_conditions_form_condition($condition, $trigger); return $form; } } // Adds a single condition's fieldset to the conditions form. function _ca_conditions_form_condition($condition, $trigger) { static $identifier = 0; // Load the data for the conditions as defined by modules. $condition_data = ca_load_condition(); // Condition name is a hard reference to the condition and so not editable. $form['name'] = array( '#type' => 'value', '#value' => $condition['#name'], ); // The title for this particular instance of this condition. $form['title'] = array( '#type' => 'textfield', '#title' => t('Title'), '#default_value' => $condition['#title'], ); $form['argument_map'] = array( '#type' => 'fieldset', '#title' => t('Arguments'), '#description' => t('Some triggers pass in multiple options for arguments related to a particular condition, so you must specify which options to use in the fields below.'), '#collapsible' => TRUE, ); // Setup a variable to decide if we can collapse the arguments fieldset. $collapsed = TRUE; foreach ($condition_data[$condition['#name']]['#arguments'] as $key => $value) { // Load the available arguments for each entity as received by the // trigger when it was pulled. $options = ca_load_trigger_arguments($trigger, $value['#entity']); // If we have more than one option for any argument, do not collapse. if (count($options) > 1) { $collapsed = FALSE; } $form['argument_map'][$key] = array( '#type' => 'select', '#title' => check_plain($value['#title']), '#options' => $options, '#default_value' => $condition['#argument_map'][$key], ); } $form['argument_map']['#collapsed'] = $collapsed; // Whether or not to negate the result of this condition. $form['settings']['negate'] = array( '#type' => 'checkbox', '#title' => t('Negate this condition.'), '#description' => t('Return FALSE if the condition is TRUE and vice versa.'), '#default_value' => $condition['#settings']['negate'], ); // Get the callback for the condition we're displaying. $callback = $condition_data[$condition['#name']]['#callback'] .'_form'; if (function_exists($callback)) { // Add the condition's form elements to the fieldset. $form['settings'] += $callback(array(), $condition['#settings']); } $form['remove'] = array( '#type' => 'submit', '#value' => t('Remove this condition'), '#submit' => array('ca_conditions_form_remove_condition_submit'), '#attributes' => array('class' => 'ca-remove-confirm'), '#name' => 'remove_condition_group_'. $identifier++, ); return $form; } // Submit handler for button to add a condition group. function ca_conditions_form_add_condition_group_submit($form, &$form_state) { // Save the existing conditions to preserve any changes. ca_conditions_form_update_conditions($form_state['values']['pid'], $form_state['values']['conditions']); // Add the condition group to the predicate. ca_add_condition_group($form_state['values']['pid']); // Display a confirmation message. drupal_set_message(t('Condition group added.')); } function ca_conditions_form_remove_condition_group_submit($form, &$form_state) { $group_key = FALSE; // Loop through the array keys of the conditions group. foreach (array_keys($form['conditions']['conditions']) as $key => $value) { // If we find the key we're looking for... if (is_numeric($value) && $value == $form_state['clicked_button']['#array_parents'][2]) { // Store its position as the new group key once the conditions are saved. // This is necessary because the save function will truncate any holes so // the keys are in numerical order starting with 0. $group_key = $key; } } // Save the existing conditions to preserve any changes. ca_conditions_form_update_conditions($form_state['values']['pid'], $form_state['values']['conditions']); // Fail if we didn't find a new group key for some reason. if ($group_key === FALSE) { drupal_set_message(t('An error occurred when trying to add the condition. Please try again.'), 'error'); } else { // Remove the condition group from the predicate. ca_remove_condition_group($form_state['values']['pid'], $group_key); // Display a confirmation message. drupal_set_message(t('Condition group removed.')); } } // Submit handler for button to add a condition to a condition group. function ca_conditions_form_add_condition_submit($form, &$form_state) { $group_key = FALSE; // Loop through the array keys of the conditions group. foreach (array_keys($form['conditions']['conditions']) as $key => $value) { // If we find the key we're looking for... if (is_numeric($value) && $value == $form_state['clicked_button']['#array_parents'][2]) { // Store its position as the new group key once the conditions are saved. // This is necessary because the save function will truncate any holes so // the keys are in numerical order starting with 0. $group_key = $key; } } // Save the existing conditions to preserve any changes. ca_conditions_form_update_conditions($form_state['values']['pid'], $form_state['values']['conditions']); // Fail if we didn't find a new group key for some reason. if ($group_key === FALSE) { drupal_set_message(t('An error occurred when trying to add the condition. Please try again.'), 'error'); } else { // Otherwise add the condition to the specified group. $name = $form_state['values']['conditions']['conditions'][$group_key]['condition']; ca_add_condition($form_state['values']['pid'], $name, $group_key); $condition = ca_load_condition($name); drupal_set_message(t('%title condition added.', array('%title' => $condition['#title']))); } } // Submit handler for button to remove a condition from a condition group. function ca_conditions_form_remove_condition_submit($form, &$form_state) { $group_key = FALSE; $cond_key = FALSE; // Loop through the array keys of the conditions group. foreach (array_keys($form['conditions']['conditions']) as $key => $value) { // If we find the key we're looking for... if (is_numeric($value) && $value == $form_state['clicked_button']['#array_parents'][2]) { // Store its position as the new group key once the conditions are saved. // This is necessary because the save function will truncate any holes so // the keys are in numerical order starting with 0. $group_key = $key; } } // Loop through the array keys of the conditions in the group. foreach (array_keys($form['conditions']['conditions'][$form_state['clicked_button']['#array_parents'][2]]['conditions']) as $key => $value) { // If we find the key we're looking for... if (is_numeric($value) && $value == $form_state['clicked_button']['#array_parents'][4]) { // Store its position as the new condition key once the conditions are // saved. This is necessary because the save function will truncate any // holes so the keys are in numerical order starting with 0. $cond_key = $key; } } // Save the existing conditions to preserve any changes. ca_conditions_form_update_conditions($form_state['values']['pid'], $form_state['values']['conditions']); // Fail if we didn't find a new group key for some reason. if ($group_key === FALSE || $cond_key === FALSE) { drupal_set_message(t('An error occurred when trying to remove the condition. Please try again.'), 'error'); } else { // Otherwise remove the condition from the specified group. ca_remove_condition($form_state['values']['pid'], $group_key, $cond_key); drupal_set_message(t('Condition removed.')); } } // Save changes submit handler for the conditions form. function ca_conditions_form_save_changes_submit($form, &$form_state) { // Save the existing conditions to preserve any changes. ca_conditions_form_update_conditions($form_state['values']['pid'], $form_state['values']['conditions']); drupal_set_message(t('Conditions saved.')); } /** * Updates a predicate's conditions based on the values from a conditions form. * * @param $pid * The ID of the predicate whose conditions should be updated. * @param $data * The conditions values from the form state that should be used to update the * predicate; normally $form_state['values']['conditions']. * @return * An array representing the full, updated predicate. */ function ca_conditions_form_update_conditions($pid, $data) { // Build the new conditions array from scratch. $conditions = ca_new_conditions(); // Override the top level operator if need be. if (isset($data['operator'])) { $condtions['#operator'] = $data['operator']; } // Use a variable to track the group array key so we can "reset" the keys. $group = 0; // Loop through each second level condition group. foreach ($data['conditions'] as $key => $value) { // Save the operator setting. $conditions['#conditions'][$group]['#operator'] = $value['operator']; $conditions['#conditions'][$group]['#conditions'] = array(); // If conditions exist... if (is_array($value['conditions']) && count($value['conditions']) > 0) { // Use a variable to track the condition array key as for groups. $condition = 0; // Loop through the conditions in this group. foreach ($value['conditions'] as $cond_key => $cond_value) { // Save the condition's settings. $conditions['#conditions'][$group]['#conditions'][$condition] = array( '#name' => $cond_value['name'], '#title' => $cond_value['title'], '#argument_map' => $cond_value['argument_map'], '#settings' => $cond_value['settings'], ); $condition++; } } $group++; } // Load the predicate as it is now. $predicate = ca_load_predicate($pid); // Update the actions and save the result. $predicate['#conditions'] = $conditions; ca_save_predicate($predicate); return $predicate; }