You are here

rules.variables.inc in Rules 6

Provides functions and classes for handling variables

File

rules/rules.variables.inc
View source
<?php

/**
 * @file Provides functions and classes for handling variables
 */

/**
 * Processes the given variables and initializes the variables data of the state
 *
 * Note that the order of the arguments will be kept, as it might be important for passing
 * the variables to further variable loading handlers.
 *
 * @param $state The current evaluation state
 * @param $args The arguments passed with the event invocation
 */
function _rules_initialize_variables(&$state, $args) {
  $argument_names = array_keys($state['set_info']['arguments']);
  if (isset($args[0]) && count($args) == 1 && is_array($args[0]) && count($args[0]) > 0 && array_diff(array_keys($args[0]), $argument_names) === array()) {

    //the caller passed an array of arguments, so let's use that
    $data = $args[0];
  }
  else {
    $data = array();
    foreach ($argument_names as $index => $name) {
      $data[$name] =& $args[$index];
    }
  }
  $state['variables'] = array();
  foreach ($state['set_info']['arguments'] as $name => $info) {
    $variable = new rules_variable();
    $data += array(
      $name => NULL,
    );
    $variable
      ->construct($state, $name, $data[$name]);
  }
}

/**
 * Gets an array of variables specified in $names from the current evalutation state.
 *
 * @param $names
 *   An array of variable names to get.
 * @param $state
 *   The current evalutation state.
 * @param $force
 *   Use specified variable handlers to load variables, if necessary.
 *
 * @return
 *   The array of requested variables with the keys as given in $names. If it's not possible
 *   to get all variables, FALSE will be returned.
 */
function rules_get_variables($names, &$state, $force = TRUE) {
  $args = array();
  foreach ($names as $key => $name) {
    if (isset($state['variables'][$name])) {
      $args[$key] =& $state['variables'][$name]
        ->get($force);
    }
    else {
      rules_log(t('Warning: Unable to get variable "@name".', array(
        '@name' => $key,
      )));
      return FALSE;
    }
  }
  return $args;
}

/**
 * Gets the arguments as defined by the element.
 *
 * Returns the arguments, which may have been specified using the data type's input
 * form or by mapping to a state variable. Else a possible defined default value is
 * returned.
 *
 * @param $element
 *   The element to get arguments for.
 * @param $state
 *   The current evalutation state.
 *
 * @return
 *   An array of argument values. If it's not possible to get all arguments, FALSE
 *   will be returned.
 */
function rules_get_element_arguments($element, &$state) {
  $element_info = rules_get_element_info($element);
  $map = rules_get_mapped_argument_names($element);
  $args = array();
  foreach (array_keys($element_info['arguments']) as $key => $name) {
    if (($var = rules_get_element_variable($element, $name)) !== NULL) {
      $args[$key] = $var;
    }
    elseif (isset($map[$name]) && isset($state['variables'][$map[$name]])) {
      $args[$key] =& $state['variables'][$map[$name]]
        ->get();
    }
    elseif (array_key_exists('default value', $element_info['arguments'][$name])) {
      $args[$key] = $element_info['arguments'][$name]['default value'];
    }
    else {
      rules_log(t('Warning: Unable to get argument "@name".', array(
        '@name' => $key,
      )));
      return FALSE;
    }
  }
  return $args;
}

/**
 * Gets a variable for the given element which uses an own input form.
 *
 * @param $element
 *   The element to get the variable for.
 * @param $name
 *   The name of the variable to get.
 *
 * @return The variable, if available.
 */
function rules_get_element_variable($element, $name) {
  if (isset($element['#settings'][$name]) && isset($element['#info']['arguments'][$name])) {
    $object = rules_get_data_object($element['#info']['arguments'][$name]);
    return $object
      ->check_value($element['#info']['arguments'][$name], $element['#settings'][$name]);
  }
}

/**
 * Gets the argument map, mapping the specified arguments of an
 * element to the variable names of the currently evaluated set.
 *
 * @param $element The configured element, which variables to map
 * @param $state The current evaluation state
 *
 * @return The argument map.
 */
