First commit

This commit is contained in:
Theodotos Andreou 2018-01-14 13:10:16 +00:00
commit c6e2478c40
13918 changed files with 2303184 additions and 0 deletions

View file

@ -0,0 +1,67 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
* $Id$
*
*/
/**
* Helpers for managing SQL-backed queue items
*
* @see CRM_Queue_Queue_Sql
*/
class CRM_Queue_BAO_QueueItem extends CRM_Queue_DAO_QueueItem {
/**
* Ensure that the required SQL table exists.
*
* @return bool
* TRUE if table now exists
*/
public static function findCreateTable() {
$checkTableSql = "show tables like 'civicrm_queue_item'";
$foundName = CRM_Core_DAO::singleValueQuery($checkTableSql);
if ($foundName == 'civicrm_queue_item') {
return TRUE;
}
// civicrm/sql/civicrm_queue_item.mysql
$fileName = dirname(__FILE__) . '/../../../sql/civicrm_queue_item.mysql';
$config = CRM_Core_Config::singleton();
CRM_Utils_File::sourceSQLFile($config->dsn, $fileName);
// Make sure it succeeded
$foundName = CRM_Core_DAO::singleValueQuery($checkTableSql);
return ($foundName == 'civicrm_queue_item');
}
}

View file

@ -0,0 +1,251 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*
* Generated from xml/schema/CRM/Queue/QueueItem.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
* (GenCodeChecksum:6ca85e3a41502dda3e60a1c53a83c67f)
*/
require_once 'CRM/Core/DAO.php';
require_once 'CRM/Utils/Type.php';
/**
* CRM_Queue_DAO_QueueItem constructor.
*/
class CRM_Queue_DAO_QueueItem extends CRM_Core_DAO {
/**
* Static instance to hold the table name.
*
* @var string
*/
static $_tableName = 'civicrm_queue_item';
/**
* Should CiviCRM log any modifications to this table in the civicrm_log table.
*
* @var boolean
*/
static $_log = false;
/**
*
* @var int unsigned
*/
public $id;
/**
* Name of the queue which includes this item
*
* @var string
*/
public $queue_name;
/**
*
* @var int
*/
public $weight;
/**
* date on which this item was submitted to the queue
*
* @var datetime
*/
public $submit_time;
/**
* date on which this job becomes available; null if ASAP
*
* @var datetime
*/
public $release_time;
/**
* Serialized queue
*
* @var text
*/
public $data;
/**
* Class constructor.
*/
function __construct() {
$this->__table = 'civicrm_queue_item';
parent::__construct();
}
/**
* Returns all the column names of this table
*
* @return array
*/
static function &fields() {
if (!isset(Civi::$statics[__CLASS__]['fields'])) {
Civi::$statics[__CLASS__]['fields'] = array(
'id' => array(
'name' => 'id',
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Queue ID') ,
'required' => true,
'table_name' => 'civicrm_queue_item',
'entity' => 'QueueItem',
'bao' => 'CRM_Queue_BAO_QueueItem',
'localizable' => 0,
) ,
'queue_name' => array(
'name' => 'queue_name',
'type' => CRM_Utils_Type::T_STRING,
'title' => ts('Queue Name') ,
'description' => 'Name of the queue which includes this item',
'required' => true,
'maxlength' => 64,
'size' => CRM_Utils_Type::BIG,
'table_name' => 'civicrm_queue_item',
'entity' => 'QueueItem',
'bao' => 'CRM_Queue_BAO_QueueItem',
'localizable' => 0,
'html' => array(
'type' => 'Text',
) ,
) ,
'weight' => array(
'name' => 'weight',
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Order') ,
'required' => true,
'table_name' => 'civicrm_queue_item',
'entity' => 'QueueItem',
'bao' => 'CRM_Queue_BAO_QueueItem',
'localizable' => 0,
'html' => array(
'type' => 'Text',
) ,
) ,
'submit_time' => array(
'name' => 'submit_time',
'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME,
'title' => ts('Submit Time') ,
'description' => 'date on which this item was submitted to the queue',
'required' => true,
'table_name' => 'civicrm_queue_item',
'entity' => 'QueueItem',
'bao' => 'CRM_Queue_BAO_QueueItem',
'localizable' => 0,
'html' => array(
'type' => 'Select Date',
) ,
) ,
'release_time' => array(
'name' => 'release_time',
'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME,
'title' => ts('Release Time') ,
'description' => 'date on which this job becomes available; null if ASAP',
'table_name' => 'civicrm_queue_item',
'entity' => 'QueueItem',
'bao' => 'CRM_Queue_BAO_QueueItem',
'localizable' => 0,
'html' => array(
'type' => 'Select Date',
) ,
) ,
'data' => array(
'name' => 'data',
'type' => CRM_Utils_Type::T_TEXT,
'title' => ts('Queue item datas') ,
'description' => 'Serialized queue',
'table_name' => 'civicrm_queue_item',
'entity' => 'QueueItem',
'bao' => 'CRM_Queue_BAO_QueueItem',
'localizable' => 0,
) ,
);
CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'fields_callback', Civi::$statics[__CLASS__]['fields']);
}
return Civi::$statics[__CLASS__]['fields'];
}
/**
* Return a mapping from field-name to the corresponding key (as used in fields()).
*
* @return array
* Array(string $name => string $uniqueName).
*/
static function &fieldKeys() {
if (!isset(Civi::$statics[__CLASS__]['fieldKeys'])) {
Civi::$statics[__CLASS__]['fieldKeys'] = array_flip(CRM_Utils_Array::collect('name', self::fields()));
}
return Civi::$statics[__CLASS__]['fieldKeys'];
}
/**
* Returns the names of this table
*
* @return string
*/
static function getTableName() {
return self::$_tableName;
}
/**
* Returns if this table needs to be logged
*
* @return boolean
*/
function getLog() {
return self::$_log;
}
/**
* Returns the list of fields that can be imported
*
* @param bool $prefix
*
* @return array
*/
static function &import($prefix = false) {
$r = CRM_Core_DAO_AllCoreTables::getImports(__CLASS__, 'queue_item', $prefix, array());
return $r;
}
/**
* Returns the list of fields that can be exported
*
* @param bool $prefix
*
* @return array
*/
static function &export($prefix = false) {
$r = CRM_Core_DAO_AllCoreTables::getExports(__CLASS__, 'queue_item', $prefix, array());
return $r;
}
/**
* Returns the list of indices
*/
public static function indices($localize = TRUE) {
$indices = array(
'index_queueids' => array(
'name' => 'index_queueids',
'field' => array(
0 => 'queue_name',
1 => 'weight',
2 => 'id',
) ,
'localizable' => false,
'sig' => 'civicrm_queue_item::0::queue_name::weight::id',
) ,
);
return ($localize && !empty($indices)) ? CRM_Core_DAO_AllCoreTables::multilingualize(__CLASS__, $indices) : $indices;
}
}

