system.eval.inc

Contains rules integration for the system module needed during evaluation.

File

modules/system.eval.inc

View source
<?php


/**
 * @file
 * Contains rules integration for the system module needed during evaluation.
 *
 * @addtogroup rules
 *
 * @{
 */

/**
 * Action: Show a drupal message.
 */
function rules_action_drupal_message($message, $status, $repeat) {
    drupal_set_message(filter_xss_admin($message), $status, $repeat);
}

/**
 * Action: Write a watchdog db log message.
 */
function rules_action_drupal_watchdog($type, $message, $severity, $link_text, $link_path) {
    if (!empty($link_path)) {
        // Use $link_path for the text if no specific text was supplied.
        $link = l(!empty($link_text) ? $link_text : $link_path, url($link_path));
    }
    else {
        $link = NULL;
    }
    watchdog($type, $message, array(), $severity, $link);
}

/**
 * Action: Page redirect.
 *
 * @see rules_page_build()
 * @see rules_drupal_goto_alter()
 */
function rules_action_drupal_goto($url, $force = FALSE, $destination = FALSE) {
    // Don't let administrators lock them out from Rules administration pages.
    if (isset($_GET['q']) && strpos($_GET['q'], 'admin/config/workflow/rules') === 0) {
        rules_log('Skipped page redirect on Rules administration page.', array(), RulesLog::WARN);
        return;
    }
    // Do not redirect during batch processing.
    if (($batch = batch_get()) && isset($batch['current_set'])) {
        rules_log('Skipped page redirect during batch processing.');
        return;
    }
    // Keep the current destination parameter if there is one set.
    if ($destination) {
        $url .= strpos($url, '?') === FALSE ? '?' : '&';
        $url .= drupal_http_build_query(drupal_get_destination());
    }
    // If force is enabled, remove any destination parameter.
    if ($force && isset($_GET['destination'])) {
        unset($_GET['destination']);
    }
    // We don't invoke drupal_goto() right now, as this would end the current
    // page execution unpredictably for modules. So we'll take over drupal_goto()
    // calls from somewhere else via hook_drupal_goto_alter() and make sure
    // a drupal_goto() is invoked before the page is output with
    // rules_page_build().
    $GLOBALS['_rules_action_drupal_goto_do'] = array(
        $url,
        $force,
    );
}

/**
 * Action: Set breadcrumb.
 */
function rules_action_breadcrumb_set(array $titles, array $paths) {
    $trail = array(
        l(t('Home'), ''),
    );
    foreach ($titles as $i => $title) {
        // Skip empty titles.
        if ($title = trim($title)) {
            // Output plaintext instead of a link if there is a title without a path.
            $path = trim($paths[$i]);
            if (!empty($paths[$i]) && $paths[$i] != '<none>') {
                $trail[] = l($title, trim($paths[$i]));
            }
            else {
                $trail[] = check_plain($title);
            }
        }
    }
    drupal_set_breadcrumb($trail);
}

/**
 * Action Implementation: Send mail.
 */
function rules_action_mail($to, $subject, $message, $from, $langcode, $settings, RulesState $state, RulesPlugin $element) {
    $to = str_replace(array(
        "\r",
        "\n",
    ), '', $to);
    $from = !empty($from) ? str_replace(array(
        "\r",
        "\n",
    ), '', $from) : NULL;
    $params = array(
        'subject' => $subject,
        'message' => $message,
        'langcode' => $langcode,
    );
    // Set a unique key for this mail.
    $name = isset($element->root()->name) ? $element->root()->name : 'unnamed';
    $key = 'rules_action_mail_' . $name . '_' . $element->elementId();
    $languages = language_list();
    $language = isset($languages[$langcode]) ? $languages[$langcode] : language_default();
    $message = drupal_mail('rules', $key, $to, $language, $params, $from);
    if ($message['result']) {
        watchdog('rules', 'Successfully sent email to %recipient', array(
            '%recipient' => $to,
        ));
    }
}