function rules_get_mapped_argument_names($element) {
  $element['#settings'] += array(
    '#argument map' => array(),
  );
  $map = $element['#settings']['#argument map'];
  if ($element_info = rules_get_element_info($element)) {

    // Initialize the map with default mappings (name => name).
    return $map + drupal_map_assoc(array_keys($element_info['arguments']));
  }
  return $map;
}

/**
 * Returns the execution arguments needed by the given element
 * It applies the input evaluators and the #argument map and gets
 * all needed arguments.
 *
 * @param $element The configured element, which is to be executed
 * @param $state The current evaluation state
 *
 * @return If not all execution arguments are available, it returns FALSE
 */
function rules_get_execution_arguments(&$element, &$state) {

  //apply the input evaluators
  $success = rules_apply_input_evaluators($element, $state);
  if ($success === FALSE) {
    rules_log(t('Element "@name" has not been executed. There are not all execution arguments needed by an input evaluator available.', array(
      '@name' => rules_get_element_label($element),
    )));
    return FALSE;
  }

  // First off get the arguments of the element as specified.
  $exec_args = rules_get_element_arguments($element, $state);
  if ($exec_args !== FALSE) {

    // Then we always append some other useful variables
    $settings = isset($element['#settings']) ? $element['#settings'] : array();
    $exec_args[] = $settings;
    $exec_args[] = $element;
    $exec_args[] =& $state;
    return $exec_args;
  }
  rules_log(t('Element "@name" has not been executed. There are not all execution arguments available.', array(
    '@name' => rules_get_element_label($element),
  )));
  return FALSE;
}

/**
 * Saves variables, which are returned by an action
 */
function rules_save_variables($element, $result, &$state) {
  $element_info = rules_get_element_info($element);
  $element['#settings'] += array(
    '#argument map' => array(),
  );
  $map = $element['#settings']['#argument map'];
  foreach (element_children($result) as $argument_name) {
    $map += array(
      $argument_name => $argument_name,
    );
    if (isset($state['variables'][$map[$argument_name]])) {

      //variable exists, so update it
      $variable =& $state['variables'][$map[$argument_name]];
      $variable
        ->update($result[$argument_name]);
      $variable
        ->save();
    }
    else {
      if (isset($element_info['new variables'][$map[$argument_name]])) {

        //it is a new variable, so add it
        $info = $element_info['new variables'][$map[$argument_name]];
        $variable = new rules_variable();
        $variable
          ->construct($state, $map[$argument_name], $result[$argument_name], $info);
        if (isset($info['save']) && $info['save']) {
          $variable
            ->save();
        }
        rules_log(t('Successfully added the new variable "@arg"', array(
          '@arg' => $info['label'],
        )));
      }
      else {
        rules_log(t('Unknown variable name "@var" return by action "@name".', array(
          '@var' => $argument_name,
          '@name' => $element['#name'],
        )), TRUE);
      }
    }
  }
}

/**
 * Packs the given variables ready for serialization. Data types which
 * are identifiable are replaced by their identifiers and loaded fresh from
 * the db when the variables are unpacked.
 *
 * @param $variables
 *   An array of variable information
 * @param $data
 *   An array of data for the given variables, in the same order as the information.
 *
 * @return
 *   The packed variables or FALSE if packing failed.
 */
function rules_pack_variables($variables, $data) {
  $packed = array(
    'variables' => $variables,
    'data' => array(),
  );
  foreach (array_values($variables) as $i => $info) {
    $type = rules_get_data_object($info, $data[$i]);
    if (isset($type) && $type
      ->is_identifiable()) {
      $id = $type
        ->get_identifier();
      if (!isset($id)) {
        return FALSE;
      }
      $packed['data'][$i] = $id;
    }
    else {
      $packed['data'][$i] = $data[$i];
    }
  }
  return $packed;
}

/**
 * Unacks the given packed variables.
 *
 * @param $packed
 *   Packed variables, as returned from rules_pack_variables().
 *
 * @return
 *   An array, containing the key 'variables' with info about the packed
 *   variables and the key 'data' with the actual data.
 *   If unpacking failed, FALSE.
 */