View file

@ -0,0 +1,201 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
* To ensure that PHP errors or unhandled exceptions are reported in JSON
* format, wrap this around your code. For example:
*
* @code
* $errorContainer = new CRM_Queue_ErrorPolicy();
* $errorContainer->call(function() {
* ...include some files, do some work, etc...
* });
* @endcode
*
* Note: Most of the code in this class is pretty generic vis-a-vis error
* handling -- except for 'reportError', whose message format is only
* appropriate for use with the CRM_Queue_Page_AJAX. Some kind of cleanup
* will be necessary to get reuse from the other parts of this class.
*/
class CRM_Queue_ErrorPolicy {
public $active;
/**
* @param null|int $level
* PHP error level to capture (e.g. E_PARSE|E_USER_ERROR).
*/
public function __construct($level = NULL) {
register_shutdown_function(array($this, 'onShutdown'));
if ($level === NULL) {
$level = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR;
}
$this->level = $level;
}
/**
* Enable the error policy.
*/
public function activate() {
$this->active = TRUE;
$this->backup = array();
foreach (array(
'display_errors',
'html_errors',
'xmlrpc_errors',
) as $key) {
$this->backup[$key] = ini_get($key);
ini_set($key, 0);
}
set_error_handler(array($this, 'onError'), $this->level);
// FIXME make this temporary/reversible
$this->errorScope = CRM_Core_TemporaryErrorScope::useException();
}
/**
* Disable the error policy.
*/
public function deactivate() {
$this->errorScope = NULL;
restore_error_handler();
foreach (array(
'display_errors',
'html_errors',
'xmlrpc_errors',
) as $key) {
ini_set($key, $this->backup[$key]);
}
$this->active = FALSE;
}
/**
* Execute the callable. Activate and deactivate the error policy
* automatically.
*
* @param callable|array|string $callable
* A callback function.
*
* @return mixed
*/
public function call($callable) {
$this->activate();
try {
$result = $callable();
}
catch (Exception$e) {
$this->reportException($e);
}
$this->deactivate();
return $result;
}
/**
* Receive (semi) recoverable error notices.
*
* @see set_error_handler
*
* @param string $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
*
* @return bool
* @throws \Exception
*/
public function onError($errno, $errstr, $errfile, $errline) {
if (!(error_reporting() & $errno)) {
return TRUE;
}
throw new Exception(sprintf('PHP Error %s at %s:%s: %s', $errno, $errfile, $errline, $errstr));
}
/**
* Receive non-recoverable error notices
*
* @see register_shutdown_function
* @see error_get_last
*/
public function onShutdown() {
if (!$this->active) {
return;
}
$error = error_get_last();
if (is_array($error) && ($error['type'] & $this->level)) {
$this->reportError($error);
}
}
/**
* Print a fatal error.
*
* @param array $error
* The PHP error (with "type", "message", etc).
*/
public function reportError($error) {
$response = array(
'is_error' => 1,
'is_continue' => 0,
'exception' => htmlentities(sprintf('Error %s: %s in %s, line %s', $error['type'], $error['message'], $error['file'], $error['line'])),
);
global $activeQueueRunner;
if (is_object($activeQueueRunner)) {
$response['last_task_title'] = $activeQueueRunner->lastTaskTitle;
}
CRM_Core_Error::debug_var('CRM_Queue_ErrorPolicy_reportError', $response);
echo json_encode($response);
// civiExit() is unnecessary -- we're only called as part of abend
}
/**
* Print an unhandled exception.
*
* @param Exception $e
* The unhandled exception.
*/
public function reportException(Exception $e) {
CRM_Core_Error::debug_var('CRM_Queue_ErrorPolicy_reportException', CRM_Core_Error::formatTextException($e));
$response = array(
'is_error' => 1,
'is_continue' => 0,
);
$config = CRM_Core_Config::singleton();
if ($config->backtrace || CRM_Core_Config::isUpgradeMode()) {
$response['exception'] = CRM_Core_Error::formatHtmlException($e);
}
else {
$response['exception'] = htmlentities($e->getMessage());
}
global $activeQueueRunner;
if (is_object($activeQueueRunner)) {
$response['last_task_title'] = $activeQueueRunner->lastTaskTitle;
}
CRM_Utils_JSON::output($response);
}
}

View file