/**
 * Action: Send mail to all users of a specific role group(s).
 */
function rules_action_mail_to_users_of_role($roles, $subject, $message, $from, $settings, RulesState $state, RulesPlugin $element) {
    $from = !empty($from) ? str_replace(array(
        "\r",
        "\n",
    ), '', $from) : NULL;
    // All authenticated users, which is everybody.
    if (in_array(DRUPAL_AUTHENTICATED_RID, $roles)) {
        $result = db_query('SELECT mail FROM {users} WHERE uid > 0');
    }
    else {
        // Avoid sending emails to members of two or more target role groups.
        $result = db_query('SELECT DISTINCT u.mail FROM {users} u INNER JOIN {users_roles} r ON u.uid = r.uid WHERE r.rid IN (:rids)', array(
            ':rids' => $roles,
        ));
    }
    // Now, actually send the mails.
    $params = array(
        'subject' => $subject,
        'message' => $message,
    );
    // Set a unique key for this mail.
    $name = isset($element->root()->name) ? $element->root()->name : 'unnamed';
    $key = 'rules_action_mail_to_users_of_role_' . $name . '_' . $element->elementId();
    $languages = language_list();
    $message = array(
        'result' => TRUE,
    );
    foreach ($result as $row) {
        $message = drupal_mail('rules', $key, $row->mail, language_default(), $params, $from);
        // If $message['result'] is FALSE, then it's likely that email sending is
        // failing at the moment, and we should just abort sending any more. If
        // however, $message['result'] is NULL, then it's likely that a module has
        // aborted sending this particular email to this particular user, and we
        // should just keep on sending emails to the other users.
        // For more information on the result value, see drupal_mail().
        if ($message['result'] === FALSE) {
            break;
        }
    }
    if ($message['result'] !== FALSE) {
        $role_names = array_intersect_key(user_roles(TRUE), array_flip($roles));
        watchdog('rules', 'Successfully sent email to the role(s) %roles.', array(
            '%roles' => implode(', ', $role_names),
        ));
    }
}

/**
 * Implements hook_mail().
 *
 * Sets the message subject and body as configured.
 */
function rules_mail($key, &$message, $params) {
    $message['subject'] .= str_replace(array(
        "\r",
        "\n",
    ), '', $params['subject']);
    $message['body'][] = $params['message'];
}

/**
 * Action: Block an IP address.
 */
function rules_action_block_ip($ip_address = NULL) {
    if (empty($ip_address)) {
        $ip_address = ip_address();
    }
    db_insert('blocked_ips')->fields(array(
        'ip' => $ip_address,
    ))
        ->execute();
    watchdog('rules', 'Banned IP address %ip', array(
        '%ip' => $ip_address,
    ));
}

/**
 * A class implementing a rules input evaluator processing tokens.
 */
class RulesTokenEvaluator extends RulesDataInputEvaluator {
    
    /**
     * Overrides RulesDataInputEvaluator::prepare().
     */
    public function prepare($text, $var_info) {
        $text = is_array($text) ? implode('', $text) : $text;
        // Skip this evaluator if there are no tokens.
        $this->setting = token_scan($text) ? TRUE : NULL;
    }
    