function rules_unpack_variables($packed) {
  foreach (array_values($packed['variables']) as $i => $info) {
    $type = rules_get_data_object($info);
    if (isset($type) && $type
      ->is_identifiable()) {
      $packed['data'][$i] = $type
        ->load($packed['data'][$i]);
      if ($packed['data'][$i] === FALSE) {
        return FALSE;
      }
    }
  }
  return $packed;
}

/**
 * Handles loading and saving a variable
 */
class rules_variable {
  var $name;
  var $info;
  var $data;
  var $_state;
  var $_changed = FALSE;

  /**
   * Constructor
   *
   * @param $state The current evaluation state
   * @param $name The name of the given variable
   * @param $data If available, the actual data, else NULL.
   * @param $info If given, the info for the variable. If not given it will be retrieved
   *   from the current's set info.
   *
   * @return If the variable name isn't valid, FALSE.
   */
  function construct(&$state, $name, &$data, $info = NULL) {
    $this->_state =& $state;
    $info = isset($info) ? $info : $state['set_info']['arguments'][$name];
    if (isset($info)) {
      $this->info = $info + array(
        'saved' => FALSE,
        'handler' => '',
      );
      $this->name = $name;
      $this
        ->_set_data($data);
      $state['variables'][$name] =& $this;
      return TRUE;
    }
    return FALSE;
  }

  /**
   * Gets the actual data. Be sure to keep the reference intact.
   *
   * @param $load Use the variable handler to load the variable, if necessary.
   *
   * @return The data or NULL.
   */
  function &get($load = TRUE) {
    $data = NULL;
    if ($load && !isset($this->data) && function_exists($this->info['handler'])) {

      // Call the handler to get the runtime data.
      $args = rules_get_variables(array_keys($this->_state['variables']), $this->_state, FALSE);
      $data = call_user_func_array($this->info['handler'], $args);
      $this
        ->_set_data($data);
      $this->info['handler'] = '';

      // Do not invoke it twice, if it fails
      rules_log(t('Loaded variable "@arg"', array(
        '@arg' => $this->info['label'],
      )));
    }
    else {
      if (isset($this->data)) {
        $data =& $this->data
          ->get();
      }
    }
    return $data;
  }
  function _set_data(&$data) {
    if (isset($data)) {
      $this->data = rules_get_data_object($this->info);

      // Set the data in the data object and make sure to keep a reference intact
      $this->data
        ->init($data);
    }
  }

  /**
   * Marks the variable to be saved.
   */
  function save() {
    $this->_changed = TRUE;
  }

  /**
   * Updates the actual variable
   */
  function update(&$data) {
    $this->data
      ->update($data);
  }

  /**
   * Saves the variable to db, if necessary
   */
  function save_changes() {

    //if the variable is not saved automatically, save it
    if ($this->_changed && !$this->info['saved'] && $this->data
      ->is_savable()) {
      rules_log(t('Saved variable @name of type @type.', array(
        '@name' => $this->info['label'],
        '@type' => $this->info['type'],
      )));
      $return = $this->data
        ->save();
      $this->_changed = FALSE;
      if (!$return) {
        rules_log(t('Failed saving variable @name of type @type.', array(
          '@name' => $this->info['label'],
          '@type' => $this->info['type'],
        )), TRUE);
      }
    }
  }

}

Functions

Namesort descending Description
rules_get_element_arguments Gets the arguments as defined by the element.
rules_get_element_variable Gets a variable for the given element which uses an own input form.
rules_get_execution_arguments Returns the execution arguments needed by the given element It applies the input evaluators and the #argument map and gets all needed arguments.
rules_get_mapped_argument_names Gets the argument map, mapping the specified arguments of an element to the variable names of the currently evaluated set.
rules_get_variables Gets an array of variables specified in $names from the current evalutation state.
rules_pack_variables Packs the given variables ready for serialization. Data types which are identifiable are replaced by their identifiers and loaded fresh from the db when the variables are unpacked.
rules_save_variables Saves variables, which are returned by an action
rules_unpack_variables Unacks the given packed variables.
_rules_initialize_variables Processes the given variables and initializes the variables data of the state

Classes

Namesort descending Description
rules_variable Handles loading and saving a variable