@ -0,0 +1,91 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
* This file hard-codes the path entries for the queueing UI, which
* allows us to use these paths during upgrades.
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
* $Id$
*
*/
require_once 'CRM/Core/I18n.php';
/**
* Class CRM_Queue_Menu
*/
class CRM_Queue_Menu {
/**
* @param string $path
* The path for which we are trying to locate the route.
* @param array $menuPath
* The route.
*/
public static function alter($path, &$menuPath) {
switch ($path) {
case 'civicrm/queue/runner':
case 'civicrm/upgrade/queue/runner':
$menuPath['path'] = $path;
$menuPath['title'] = 'Queue Runner';
$menuPath['page_callback'] = 'CRM_Queue_Page_Runner';
$menuPath['access_arguments'][0][] = 'access CiviCRM';
$menuPath['access_callback'] = array('CRM_Core_Permission', 'checkMenu');
break;
case 'civicrm/queue/ajax/runNext':
case 'civicrm/upgrade/queue/ajax/runNext':
$menuPath['path'] = $path;
$menuPath['page_callback'] = array('CRM_Queue_Page_AJAX', 'runNext');
$menuPath['access_arguments'][0][] = 'access CiviCRM';
$menuPath['access_callback'] = array('CRM_Core_Permission', 'checkMenu');
break;
case 'civicrm/queue/ajax/skipNext':
case 'civicrm/upgrade/queue/ajax/skipNext':
$menuPath['path'] = $path;
$menuPath['page_callback'] = array('CRM_Queue_Page_AJAX', 'skipNext');
$menuPath['access_arguments'][0][] = 'access CiviCRM';
$menuPath['access_callback'] = array('CRM_Core_Permission', 'checkMenu');
break;
case 'civicrm/queue/ajax/onEnd':
case 'civicrm/upgrade/queue/ajax/onEnd':
$menuPath['path'] = $path;
$menuPath['page_callback'] = array('CRM_Queue_Page_AJAX', 'onEnd');
$menuPath['access_arguments'][0][] = 'access CiviCRM';
$menuPath['access_callback'] = array('CRM_Core_Permission', 'checkMenu');
break;
default:
// unrecognized
}
}
}

View file

@ -0,0 +1,131 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
* Class CRM_Queue_Page_AJAX
*/
class CRM_Queue_Page_AJAX {
/**
* Run the next task and return status information.
*
* Outputs JSON: array(
* is_error => bool,
* is_continue => bool,
* numberOfItems => int,
* exception => htmlString
* )
*/
public static function runNext() {
$errorPolicy = new CRM_Queue_ErrorPolicy();
$errorPolicy->call(function () {
global $activeQueueRunner;
$qrid = CRM_Utils_Request::retrieve('qrid', 'String', CRM_Core_DAO::$_nullObject, TRUE, NULL, 'POST');
$activeQueueRunner = CRM_Queue_Runner::instance($qrid);
if (!is_object($activeQueueRunner)) {
throw new Exception('Queue runner must be configured before execution.');
}
$result = $activeQueueRunner->runNext(TRUE);
CRM_Queue_Page_AJAX::_return('runNext', $result);
});
}
/**
* Run the next task and return status information.
*
* Outputs JSON: array(
* is_error => bool,
* is_continue => bool,
* numberOfItems => int,
* exception => htmlString
* )
*/
public static function skipNext() {
$errorPolicy = new CRM_Queue_ErrorPolicy();
$errorPolicy->call(function () {
global $activeQueueRunner;
$qrid = CRM_Utils_Request::retrieve('qrid', 'String', CRM_Core_DAO::$_nullObject, TRUE, NULL, 'POST');
$activeQueueRunner = CRM_Queue_Runner::instance($qrid);
if (!is_object($activeQueueRunner)) {
throw new Exception('Queue runner must be configured before execution.');
}
$result = $activeQueueRunner->skipNext(TRUE);
CRM_Queue_Page_AJAX::_return('skipNext', $result);
});
}
/**
* Run the next task and return status information.
*
* Outputs JSON: array(
* is_error => bool,
* is_continue => bool,
* numberOfItems => int,
* exception => htmlString
* )
*/
public static function onEnd() {
$errorPolicy = new CRM_Queue_ErrorPolicy();
$errorPolicy->call(function () {
global $activeQueueRunner;
$qrid = CRM_Utils_Request::retrieve('qrid', 'String', CRM_Core_DAO::$_nullObject, TRUE, NULL, 'POST');
$activeQueueRunner = CRM_Queue_Runner::instance($qrid);
if (!is_object($activeQueueRunner)) {
throw new Exception('Queue runner must be configured before execution. - onEnd');
}
$result = $activeQueueRunner->handleEnd(FALSE);
CRM_Queue_Page_AJAX::_return('onEnd', $result);
});
}
/**
* Performing any view-layer filtering on result and send to client.
*
* @param string $op
* @param array $result
*/
public static function _return($op, $result) {
if ($result['is_error']) {
if (is_object($result['exception'])) {
CRM_Core_Error::debug_var("CRM_Queue_Page_AJAX_{$op}_error", CRM_Core_Error::formatTextException($result['exception']));
$config = CRM_Core_Config::singleton();
if ($config->backtrace || CRM_Core_Config::isUpgradeMode()) {
$result['exception'] = CRM_Core_Error::formatHtmlException($result['exception']);
}
else {
$result['exception'] = $result['exception']->getMessage();
}
}
else {
CRM_Core_Error::debug_var("CRM_Queue_Page_AJAX_{$op}_error", $result);
}
}
CRM_Utils_JSON::output($result);
}
}

View file