    /**
     * Evaluate tokens.
     *
     * We replace the tokens on our own as we cannot use token_replace(), because
     * token usually assumes that $data['node'] is a of type node, which doesn't
     * hold in general in our case.
     * So we properly map variable names to variable data types and then run the
     * replacement ourself.
     */
    public function evaluate($text, $options, RulesState $state) {
        $var_info = $state->varInfo();
        $options += array(
            'sanitize' => FALSE,
        );
        $replacements = array();
        $data = array();
        // We also support replacing tokens in a list of textual values.
        $whole_text = is_array($text) ? implode('', $text) : $text;
        foreach (token_scan($whole_text) as $var_name => $tokens) {
            $var_name = str_replace('-', '_', $var_name);
            if (isset($var_info[$var_name]) && ($token_type = _rules_system_token_map_type($var_info[$var_name]['type']))) {
                // We have to key $data with the type token uses for the variable.
                $data = rules_unwrap_data(array(
                    $token_type => $state->get($var_name),
                ), array(
                    $token_type => $var_info[$var_name],
                ));
                $replacements += token_generate($token_type, $tokens, $data, $options);
            }
            else {
                $replacements += token_generate($var_name, $tokens, array(), $options);
            }
            // Remove tokens if no replacement value is found. As token_replace() does
            // if 'clear' is set.
            $replacements += array_fill_keys($tokens, '');
        }
        // Optionally clean the list of replacement values.
        if (!empty($options['callback']) && function_exists($options['callback'])) {
            $function = $options['callback'];
            $function($replacements, $data, $options);
        }
        // Actually apply the replacements.
        $tokens = array_keys($replacements);
        $values = array_values($replacements);
        if (is_array($text)) {
            foreach ($text as $i => $text_item) {
                $text[$i] = str_replace($tokens, $values, $text_item);
            }
            return $text;
        }
        return str_replace($tokens, $values, $text);
    }
    
    /**
     * Create documentation about the available replacement patterns.
     *
     * @param array $var_info
     *   Array with the available variables.
     *
     * @return array
     *   Renderable array with the replacement pattern documentation.
     */
    public static function help($var_info) {
        $render = array(
            '#type' => 'fieldset',
            '#title' => t('Replacement patterns'),
            '#collapsible' => TRUE,
            '#collapsed' => TRUE,
            '#description' => t('Note that token replacements containing chained objects – such as [node:author:uid] – are not listed here, but are still available. The <em>data selection</em> input mode may help you find more complex replacement patterns. See <a href="@url">the online documentation</a> for more information about complex replacement patterns.', array(
                '@url' => rules_external_help('chained-tokens'),
            )),
        );
        $token_info = token_info();
        foreach ($var_info as $name => $info) {
            $token_types[$name] = _rules_system_token_map_type($info['type']);
        }
        foreach ($token_types as $name => $token_type) {
            if (isset($token_info['types'][$token_type])) {
                $render[$name] = array(
                    '#theme' => 'table',
                    '#header' => array(
                        t('Token'),
                        t('Label'),
                        t('Description'),
                    ),
                    '#prefix' => '<h3>' . t('Replacement patterns for %label', array(
                        '%label' => $var_info[$name]['label'],
                    )) . '</h3>',
                );
                foreach ($token_info['tokens'][$token_type] as $token => $info) {
                    $token = '[' . str_replace('_', '-', $name) . ':' . $token . ']';
                    $render[$name]['#rows'][$token] = array(
                        check_plain($token),
                        check_plain($info['name']),
                        check_plain($info['description']),
                    );
                }
            }
        }
        return $render;
    }

}

/**
 * Looks for a token type mapping. Defaults to passing through the type.
 */
function _rules_system_token_map_type($type) {
    $entity_info = entity_get_info();
    if (isset($entity_info[$type]['token type'])) {
        return $entity_info[$type]['token type'];
    }
    $cache = rules_get_cache();
    if (isset($cache['data_info'][$type]['token type'])) {
        return $cache['data_info'][$type]['token type'];
    }
    return $type;
}

/**
 * @} End of "addtogroup rules"
 */

Related topics

Functions

Title Deprecated Summary
rules_action_block_ip Action: Block an IP address.
rules_action_breadcrumb_set Action: Set breadcrumb.
rules_action_drupal_goto Action: Page redirect.
rules_action_drupal_message Action: Show a drupal message.
rules_action_drupal_watchdog Action: Write a watchdog db log message.
rules_action_mail Action Implementation: Send mail.
rules_action_mail_to_users_of_role Action: Send mail to all users of a specific role group(s).
rules_mail Implements hook_mail().
_rules_system_token_map_type Looks for a token type mapping. Defaults to passing through the type.

Classes

Title Deprecated Summary
RulesTokenEvaluator A class implementing a rules input evaluator processing tokens.