first import

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-08 11:40:19 +02:00
commit 1bc61b12ad
8435 changed files with 1582817 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
<?php
/**
* @file
* Views integration for the rules scheduler module.
*/
/**
* Implements hook_views_data(). Specifies the list of future scheduled
* tasks displayed on the schedule page.
*/
function rules_scheduler_views_data() {
$table = array(
'rules_scheduler' => array(
'table' => array(
'group' => 'Rules scheduler',
'base' => array(
'field' => 'tid',
'title' => t('Scheduled Rules components'),
'help' => t("Scheduled Rules components that are executed based on time and cron"),
'weight' => -10,
),
),
'tid' => array(
'title' => t('Tid'),
'help' => t('The internal ID of the scheduled component'),
'field' => array(
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
),
'config' => array(
'title' => t('Component name'),
'help' => t('The name of the component'),
'field' => array(
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'rules_scheduler_views_filter',
),
'argument' => array(
'handler' => 'views_handler_argument_string',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
),
'date' => array(
'title' => t('Scheduled date'),
'help' => t('Scheduled date and time stamp'),
'field' => array(
'handler' => 'views_handler_field_date',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
),
'identifier' => array(
'title' => t('User provided identifier'),
'help' => t('ID to recognize this specific scheduled task'),
'field' => array(
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
),
),
);
return $table;
}

View File

@@ -0,0 +1,180 @@
<?php
/**
* @file
* Views integration for the rules scheduler module.
*/
/**
* Implements hook_views_default_views().
*/
function rules_scheduler_views_default_views() {
$view = new view;
$view->name = 'rules_scheduler';
$view->description = 'Scheduled Rules components';
$view->tag = '';
$view->base_table = 'rules_scheduler';
$view->api_version = '3.0-alpha1';
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
/* Display: Defaults */
$handler = $view->new_display('default', 'Defaults', 'default');
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['access']['perm'] = 'administer rules';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['exposed_form']['type'] = 'basic';
$handler->display->display_options['pager']['type'] = 'full';
$handler->display->display_options['pager']['options']['items_per_page'] = '30';
$handler->display->display_options['pager']['options']['offset'] = '0';
$handler->display->display_options['pager']['options']['id'] = '0';
$handler->display->display_options['style_plugin'] = 'table';
$handler->display->display_options['style_options']['columns'] = array(
'tid' => 'tid',
'config' => 'config',
'date' => 'date',
'identifier' => 'identifier',
'nothing' => 'nothing',
);
$handler->display->display_options['style_options']['default'] = 'date';
$handler->display->display_options['style_options']['info'] = array(
'tid' => array(
'sortable' => 0,
'default_sort_order' => 'asc',
'align' => '',
'separator' => '',
),
'config' => array(
'sortable' => 1,
'default_sort_order' => 'asc',
'align' => '',
'separator' => '',
),
'date' => array(
'sortable' => 1,
'default_sort_order' => 'asc',
'align' => '',
'separator' => '',
),
'identifier' => array(
'sortable' => 1,
'default_sort_order' => 'asc',
'align' => '',
'separator' => '',
),
'nothing' => array(
'align' => '',
'separator' => '',
),
);
$handler->display->display_options['style_options']['override'] = 1;
$handler->display->display_options['style_options']['sticky'] = 0;
/* Empty text: Global: Text area */
$handler->display->display_options['empty']['area']['id'] = 'area';
$handler->display->display_options['empty']['area']['table'] = 'views';
$handler->display->display_options['empty']['area']['field'] = 'area';
$handler->display->display_options['empty']['area']['empty'] = FALSE;
$handler->display->display_options['empty']['area']['content'] = 'No tasks have been scheduled.';
$handler->display->display_options['empty']['area']['format'] = 'plain_text';
/* Field: Rules scheduler: Tid */
$handler->display->display_options['fields']['tid']['id'] = 'tid';
$handler->display->display_options['fields']['tid']['table'] = 'rules_scheduler';
$handler->display->display_options['fields']['tid']['field'] = 'tid';
/* Field: Rules scheduler: Component name */
$handler->display->display_options['fields']['config']['id'] = 'config';
$handler->display->display_options['fields']['config']['table'] = 'rules_scheduler';
$handler->display->display_options['fields']['config']['field'] = 'config';
$handler->display->display_options['fields']['config']['alter']['alter_text'] = 0;
$handler->display->display_options['fields']['config']['alter']['make_link'] = 1;
$handler->display->display_options['fields']['config']['alter']['path'] = 'admin/config/workflow/rules/config/[config]';
$handler->display->display_options['fields']['config']['alter']['absolute'] = 0;
$handler->display->display_options['fields']['config']['alter']['trim'] = 0;
$handler->display->display_options['fields']['config']['alter']['word_boundary'] = 1;
$handler->display->display_options['fields']['config']['alter']['ellipsis'] = 1;
$handler->display->display_options['fields']['config']['alter']['strip_tags'] = 0;
$handler->display->display_options['fields']['config']['alter']['html'] = 0;
$handler->display->display_options['fields']['config']['element_label_colon'] = 1;
$handler->display->display_options['fields']['config']['element_default_classes'] = 1;
$handler->display->display_options['fields']['config']['hide_empty'] = 0;
$handler->display->display_options['fields']['config']['empty_zero'] = 0;
/* Field: Rules scheduler: Scheduled date */
$handler->display->display_options['fields']['date']['id'] = 'date';
$handler->display->display_options['fields']['date']['table'] = 'rules_scheduler';
$handler->display->display_options['fields']['date']['field'] = 'date';
/* Field: Rules scheduler: User provided identifier */
$handler->display->display_options['fields']['identifier']['id'] = 'identifier';
$handler->display->display_options['fields']['identifier']['table'] = 'rules_scheduler';
$handler->display->display_options['fields']['identifier']['field'] = 'identifier';
/* Field: Global: Custom text */
$handler->display->display_options['fields']['nothing']['id'] = 'nothing';
$handler->display->display_options['fields']['nothing']['table'] = 'views';
$handler->display->display_options['fields']['nothing']['field'] = 'nothing';
$handler->display->display_options['fields']['nothing']['label'] = 'Operations';
$handler->display->display_options['fields']['nothing']['alter']['text'] = 'delete';
$handler->display->display_options['fields']['nothing']['alter']['make_link'] = 1;
$handler->display->display_options['fields']['nothing']['alter']['path'] = 'admin/config/workflow/rules/schedule/[tid]/delete';
$handler->display->display_options['fields']['nothing']['alter']['absolute'] = 0;
$handler->display->display_options['fields']['nothing']['alter']['alt'] = 'Delete this scheduled task';
$handler->display->display_options['fields']['nothing']['alter']['trim'] = 0;
$handler->display->display_options['fields']['nothing']['alter']['word_boundary'] = 1;
$handler->display->display_options['fields']['nothing']['alter']['ellipsis'] = 1;
$handler->display->display_options['fields']['nothing']['alter']['strip_tags'] = 0;
$handler->display->display_options['fields']['nothing']['alter']['html'] = 0;
$handler->display->display_options['fields']['nothing']['element_label_colon'] = 1;
$handler->display->display_options['fields']['nothing']['element_default_classes'] = 1;
$handler->display->display_options['fields']['nothing']['hide_empty'] = 0;
$handler->display->display_options['fields']['nothing']['empty_zero'] = 0;
/* Sort criterion: Rules scheduler: Scheduled date */
$handler->display->display_options['sorts']['date']['id'] = 'date';
$handler->display->display_options['sorts']['date']['table'] = 'rules_scheduler';
$handler->display->display_options['sorts']['date']['field'] = 'date';
/* Argument: Rules scheduler: Component name */
$handler->display->display_options['arguments']['config']['id'] = 'config';
$handler->display->display_options['arguments']['config']['table'] = 'rules_scheduler';
$handler->display->display_options['arguments']['config']['field'] = 'config';
$handler->display->display_options['arguments']['config']['style_plugin'] = 'default_summary';
$handler->display->display_options['arguments']['config']['wildcard'] = '0';
$handler->display->display_options['arguments']['config']['default_argument_type'] = 'fixed';
$handler->display->display_options['arguments']['config']['glossary'] = 0;
$handler->display->display_options['arguments']['config']['limit'] = '0';
$handler->display->display_options['arguments']['config']['transform_dash'] = 0;
/* Filter: Rules scheduler: Component name */
$handler->display->display_options['filters']['config']['id'] = 'config';
$handler->display->display_options['filters']['config']['table'] = 'rules_scheduler';
$handler->display->display_options['filters']['config']['field'] = 'config';
$handler->display->display_options['filters']['config']['exposed'] = TRUE;
$handler->display->display_options['filters']['config']['expose']['operator'] = 'config_op';
$handler->display->display_options['filters']['config']['expose']['label'] = 'Component filter';
$handler->display->display_options['filters']['config']['expose']['identifier'] = 'config';
$handler->display->display_options['filters']['config']['expose']['remember'] = 1;
$handler->display->display_options['filters']['config']['expose']['use_operator'] = 0;
$handler->display->display_options['filters']['config']['expose']['reduce'] = 0;
$translatables['rules_scheduler'] = array(
t('Defaults'),
t('more'),
t('Apply'),
t('Reset'),
t('Sort By'),
t('Asc'),
t('Desc'),
t('Items per page'),
t('- All -'),
t('Offset'),
t('No tasks have been scheduled.'),
t('Tid'),
t('Component name'),
t('admin/config/workflow/rules/config/[config]'),
t('Scheduled date'),
t('User provided identifier'),
t('Operations'),
t('delete'),
t('admin/config/workflow/rules/schedule/[tid]/delete'),
t('Delete this scheduled task'),
t('All'),
t('Component filter'),
);
$views = array();
$views[$view->name] = $view;
return $views;
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @file
* An extended subclass for component filtering.
*/
class rules_scheduler_views_filter extends views_handler_filter_in_operator {
function get_value_options() {
if (!isset($this->value_options)) {
$this->value_title = t('Component');
$result = db_select('rules_scheduler', 'r')
->fields('r', array('config'))
->distinct()
->execute();
$config_names = array();
foreach ($result as $record) {
$config_names[$record->config] = $record->config;
}
$this->value_options = $config_names;
}
}
}

View File

@@ -0,0 +1,140 @@
<?php
/**
* @file
* Admin forms for scheduling.
*/
/**
* Schedule page with a view for the scheduled tasks.
*/
function rules_scheduler_schedule_page() {
// Display view for all scheduled tasks
if (module_exists('views')) {
// We cannot use views_embed_view() here as we need to set the path for the
// component filter form.
$view = views_get_view('rules_scheduler');
$view->override_path = RULES_SCHEDULER_PATH;
$task_list = $view->preview();
}
else {
$task_list = t('To display scheduled tasks you have to install the <a href="http://drupal.org/project/views">Views</a> module.');
}
$page['task_view'] = array(
'#markup' => $task_list,
);
$form = drupal_get_form('rules_scheduler_form');
$page['delete'] = array(
'#markup' => drupal_render($form),
);
return $page;
}
/**
* Form for deletion of tasks by component.
*/
function rules_scheduler_form($form, &$form_state) {
$result = db_select('rules_scheduler', 'r')
->fields('r', array('config'))
->distinct()
->execute();
$config_options = array_intersect_key(rules_get_components(TRUE), $result->fetchAllAssoc('config'));
// Fieldset for canceling by component name.
$form['delete_by_config'] = array(
'#type' => 'fieldset',
'#title' => t('Delete tasks by component name'),
'#disabled' => empty($config_options)
);
$form['delete_by_config']['config'] = array(
'#title' => t('Component'),
'#type' => 'select',
'#options' => $config_options,
'#description' => t('Select the component for which to delete all scheduled tasks.'),
'#required' => TRUE,
);
$form['delete_by_config']['submit'] = array(
'#type' => 'submit',
'#value' => t('Delete tasks'),
'#submit' => array('rules_scheduler_form_delete_by_config_submit'),
);
return $form;
}
/**
* Submit handler for deleting future scheduled tasks.
*/
function rules_scheduler_form_delete_by_config_submit($form, &$form_state) {
$config = rules_config_load($form_state['values']['config']);
rules_action('schedule_delete')->execute($config->name);
drupal_set_message(t('All scheduled tasks associated with %config have been deleted.', array('%config' => $config->label())));
$form_state['redirect'] = RULES_SCHEDULER_PATH;
}
/**
* Confirmation form for deleting single tasks.
*/
function rules_scheduler_delete_task($form, &$form_state, $task) {
$form_state['task'] = $task;
$config = rules_config_load($task['config']);
$path['path'] = isset($_GET['destination']) ? $_GET['destination'] : RULES_SCHEDULER_PATH;
$title = t('Are you sure you want to delete the scheduled task %id?', array('%id' => $task['tid']));
if (!empty($task['identifier'])) {
$msg = t('This task with the custom identifier %id executes component %label on %date. The action cannot be undone.', array(
'%label' => $config->label(),
'%id' => $task['identifier'],
'%date' => format_date($task['date']),
));
}
else {
$msg = t('This task executes component %label and will be executed on %date. The action cannot be undone.', array(
'%label' => $config->label(),
'%id' => $task['identifier'],
'%date' => format_date($task['date']),
));
}
return confirm_form($form, $title, $path, $msg, t('Delete'), t('Cancel'));
}
/**
* Submit handler for deleting single tasks.
*/
function rules_scheduler_delete_task_submit($form, &$form_state) {
rules_scheduler_task_delete($form_state['task']['tid']);
drupal_set_message(t('Task %tid has been deleted.', array('%tid' => $form_state['task']['tid'])));
$form_state['redirect'] = RULES_SCHEDULER_PATH;
}
/**
* Configuration form to manually schedule a rules component.
*/
function rules_scheduler_schedule_form($form, &$form_state, $rules_config, $base_path) {
// Only components can be scheduled.
if (!($rules_config instanceof RulesTriggerableInterface)) {
RulesPluginUI::$basePath = $base_path;
$form_state['component'] = $rules_config->name;
$action = rules_action('schedule', array('component' => $rules_config->name));
$action->form($form, $form_state);
// The component should be fixed, so hide the paramter for it.
$form['parameter']['component']['#access'] = FALSE;
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Schedule'),
);
$form['#validate'] = array('rules_ui_form_rules_config_validate');
return $form;
}
drupal_not_found();
exit;
}
/**
* Submit callback to execute the scheduling action.
*/
function rules_scheduler_schedule_form_submit($form, &$form_state) {
$action = $form_state['rules_element'];
$action->execute();
drupal_set_message(t('Component %label has been scheduled.', array('%label' => rules_config_load($form_state['component'])->label())));
$form_state['redirect'] = RULES_SCHEDULER_PATH;
}

View File

@@ -0,0 +1,20 @@
name = Rules Scheduler
description = Schedule the execution of Rules components using actions.
dependencies[] = rules
package = Rules
core = 7.x
files[] = rules_scheduler.admin.inc
files[] = rules_scheduler.module
files[] = rules_scheduler.install
files[] = rules_scheduler.rules.inc
files[] = rules_scheduler.test
files[] = includes/rules_scheduler.views_default.inc
files[] = includes/rules_scheduler.views.inc
files[] = includes/rules_scheduler_views_filter.inc
; Information added by drupal.org packaging script on 2012-10-23
version = "7.x-2.2+5-dev"
core = "7.x"
project = "rules"
datestamp = "1350998486"

View File

@@ -0,0 +1,159 @@
<?php
/**
* @file
* Rules Scheduler - Installation file.
*/
/**
* Implements hook_schema().
*/
function rules_scheduler_schema() {
$schema['rules_scheduler'] = array(
'description' => 'Stores scheduled tasks.',
'fields' => array(
'tid' => array(
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => "The scheduled task's id.",
),
'config' => array(
'type' => 'varchar',
'length' => '64',
'default' => '',
'not null' => TRUE,
'description' => "The scheduled configuration's name.",
),
'date' => array(
'description' => 'The Unix timestamp of when the task is to be scheduled.',
'type' => 'int',
'not null' => TRUE,
),
'state' => array(
'type' => 'text',
'not null' => FALSE,
'serialize' => TRUE,
'description' => 'The whole, serialized evaluation state.',
),
'identifier' => array(
'type' => 'varchar',
'length' => '255',
'default' => '',
'not null' => FALSE,
'description' => 'The user defined string identifying this task.',
),
),
'primary key' => array('tid'),
'indexes' => array(
'date' => array('date'),
),
'unique key' => array(
'id' => array('config', 'identifier'),
),
);
return $schema;
}
/**
* Upgrade from Rules scheduler 6.x-1.x to 7.x.
*/
function rules_scheduler_update_7200() {
// Rename the old table so we can keep its content and start over with a
// fresh one.
db_rename_table('rules_scheduler', 'rules_scheduler_d6');
// Create the d7 table.
$schema['rules_scheduler'] = array(
'description' => 'Stores scheduled tasks.',
'fields' => array(
'tid' => array(
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => "The scheduled task's id.",
),
'config' => array(
'type' => 'varchar',
'length' => '255',
'default' => '',
'not null' => TRUE,
'description' => "The scheduled configuration's name.",
),
'date' => array(
'description' => 'The Unix timestamp of when the task is to be scheduled.',
'type' => 'int',
'not null' => TRUE,
),
'state' => array(
'type' => 'text',
'not null' => FALSE,
'serialize' => TRUE,
'description' => 'The whole, serialized evaluation state.',
),
'identifier' => array(
'type' => 'varchar',
'length' => '255',
'default' => '',
'not null' => FALSE,
'description' => 'The user defined string identifying this task.',
),
),
'primary key' => array('tid'),
'indexes' => array('date' => array('date')),
);
db_create_table('rules_scheduler', $schema['rules_scheduler']);
}
/**
* Fix the length of the rules_scheduler.name column.
*/
function rules_scheduler_update_7202() {
// Note that update 7201 (add the 'id' unique key') has been removed as it is
// incorporated by 7202. For anyone that has already run the previous update
// 7201, we have to first drop the unique key.
db_drop_unique_key('rules_scheduler', 'id');
db_change_field('rules_scheduler', 'config', 'config', array(
'type' => 'varchar',
'length' => '64',
'default' => '',
'not null' => TRUE,
'description' => "The scheduled configuration's name.",
));
db_add_unique_key('rules_scheduler', 'id', array('config', 'identifier'));
}
/**
* Rules upgrade callback for mapping the action name.
*/
function rules_scheduler_action_upgrade_map_name($element) {
return 'schedule';
}
/**
* Rules upgrade callback.
*/
function rules_scheduler_action_upgrade($element, $target) {
$target->settings['component'] = $element['#info']['set'];
$target->settings['date'] = $element['#settings']['task_date'];
$target->settings['identifier'] = $element['#settings']['task_identifier'];
unset($element['#info']['arguments']['task_date'], $element['#info']['arguments']['task_identifier']);
foreach ($element['#info']['arguments'] as $name => $info) {
rules_upgrade_element_parameter_settings($element, $target, $name, $info, 'param_' . $name);
}
}
/**
* Rules upgrade callback for mapping the action name.
*/
function rules_action_delete_scheduled_set_upgrade_map_name($element) {
return 'schedule_delete';
}
/**
* Rules upgrade callback.
*/
function rules_action_delete_scheduled_set_upgrade($element, $target) {
$target->settings['component'] = $element['#settings']['ruleset'];
$target->settings['task'] = $element['#settings']['task_identifier'];
}

View File

@@ -0,0 +1,171 @@
<?php
/**
* @file
* Rules scheduler module.
*/
define('RULES_SCHEDULER_PATH', 'admin/config/workflow/rules/schedule');
/**
* Implements hook_cron().
*/
function rules_scheduler_cron() {
// Limit adding tasks to 1000 per cron run.
$result = db_select('rules_scheduler', 'r', array('fetch' => PDO::FETCH_ASSOC))
->fields('r')
->condition('date', time(), '<=')
->range(0, 1000)
->execute();
$queue = DrupalQueue::get('rules_scheduler_tasks');
foreach ($result as $task) {
// Add the task to the queue and remove the entry afterwards.
if ($queue->createItem($task)) {
db_delete('rules_scheduler')
->condition('tid', $task['tid'])
->execute();
$task_created = TRUE;
}
}
if (!empty($task_created)) {
// hook_exit() is not invoked for cron runs, so register it as shutdown
// callback for logging the rules log to the watchdog.
drupal_register_shutdown_function('rules_exit');
// Clear the log before running tasks via the queue to avoid logging
// unrelated logs from previous cron-operations.
RulesLog::logger()->clear();
}
}
/**
* Implements hook_cron_queue_info().
*/
function rules_scheduler_cron_queue_info() {
$queues['rules_scheduler_tasks'] = array(
'worker callback' => 'rules_scheduler_run_task',
'time' => 15,
);
return $queues;
}
/**
* Queue worker callback for running a single task.
*/
function rules_scheduler_run_task(array $task) {
if ($component = rules_get_cache('comp_' . $task['config'])) {
$replacements = array('%label' => $component->label(), '%plugin' => $component->plugin());
$replacements['%identifier'] = $task['identifier'] ? $task['identifier'] : t('without identifier');
rules_log('Scheduled evaluation of %plugin %label, task %identifier.', $replacements, RulesLog::INFO, $component, TRUE);
$state = unserialize($task['state']);
$state->restoreBlocks();
// Finally evaluate the component with the given state.
$component->evaluate($state);
rules_log('Finished evaluation of %plugin %label, task %identifier.', $replacements, RulesLog::INFO, $component, FALSE);
$state->cleanUp();
}
}
/**
* Implements hook_rules_ui_menu_alter().
*
* Adds a menu item for the 'schedule' operation.
*/
function rules_scheduler_rules_ui_menu_alter(&$items, $base_path, $base_count) {
$items[$base_path . '/manage/%rules_config/schedule'] = array(
'title callback' => 'rules_get_title',
'title arguments' => array('Schedule !plugin "!label"', $base_count + 1),
'page callback' => 'drupal_get_form',
'page arguments' => array('rules_scheduler_schedule_form', $base_count + 1, $base_path),
'access callback' => 'rules_config_access',
'access arguments' => array('update', $base_count + 1),
'file' => 'rules_scheduler.admin.inc',
'file path' => drupal_get_path('module', 'rules_scheduler'),
);
}
/**
* Implements hook_menu().
*/
function rules_scheduler_menu() {
$items = array();
$items[RULES_SCHEDULER_PATH] = array(
'title' => 'Schedule',
'type' => MENU_LOCAL_TASK,
'page callback' => 'rules_scheduler_schedule_page',
'access arguments' => array('administer rules'),
'file' => 'rules_scheduler.admin.inc',
);
$items[RULES_SCHEDULER_PATH .'/%rules_scheduler_task/delete'] = array(
'title' => 'Delete a scheduled task',
'type' => MENU_CALLBACK,
'page callback' => 'drupal_get_form',
'page arguments' => array('rules_scheduler_delete_task', 5),
'access arguments' => array('administer rules'),
'file' => 'rules_scheduler.admin.inc',
);
return $items;
}
/**
* Load a task by a given task ID.
*/
function rules_scheduler_task_load($tid) {
$result = db_select('rules_scheduler', 'r')
->fields('r')
->condition('tid', (int) $tid)
->execute();
return $result->fetchAssoc();
}
/**
* Delete a task by a given task ID.
*/
function rules_scheduler_task_delete($tid) {
db_delete('rules_scheduler')
->condition('tid', $tid)
->execute();
}
/**
* Schedule a task to be executed later on.
*
* @param $task
* An array representing the task with the following keys:
* - config: The machine readable name of the to be scheduled component.
* - date: Timestamp when the component should be executed.
* - state: An rules evaluation state to use for scheduling.
* - identifier: User provided string to identify the task per scheduled
* configuration.
*/
function rules_scheduler_schedule_task($task) {
if (!empty($task['identifier'])) {
// If there is a task with the same identifier and component, we replace it.
db_delete('rules_scheduler')
->condition('config', $task['config'])
->condition('identifier', $task['identifier'])
->execute();
}
drupal_write_record('rules_scheduler', $task);
}
/**
* Implements hook_rules_config_delete().
*/
function rules_scheduler_rules_config_delete($rules_config) {
// Delete all tasks scheduled for this config.
db_delete('rules_scheduler')
->condition('config', $rules_config->name)
->execute();
}
/**
* Implements hook_views_api().
*/
function rules_scheduler_views_api() {
return array(
'api' => '3.0-alpha1',
'path' => drupal_get_path('module', 'rules_scheduler') .'/includes',
);
}

View File

@@ -0,0 +1,214 @@
<?php
/**
* @file
* Rules integration for the rules scheduler module.
*
* @addtogroup rules
* @{
*/
/**
* Implements hook_rules_action_info().
*/
function rules_scheduler_rules_action_info() {
$items['schedule'] = array(
'label' => t('Schedule component evaluation'),
'group' => t('Rules scheduler'),
'base' => 'rules_scheduler_action_schedule',
'named parameter' => TRUE,
'parameter' => array(
'component' => array(
'type' => 'text',
'label' => t('Component'),
'options list' => 'rules_scheduler_component_options_list',
'restriction' => 'input',
'description' => 'Select the component to schedule. Only components containing actions are available no condition sets.',
),
'date' => array(
'type' => 'date',
'label' => t('Scheduled evaluation date'),
),
'identifier' => array(
'type' => 'text',
'label' => t('Identifier'),
'description' => t('A string used for identifying this task. Any existing tasks for this component with the same identifier will be replaced.'),
'optional' => TRUE,
),
// Further needed parameter by the component are added during processing.
),
);
// Add action to delete scheduled tasks.
$items['schedule_delete'] = array(
'label' => t('Delete scheduled tasks'),
'group' => t('Rules scheduler'),
'base' => 'rules_scheduler_action_delete',
'parameter' => array(
'component' => array(
'type' => 'text',
'label' => t('Component'),
'options list' => 'rules_scheduler_component_options_list',
'description' => t('The component for which scheduled tasks will be deleted.'),
'optional' => TRUE,
),
'task' => array(
'type' => 'text',
'label' => t('Task identifier'),
'description' => t('All tasks that are annotated with the given identifier will be deleted.'),
'optional' => TRUE,
),
),
);
return $items;
}
/**
* Options list callback returning a list of action components.
*/
function rules_scheduler_component_options_list() {
return rules_get_components(TRUE, 'action');
}
/**
* Base action implementation for scheduling components.
*/
function rules_scheduler_action_schedule($args, $element) {
$state = $args['state'];
if ($component = rules_get_cache('comp_' . $args['component'])) {
// Manually create a new evaluation state for scheduling the evaluation.
$new_state = new RulesState();
// Register all parameters as variables.
foreach ($element->pluginParameterInfo() as $name => $info) {
if (strpos($name, 'param_') === 0) {
// Remove the parameter name prefix 'param_'.
$var_name = substr($name, 6);
$new_state->addVariable($var_name, $state->currentArguments[$name], $info);
}
}
rules_scheduler_schedule_task(array(
'date' => $args['date'],
'config' => $args['component'],
'state' => $new_state,
'identifier' => $args['identifier'],
));
}
else {
throw new RulesEvaluationException('Unable to get the component %name', array('%name' => $args['component']), $element, RulesLog::ERROR);
}
}
/**
* Info alteration callback for the schedule action.
*/
function rules_scheduler_action_schedule_info_alter(&$element_info, RulesPlugin $element) {
if (isset($element->settings['component'])) {
// If run during a cache rebuild the cache might not be instantiated yet,
// so fail back to loading the component from database.
if (($component = rules_get_cache('comp_' . $element->settings['component'])) || $component = rules_config_load($element->settings['component'])) {
// Add in the needed parameters.
foreach ($component->parameterInfo() as $name => $info) {
$element_info['parameter']['param_' . $name] = $info;
}
}
}
}
/**
* Validate callback for the schedule action to make sure the component exists and is not dirty.
*
* @see rules_element_invoke_component_validate()
*/
function rules_scheduler_action_schedule_validate(RulesPlugin $element) {
$info = $element->info();
$component = rules_config_load($element->settings['component']);
if (!$component) {
throw new RulesIntegrityException(t('The component %config does not exist.', array('%config' => $element->settings['component'])), $element);
}
// Check if the component is marked as dirty.
rules_config_update_dirty_flag($component);
if (!empty($component->dirty)) {
throw new RulesIntegrityException(t('The utilized component %config fails the integrity check.', array('%config' => $element->settings['component'])), $element);
}
}
/**
* Help for the schedule action.
*/
function rules_scheduler_action_schedule_help() {
return t("Note that component evaluation is triggered by <em>cron</em> make sure cron is configured correctly by checking your site's !status. The scheduling time accuracy depends on your configured cron interval. See <a href='@url'>the online documentation</a> for more information on how to schedule evaluation of components.",
array('!status' => l('Status report', 'admin/reports/status'),
'@url' => rules_external_help('scheduler')));
}
/**
* Form alter callback for the schedule action.
*/
function rules_scheduler_action_schedule_form_alter(&$form, &$form_state, $options, RulesAbstractPlugin $element) {
$first_step = empty($element->settings['component']);
$form['reload'] = array(
'#weight' => 5,
'#type' => 'submit',
'#name' => 'reload',
'#value' => $first_step ? t('Continue') : t('Reload form'),
'#limit_validation_errors' => array(array('parameter', 'component')),
'#submit' => array('rules_action_type_form_submit_rebuild'),
'#ajax' => rules_ui_form_default_ajax(),
);
// Use ajax and trigger as the reload button.
$form['parameter']['component']['settings']['type']['#ajax'] = $form['reload']['#ajax'] + array(
'event' => 'change',
'trigger_as' => array('name' => 'reload'),
);
if ($first_step) {
// In the first step show only the component select.
foreach (element_children($form['parameter']) as $key) {
if ($key != 'component') {
unset($form['parameter'][$key]);
}
}
unset($form['submit']);
unset($form['provides']);
}
else {
// Hide the reload button in case js is enabled and it's not the first step.
$form['reload']['#attributes'] = array('class' => array('rules-hide-js'));
}
}
/**
* Action: Delete scheduled tasks.
*/
function rules_scheduler_action_delete($component_name = NULL, $task_identifier = NULL) {
$query = db_delete('rules_scheduler');
if (!empty($component_name)) {
$query->condition('config', $component_name);
}
if (!empty($task_identifier)) {
$query->condition('identifier', $task_identifier);
}
$query->execute();
}
/**
* Cancel scheduled task action validation callback.
*/
function rules_scheduler_action_delete_validate($element) {
if (empty($element->settings['task']) && empty($element->settings['task:select']) &&
empty($element->settings['component']) && empty($element->settings['component:select'])) {
throw new RulesIntegrityException(t('You have to specify at least either a component or a task identifier.'), $element);
}
}
/**
* Help for the cancel action.
*/
function rules_scheduler_action_delete_help() {
return t('This action allows you to delete scheduled tasks that are waiting for future execution.') .' '. t('They can be addressed by an identifier or by the component name, whereas if both are specified only tasks fulfilling both requirements will be deleted.');
}
/**
* @}
*/

View File

@@ -0,0 +1,100 @@
<?php
/**
* @file
* Rules Scheduler tests.
*/
class RulesSchedulerTestCase extends DrupalWebTestCase {
static function getInfo() {
return array(
'name' => 'Rules Scheduler tests',
'description' => 'Test scheduling components.',
'group' => 'Rules',
);
}
function setUp() {
parent::setUp('rules_scheduler');
RulesLog::logger()->clear();
variable_set('rules_debug_log', 1);
}
/**
* Tests scheduling components from the action.
*
* Note that this also makes sure Rules properly handles timezones, else this
* test could fail due to a wrong 'now' timestamp.
*/
function testComponentSchedule() {
$set = rules_rule_set(array(
'node1' => array('type' => 'node', 'label' => 'node'),
));
$set->rule(rule()->condition('node_is_published', array('node:select' => 'node1'))
->action('node_unpublish', array('node:select' => 'node1'))
);
$set->integrityCheck()->save('rules_test_set_2');
// Use different names for the variables to ensure they are properly mapped.
$rule = rule(array(
'node2' => array('type' => 'node', 'label' => 'node'),
));
$rule->action('schedule', array(
'component' => 'rules_test_set_2',
'identifier' => 'node_[node2:nid]',
'date' => 'now',
'param_node1:select' => 'node2',
));
$node = $this->drupalCreateNode(array('title' => 'The title.', 'status' => 1));
$rule->execute($node);
// Run cron to let the rules scheduler do its work.
drupal_cron_run();
$node = node_load($node->nid, NULL, TRUE);
$this->assertFalse($node->status, 'The component has been properly scheduled.');
RulesLog::logger()->checkLog();
}
/**
* Make sure recurion prevention is working fine for scheduled rule sets.
*/
function testRecursionPrevention() {
$set = rules_rule_set(array(
'node1' => array('type' => 'node', 'label' => 'node'),
));
$set->rule(rule()->condition('node_is_published', array('node:select' => 'node1'))
->action('node_unpublish', array('node:select' => 'node1'))
);
$set->integrityCheck()->save('rules_test_set_2');
// Add an reaction rule that is triggered upon a node save. The scheduled
// component changes the node, thus it would be scheduled again and run in
// an endless loop.
$rule = rules_reaction_rule();
$rule->event('node_insert');
$rule->event('node_update');
$rule->action('schedule', array(
'component' => 'rules_test_set_2',
'identifier' => '',
'date' => 'now',
'param_node1:select' => 'node',
));
$rule->save();
// Create a node, what triggers the rule.
$node = $this->drupalCreateNode(array('title' => 'The title.', 'status' => 1));
// Run cron to let the rules scheduler do its work.
drupal_cron_run();
$node = node_load($node->nid, NULL, TRUE);
$this->assertFalse($node->status, 'The component has been properly scheduled.');
$text1 = RulesLog::logger()->render();
$text2 = RulesTestCase::t('Not evaluating reaction rule %unlabeled to prevent recursion.', array('unlabeled' => $rule->name));
$this->assertTrue((strpos($text1, $text2) !== FALSE), "Scheduled recursion prevented.");
RulesLog::logger()->checkLog();
}
}