@ -0,0 +1,83 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
require_once 'CRM/Core/Page.php';
/**
* The queue-runner page provides an interactive, web-based system
* running the tasks in a queue and monitoring its progression.
*
* Do not link or redirect to this page directly -- go through
* CRM_Queue_Runner::runAllViaWeb().
*
* Note: The queue runner only requires 'access CiviCRM' permission.
* To ensure that malicious parties don't use this feature to
* run queues on the wrong schedule, the queue-runner has an
* extra authorization step: it checks for a session variable named
* $_SESSION['queueRunners][$qrid]. This variable is properly setup
* if you use the CRM_Queue_Runner::runAllViaWeb() interface.
*/
class CRM_Queue_Page_Runner extends CRM_Core_Page {
/**
*
* POST Param 'qrid': string, usually the name of the queue
*/
public function run() {
$qrid = CRM_Utils_Request::retrieve('qrid', 'String', $this, TRUE);
$runner = CRM_Queue_Runner::instance($qrid);
if (!is_object($runner)) {
CRM_Core_Error::fatal('Queue runner must be configured before execution.');
}
CRM_Utils_System::setTitle($runner->title);
$this->assign('queueRunnerData', array(
'qrid' => $runner->qrid,
'runNextAjax' => CRM_Utils_System::url($runner->pathPrefix . '/ajax/runNext', NULL, FALSE, NULL, FALSE),
'skipNextAjax' => CRM_Utils_System::url($runner->pathPrefix . '/ajax/skipNext', NULL, FALSE, NULL, FALSE),
'onEndAjax' => CRM_Utils_System::url($runner->pathPrefix . '/ajax/onEnd', NULL, FALSE, NULL, FALSE),
'completed' => 0,
'numberOfItems' => $runner->queue->numberOfItems(),
'buttons' => $runner->buttons,
));
if ($runner->isMinimal) {
// Render page header
if (!defined('CIVICRM_UF_HEAD') && $region = CRM_Core_Region::instance('html-header', FALSE)) {
CRM_Utils_System::addHTMLHead($region->render(''));
}
$smarty = CRM_Core_Smarty::singleton();
$content = $smarty->fetch('CRM/Queue/Page/Runner.tpl');
echo CRM_Utils_System::theme($content, $this->_print, TRUE);
}
else {
parent::run();
}
}
}

View file

@ -0,0 +1,149 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
* A queue is an object (usually backed by some persistent data store)
* which stores a list of tasks or messages for use by other processes.
*
* This would ideally be an interface, but it's handy to specify the
* "function __construct()" and the "$name" handling
*
* Note: This interface closely parallels the DrupalQueueInterface.
*/
abstract class CRM_Queue_Queue {
/**
* @var string
*/
private $_name;
/**
* Create a reference to queue. After constructing the queue, one should
* usually call createQueue (if it's a new queue) or loadQueue (if it's
* known to be an existing queue).
*
* @param array $queueSpec
* Array with keys:
* - type: string, required, e.g. "interactive", "immediate", "stomp",
* "beanstalk"
* - name: string, required, e.g. "upgrade-tasks"
* - reset: bool, optional; if a queue is found, then it should be
* flushed; default to TRUE
* - (additional keys depending on the queue provider).
*/
public function __construct($queueSpec) {
$this->_name = $queueSpec['name'];
}
/**
* Determine the string name of this queue.
*
* @return string
*/
public function getName() {
return $this->_name;
}
/**
* Perform any registation or resource-allocation for a new queue
*/
public abstract function createQueue();
/**
* Perform any loading or pre-fetch for an existing queue.
*/
public abstract function loadQueue();
/**
* Release any resources claimed by the queue (memory, DB rows, etc)
*/
public abstract function deleteQueue();
/**
* Check if the queue exists.
*
* @return bool
*/
public abstract function existsQueue();
/**
* Add a new item to the queue.
*
* @param mixed $data
* Serializable PHP object or array.
* @param array $options
* Queue-dependent options; for example, if this is a
* priority-queue, then $options might specify the item's priority.
*/
public abstract function createItem($data, $options = array());
/**
* Determine number of items remaining in the queue.
*
* @return int
*/
public abstract function numberOfItems();
/**
* Get the next item.
*
* @param int $lease_time
* Seconds.
*
* @return object
* with key 'data' that matches the inputted data
*/
public abstract function claimItem($lease_time = 3600);
/**
* Get the next item, even if there's an active lease
*
* @param int $lease_time
* Seconds.
*
* @return object
* with key 'data' that matches the inputted data
*/
public abstract function stealItem($lease_time = 3600);
/**
* Remove an item from the queue.
*
* @param object $item
* The item returned by claimItem.
*/
public abstract function deleteItem($item);
/**
* Return an item that could not be processed.
*
* @param object $item
* The item returned by claimItem.
*/
public abstract function releaseItem($item);
}

View file

@ -0,0 +1,197 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
* A queue implementation which stores items in the CiviCRM SQL database
*/
class CRM_Queue_Queue_Memory extends CRM_Queue_Queue {
/**
* @var array
* array(queueItemId => queueItemData)
*/
public $items;
/**
* @var array
* array(queueItemId => releaseTime), expressed in seconds since epoch.
*/
public $releaseTimes;
public $nextQueueItemId = 1;
/**
* Create a reference to queue. After constructing the queue, one should
* usually call createQueue (if it's a new queue) or loadQueue (if it's
* known to be an existing queue).
*
* @param array $queueSpec
* Array with keys:
* - type: string, required, e.g. "interactive", "immediate", "stomp",
* "beanstalk"
* - name: string, required, e.g. "upgrade-tasks"
* - reset: bool, optional; if a queue is found, then it should be
* flushed; default to TRUE
* - (additional keys depending on the queue provider).
*/
public function __construct($queueSpec) {
parent::__construct($queueSpec);
}
/**
* Perform any registation or resource-allocation for a new queue
*/
public function createQueue() {
$this->items = array();
$this->releaseTimes = array();
}
/**
* Perform any loading or pre-fetch for an existing queue.
*/
public function loadQueue() {
// $this->createQueue();
throw new Exception('Unsupported: CRM_Queue_Queue_Memory::loadQueue');
}
/**
* Release any resources claimed by the queue (memory, DB rows, etc)
*/
public function deleteQueue() {
$this->items = NULL;
$this->releaseTimes = NULL;
}
/**
* Check if the queue exists.
*
* @return bool
*/
public function existsQueue() {
return is_array($this->items);
}
/**
* Add a new item to the queue.
*
* @param mixed $data
* Serializable PHP object or array.
* @param array $options
* Queue-dependent options; for example, if this is a
* priority-queue, then $options might specify the item's priority.
*/
public function createItem($data, $options = array()) {
$id = $this->nextQueueItemId++;
// force copy, no unintendedsharing effects from pointers
$this->items[$id] = serialize($data);
}
/**
* Determine number of items remaining in the queue.
*
* @return int
*/
public function numberOfItems() {
return count($this->items);
}
/**
* Get and remove the next item.
*
* @param int $leaseTime
* Seconds.
*
* @return object
* Includes key 'data' that matches the inputted data.
*/
public function claimItem($leaseTime = 3600) {
// foreach hits the items in order -- but we short-circuit after the first
foreach ($this->items as $id => $data) {
$nowEpoch = CRM_Utils_Time::getTimeRaw();
if (empty($this->releaseTimes[$id]) || $this->releaseTimes[$id] < $nowEpoch) {
$this->releaseTimes[$id] = $nowEpoch + $leaseTime;
$item = new stdClass();
$item->id = $id;
$item->data = unserialize($data);
return $item;
}
else {
// item in queue is reserved
return FALSE;
}
}
// nothing in queue
return FALSE;
}
/**
* Get the next item.
*
* @param int $leaseTime
* Seconds.
*
* @return object
* With key 'data' that matches the inputted data.
*/
public function stealItem($leaseTime = 3600) {
// foreach hits the items in order -- but we short-circuit after the first
foreach ($this->items as $id => $data) {
$nowEpoch = CRM_Utils_Time::getTimeRaw();
$this->releaseTimes[$id] = $nowEpoch + $leaseTime;
$item = new stdClass();
$item->id = $id;
$item->data = unserialize($data);
return $item;
}
// nothing in queue
return FALSE;
}
/**
* Remove an item from the queue.
*
* @param object $item
* The item returned by claimItem.
*/
public function deleteItem($item) {
unset($this->items[$item->id]);
unset($this->releaseTimes[$item->id]);
}
/**
* Return an item that could not be processed.
*
* @param CRM_Core_DAO $item
* The item returned by claimItem.
*/
public function releaseItem($item) {
unset($this->releaseTimes[$item->id]);
}
}

View file

@ -0,0 +1,220 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
* A queue implementation which stores items in the CiviCRM SQL database
*/
class CRM_Queue_Queue_Sql extends CRM_Queue_Queue {
/**
* Create a reference to queue. After constructing the queue, one should
* usually call createQueue (if it's a new queue) or loadQueue (if it's
* known to be an existing queue).
*
* @param array $queueSpec
* Array with keys:
* - type: string, required, e.g. "interactive", "immediate", "stomp",
* "beanstalk"
* - name: string, required, e.g. "upgrade-tasks"
* - reset: bool, optional; if a queue is found, then it should be
* flushed; default to TRUE
* - (additional keys depending on the queue provider).
*/
public function __construct($queueSpec) {
parent::__construct($queueSpec);
}
/**
* Perform any registation or resource-allocation for a new queue
*/
public function createQueue() {
// nothing to do -- just start CRUDing items in the appropriate table
}
/**
* Perform any loading or pre-fetch for an existing queue.
*/
public function loadQueue() {
// nothing to do -- just start CRUDing items in the appropriate table
}
/**
* Release any resources claimed by the queue (memory, DB rows, etc)
*/
public function deleteQueue() {
return CRM_Core_DAO::singleValueQuery("
DELETE FROM civicrm_queue_item
WHERE queue_name = %1
", array(
1 => array($this->getName(), 'String'),
));
}
/**
* Check if the queue exists.
*
* @return bool
*/
public function existsQueue() {
return ($this->numberOfItems() > 0);
}
/**
* Add a new item to the queue.
*
* @param mixed $data
* Serializable PHP object or array.
* @param array $options
* Queue-dependent options; for example, if this is a
* priority-queue, then $options might specify the item's priority.
*/
public function createItem($data, $options = array()) {
$dao = new CRM_Queue_DAO_QueueItem();
$dao->queue_name = $this->getName();
$dao->submit_time = CRM_Utils_Time::getTime('YmdHis');
$dao->data = serialize($data);
$dao->weight = CRM_Utils_Array::value('weight', $options, 0);
$dao->save();
}
/**
* Determine number of items remaining in the queue.
*
* @return int
*/
public function numberOfItems() {
return CRM_Core_DAO::singleValueQuery("
SELECT count(*)
FROM civicrm_queue_item
WHERE queue_name = %1
", array(
1 => array($this->getName(), 'String'),
));
}
/**
* Get the next item.
*
* @param int $lease_time
* Seconds.
*
* @return object
* With key 'data' that matches the inputted data.
*/
public function claimItem($lease_time = 3600) {
$sql = "
SELECT id, queue_name, submit_time, release_time, data
FROM civicrm_queue_item
WHERE queue_name = %1
ORDER BY weight ASC, id ASC
LIMIT 1
";
$params = array(
1 => array($this->getName(), 'String'),
);
$dao = CRM_Core_DAO::executeQuery($sql, $params, TRUE, 'CRM_Queue_DAO_QueueItem');
if (is_a($dao, 'DB_Error')) {
// FIXME - Adding code to allow tests to pass
CRM_Core_Error::fatal();
}
if ($dao->fetch()) {
$nowEpoch = CRM_Utils_Time::getTimeRaw();
if ($dao->release_time === NULL || strtotime($dao->release_time) < $nowEpoch) {
CRM_Core_DAO::executeQuery("UPDATE civicrm_queue_item SET release_time = %1 WHERE id = %2", array(
'1' => array(date('YmdHis', $nowEpoch + $lease_time), 'String'),
'2' => array($dao->id, 'Integer'),
));
// work-around: inconsistent date-formatting causes unintentional breakage
# $dao->submit_time = date('YmdHis', strtotime($dao->submit_time));
# $dao->release_time = date('YmdHis', $nowEpoch + $lease_time);
# $dao->save();
$dao->data = unserialize($dao->data);
return $dao;
}
}
}
/**
* Get the next item, even if there's an active lease
*
* @param int $lease_time
* Seconds.
*
* @return object
* With key 'data' that matches the inputted data.
*/
public function stealItem($lease_time = 3600) {
$sql = "
SELECT id, queue_name, submit_time, release_time, data
FROM civicrm_queue_item
WHERE queue_name = %1
ORDER BY weight ASC, id ASC
LIMIT 1
";
$params = array(
1 => array($this->getName(), 'String'),
);
$dao = CRM_Core_DAO::executeQuery($sql, $params, TRUE, 'CRM_Queue_DAO_QueueItem');
if ($dao->fetch()) {
$nowEpoch = CRM_Utils_Time::getTimeRaw();
CRM_Core_DAO::executeQuery("UPDATE civicrm_queue_item SET release_time = %1 WHERE id = %2", array(
'1' => array(date('YmdHis', $nowEpoch + $lease_time), 'String'),
'2' => array($dao->id, 'Integer'),
));
$dao->data = unserialize($dao->data);
return $dao;
}
}
/**
* Remove an item from the queue.
*
* @param CRM_Core_DAO $dao
* The item returned by claimItem.
*/
public function deleteItem($dao) {
$dao->delete();
$dao->free();
}
/**
* Return an item that could not be processed.
*
* @param CRM_Core_DAO $dao
* The item returned by claimItem.
*/
public function releaseItem($dao) {
$sql = "UPDATE civicrm_queue_item SET release_time = NULL WHERE id = %1";
$params = array(
1 => array($dao->id, 'Integer'),
);
CRM_Core_DAO::executeQuery($sql, $params);
$dao->free();
}
}

View file

@ -0,0 +1,365 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
* The queue runner is a helper which runs all jobs in a queue.
*
* The queue runner is most useful for one-off queues (such as an upgrade);
* if the intention is to develop a dedicated, long-running worker thread,
* then one should consider writing a new queue consumer.
*/
class CRM_Queue_Runner {
/**
* The failed task should be discarded, and queue processing should continue.
*/
const ERROR_CONTINUE = 1;
/**
* The failed task should be kept in the queue, and queue processing should
* abort.
*/
const ERROR_ABORT = 2;
/**
* @var string
*/
public $title;
/**
* @var CRM_Queue_Queue
*/
public $queue;
public $errorMode;
public $isMinimal;
public $onEnd;
public $onEndUrl;
public $pathPrefix;
// queue-runner id; used for persistence
public $qrid;
/**
* @var array whether to display buttons, eg ('retry' => TRUE, 'skip' => FALSE)
*/
public $buttons;
/**
* @var CRM_Queue_TaskContext
*/
public $taskCtx;
/**
* Locate a previously-created instance of the queue-runner.
*
* @param string $qrid
* The queue-runner ID.
*
* @return CRM_Queue_Runner|NULL
*/
public static function instance($qrid) {
if (!empty($_SESSION['queueRunners'][$qrid])) {
return unserialize($_SESSION['queueRunners'][$qrid]);
}
else {
return NULL;
}
}
/**
*
* FIXME: parameter validation
* FIXME: document signature of onEnd callback
*
* @param array $runnerSpec
* Array with keys:
* - queue: CRM_Queue_Queue
* - errorMode: int, ERROR_CONTINUE or ERROR_ABORT.
* - onEnd: mixed, a callback to update the UI after running; should be
* both callable and serializable.
* - onEndUrl: string, the URL to which one redirects.
* - pathPrefix: string, prepended to URLs for the web-runner;
* default: 'civicrm/queue'.
*/
public function __construct($runnerSpec) {
$this->title = CRM_Utils_Array::value('title', $runnerSpec, ts('Queue Runner'));
$this->queue = $runnerSpec['queue'];
$this->errorMode = CRM_Utils_Array::value('errorMode', $runnerSpec, self::ERROR_ABORT);
$this->isMinimal = CRM_Utils_Array::value('isMinimal', $runnerSpec, FALSE);
$this->onEnd = CRM_Utils_Array::value('onEnd', $runnerSpec, NULL);
$this->onEndUrl = CRM_Utils_Array::value('onEndUrl', $runnerSpec, NULL);
$this->pathPrefix = CRM_Utils_Array::value('pathPrefix', $runnerSpec, 'civicrm/queue');
$this->buttons = CRM_Utils_Array::value('buttons', $runnerSpec, array('retry' => TRUE, 'skip' => TRUE));
// perhaps this value should be randomized?
$this->qrid = $this->queue->getName();
}
/**
* @return array
*/
public function __sleep() {
// exclude taskCtx
return array(
'title',
'queue',
'errorMode',
'isMinimal',
'onEnd',
'onEndUrl',
'pathPrefix',
'qrid',
'buttons',
);
}
/**
* Redirect to the web-based queue-runner and evaluate all tasks in a queue.
*/
public function runAllViaWeb() {
$_SESSION['queueRunners'][$this->qrid] = serialize($this);
$url = CRM_Utils_System::url($this->pathPrefix . '/runner', 'reset=1&qrid=' . urlencode($this->qrid));
CRM_Utils_System::redirect($url);
// TODO: evaluate items incrementally via AJAX polling, cleanup session
}
/**
* Immediately run all tasks in a queue (until either reaching the end
* of the queue or encountering an error)
*
* If the runner has an onEndUrl, then this function will not return
*
* @return mixed
* TRUE if all tasks complete normally; otherwise, an array describing the
* failed task
*/
public function runAll() {
$taskResult = $this->formatTaskResult(TRUE);
while ($taskResult['is_continue']) {
// setRaiseException should't be necessary here, but there's a bug
// somewhere which causes this setting to be lost. Observed while
// upgrading 4.0=>4.2. This preference really shouldn't be a global
// setting -- it should be more of a contextual/stack-based setting.
// This should be appropriate because queue-runners are not used with
// basic web pages -- they're used with CLI/REST/AJAX.
$errorScope = CRM_Core_TemporaryErrorScope::useException();
$taskResult = $this->runNext();
$errorScope = NULL;
}
if ($taskResult['numberOfItems'] == 0) {
$result = $this->handleEnd();
if (!empty($result['redirect_url'])) {
CRM_Utils_System::redirect($result['redirect_url']);
}
return TRUE;
}
else {
return $taskResult;
}
}
/**
* Take the next item from the queue and attempt to run it.
*
* Individual tasks may also throw exceptions -- caller should watch for
* exceptions.
*
* @param bool $useSteal
* Whether to steal active locks.
*
* @return array
* - is_error => bool,
* - is_continue => bool,
* - numberOfItems => int,
* - 'last_task_title' => $,
* - 'exception' => $
*/
public function runNext($useSteal = FALSE) {
if ($useSteal) {
$item = $this->queue->stealItem();
}
else {
$item = $this->queue->claimItem();
}
if ($item) {
$this->lastTaskTitle = $item->data->title;
$exception = NULL;
try {
CRM_Core_Error::debug_log_message("Running task: " . $this->lastTaskTitle);
$isOK = $item->data->run($this->getTaskContext());
if (!$isOK) {
$exception = new Exception('Task returned false');
}
}
catch (Exception$e) {
$isOK = FALSE;
$exception = $e;
}
if ($isOK) {
$this->queue->deleteItem($item);
}
else {
$this->releaseErrorItem($item);
}
return $this->formatTaskResult($isOK, $exception);
}
else {
return $this->formatTaskResult(FALSE, new Exception('Failed to claim next task'));
}
}
/**
* Take the next item from the queue and attempt to run it.
*
* Individual tasks may also throw exceptions -- caller should watch for
* exceptions.
*
* @param bool $useSteal
* Whether to steal active locks.
*
* @return array
* - is_error => bool,
* - is_continue => bool,
* - numberOfItems => int)
*/
public function skipNext($useSteal = FALSE) {
if ($useSteal) {
$item = $this->queue->stealItem();
}
else {
$item = $this->queue->claimItem();
}
if ($item) {
$this->lastTaskTitle = $item->data->title;
$this->queue->deleteItem($item);
return $this->formatTaskResult(TRUE);
}
else {
return $this->formatTaskResult(FALSE, new Exception('Failed to claim next task'));
}
}
/**
* Release an item in keeping with the error mode.
*
* @param object $item
* The item previously produced by Queue::claimItem.
*/
protected function releaseErrorItem($item) {
switch ($this->errorMode) {
case self::ERROR_CONTINUE:
$this->queue->deleteItem($item);
case self::ERROR_ABORT:
default:
$this->queue->releaseItem($item);
}
}
/**
* @return array
* - is_error => bool,
* - is_continue => bool,
* - numberOfItems => int,
* - redirect_url => string
*/
public function handleEnd() {
if (is_callable($this->onEnd)) {
call_user_func($this->onEnd, $this->getTaskContext());
}
// Don't remove queueRunner until onEnd succeeds
if (!empty($_SESSION['queueRunners'][$this->qrid])) {
unset($_SESSION['queueRunners'][$this->qrid]);
}
// Fallback; web UI does redirect in Javascript
$result = array();
$result['is_error'] = 0;
$result['numberOfItems'] = 0;
$result['is_continue'] = 0;
if (!empty($this->onEndUrl)) {
$result['redirect_url'] = $this->onEndUrl;
}
return $result;
}
/**
* Format a result record which describes whether the task completed.
*
* @param bool $isOK
* TRUE if the task completed successfully.
* @param Exception|NULL $exception
* If applicable, an unhandled exception that arose during execution.
*
* @return array
* (is_error => bool, is_continue => bool, numberOfItems => int)
*/
public function formatTaskResult($isOK, $exception = NULL) {
$numberOfItems = $this->queue->numberOfItems();
$result = array();
$result['is_error'] = $isOK ? 0 : 1;
$result['exception'] = $exception;
$result['last_task_title'] = isset($this->lastTaskTitle) ? $this->lastTaskTitle : '';
$result['numberOfItems'] = $this->queue->numberOfItems();
if ($result['numberOfItems'] <= 0) {
// nothing to do
$result['is_continue'] = 0;
}
elseif ($isOK) {
// more tasks remain, and this task succeeded
$result['is_continue'] = 1;
}
elseif ($this->errorMode == CRM_Queue_Runner::ERROR_CONTINUE) {
// more tasks remain, and we can disregard this error
$result['is_continue'] = 1;
}
else {
// more tasks remain, but we can't disregard the error
$result['is_continue'] = 0;
}
return $result;
}
/**
* @return CRM_Queue_TaskContext
*/
protected function getTaskContext() {
if (!is_object($this->taskCtx)) {
$this->taskCtx = new CRM_Queue_TaskContext();
$this->taskCtx->queue = $this->queue;
// $this->taskCtx->log = CRM_Core_Config::getLog();
$this->taskCtx->log = CRM_Core_Error::createDebugLogger();
}
return $this->taskCtx;
}
}

View file

@ -0,0 +1,172 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
* The queue service provides an interface for creating or locating
* queues. Note that this approach hides the details of data-storage:
* different queue-providers may store the queue content in different
* ways (in memory, in SQL, or in an external service).
*
* @code
* $queue = CRM_Queue_Service::singleton()->create(array(
* 'type' => 'interactive',
* 'name' => 'upgrade-tasks',
* ));
* $queue->createItem($myData);
*
* // Some time later...
* $item = $queue->claimItem();
* if ($item) {
* if (my_process($item->data)) {
* $queue->deleteItem($item);
* } else {
* $queue->releaseItem($item);
* }
* }
* @endcode
*/
class CRM_Queue_Service {
protected static $_singleton;
/**
* FIXME: Singleton pattern should be removed when dependency-injection
* becomes available.
*
* @param bool $forceNew
* TRUE if a new instance must be created.
*
* @return \CRM_Queue_Service
*/
public static function &singleton($forceNew = FALSE) {
if ($forceNew || !self::$_singleton) {
self::$_singleton = new CRM_Queue_Service();
}
return self::$_singleton;
}
/**
* @var array (string $queueName => CRM_Queue_Queue)
*/
public $queues;
/**
*/
public function __construct() {
$this->queues = array();
}
/**
* Create a queue. If one already exists, then it will be reused.
*
* @param array $queueSpec
* Array with keys:
* - type: string, required, e.g. "interactive", "immediate", "stomp",
* "beanstalk"
* - name: string, required, e.g. "upgrade-tasks"
* - reset: bool, optional; if a queue is found, then it should be
* flushed; default to TRUE
* - (additional keys depending on the queue provider).
*
* @return CRM_Queue_Queue
*/
public function create($queueSpec) {
if (@is_object($this->queues[$queueSpec['name']]) && empty($queueSpec['reset'])) {
return $this->queues[$queueSpec['name']];
}
$queue = $this->instantiateQueueObject($queueSpec);
$exists = $queue->existsQueue();
if (!$exists) {
$queue->createQueue();
}
elseif (@$queueSpec['reset']) {
$queue->deleteQueue();
$queue->createQueue();
}
else {
$queue->loadQueue();
}
$this->queues[$queueSpec['name']] = $queue;
return $queue;
}
/**
* Look up an existing queue.
*
* @param array $queueSpec
* Array with keys:
* - type: string, required, e.g. "interactive", "immediate", "stomp",
* "beanstalk"
* - name: string, required, e.g. "upgrade-tasks"
* - (additional keys depending on the queue provider).
*
* @return CRM_Queue_Queue
*/
public function load($queueSpec) {
if (is_object($this->queues[$queueSpec['name']])) {
return $this->queues[$queueSpec['name']];
}
$queue = $this->instantiateQueueObject($queueSpec);
$queue->loadQueue();
$this->queues[$queueSpec['name']] = $queue;
return $queue;
}
/**
* Convert a queue "type" name to a class name.
*
* @param string $type
* E.g. "interactive", "immediate", "stomp", "beanstalk".
*
* @return string
* Class-name
*/
protected function getQueueClass($type) {
$type = preg_replace('/[^a-zA-Z0-9]/', '', $type);
$className = 'CRM_Queue_Queue_' . $type;
// FIXME: when used with class-autoloader, this may be unnecessary
if (!class_exists($className)) {
$classFile = 'CRM/Queue/Queue/' . $type . '.php';
require_once $classFile;
}
return $className;
}
/**
* @param array $queueSpec
* See create().
*
* @return CRM_Queue_Queue
*/
protected function instantiateQueueObject($queueSpec) {
// note: you should probably never do anything else here
$class = new ReflectionClass($this->getQueueClass($queueSpec['type']));
return $class->newInstance($queueSpec);
}
}

View file

@ -0,0 +1,96 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
* A task is an item that can be enqueued and later executed
*/
class CRM_Queue_Task {
/**
* Task was performed successfully.
*/
const TASK_SUCCESS = 1;
/**
* Task failed and should not be retried.
*/
const TASK_FAIL = 2;
/**
* @var mixed, serializable
*/
public $callback;
/**
* @var array, serializable
*/
public $arguments;
/**
* @var string, NULL-able
*/
public $title;
/**
* @param mixed $callback
* Serializable, a callable PHP item; must accept at least one argument
* (CRM_Queue_TaskContext).
* @param array $arguments
* Serializable, extra arguments to pass to the callback (in order).
* @param string $title
* A printable string which describes this task.
*/
public function __construct($callback, $arguments, $title = NULL) {
$this->callback = $callback;
$this->arguments = $arguments;
$this->title = $title;
}
/**
* Perform the task.
*
* @param array $taskCtx
* Array with keys:
* - log: object 'Log'
*
* @throws Exception
* @return bool, TRUE if task completes successfully
*/
public function run($taskCtx) {
$args = $this->arguments;
array_unshift($args, $taskCtx);
if (is_callable($this->callback)) {
$result = call_user_func_array($this->callback, $args);
return $result;
}
else {
throw new Exception('Failed to call callback: ' . print_r($this->callback));
}
}
}

View file

@ -0,0 +1,43 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
* Describe the runtime environment in which a queue task executes
*/
class CRM_Queue_TaskContext {
/**
* @var CRM_Queue_Queue
*/
public $queue;
/**
* @var Log
*/
public $log;
}