Commit a2e9dd30 authored by bgm's avatar bgm Committed by Aegir user

infra/ops#919 Upgrade civirules

parent f93b4fb1
# CHANGELOG
## Version 2.12 (not yet released)
## Version 2.11
* Added action to create relationships.
* Added action to create a membership
* Added action to set financial type of a contribution
* Added condition to check whether a contribution is a recurring contribution
* fixed issue #53 (https://lab.civicrm.org/extensions/civirules/issues/53)
* fixed issue #46 (the is empty condition on the field value comparison is broken)
* fixed issue #59 (added triggers for campaign and condition campaign type)
## Version 2.10
* Added clone butten to the edit rule screen, so you can copy and change only what needs changing (#29)
* Added configuration for the record type for Activity and Case Activity trigger.
* Fixed bug in Activity and Case Activity trigger with an empty contact id.
* Added action to set Case Role
* Added trigger for new UFMatch record (link with CMS user is added)
* Removed the Case Added trigger as it causes errors (check https://lab.civicrm.org/extensions/civirules/issues/45). To do stuff when a new case is added use the Case Activity Added trigger instead with activity type Open Case. During the upgrade all existing rules based on the Case Added trigger will be deleted! They need to be recreated manually with the Case Activity is added trigger with activity type Open Case.
* Added condition Compare old participant status to new participant status
## Version 2.9
* Adds new action: update participant status
* Refactored the way triggers, actions and conditions are inserted in the database upon installation (#24).
* Fixed the fatal error after copying a profile (#19).
* Fixed php warning in CRM_CivirulesConditions_Contact_AgeComparison
* Fixed Cancel button on Rule form returns to "random" page (now it returns to rule overview)
* Fixed uncorrect behavior of isConditionValid with empty value (now returns FALSE)
* Fixed issue 40 (https://lab.civicrm.org/extensions/civirules/issues/40) where the fresh install SQL scripts still create tables with CONSTRAINT ON DELETE RESTRICT rather than ON DELETE CASCADE. There is an upgrade action (2025) linked to this fix which will remove the current constraints on tables civirule_rule_action, civirule_rule_condition and civirule_rule_tag and replace them with CONSTRAINT ON DELETE CASCADE and ON UPDATE RESTRICT.
* Introduces the option to take child groups into consideration for the condition 'contact is (not) in group'.
## Version 2.8
* "Set Thank You Date for a Contribution" action now supports options for time as well as date.
* Added trigger for Event Date reached.
* Added option to compare with original value in Field Value Comparison condition
* Add a condition for contacts being within a specific domain. This is useful for multisite installations as it allows rules to only be executed on contacts that are within that domain's domain_group_id
## Version 2.7
* Changed the ON DELETE NO ACTION to ON DELETE CASCADE for the constraints for tables civirule_rule_action, civirule_rule_condition, civirule_rule_tag which fixes #8
* Fixed notices and warnings on isRuleOnQueue method
* Add "show disabled rules" checkbox on filter for Manage Rules
## Version 2.6
REQUIRES MENU REBUILD! (/civicrm/clearcache)
* Added a trigger for membership end date
* Replaced the Find Rules custom search with a Manage Rules form
......@@ -7,6 +7,8 @@
*/
class CRM_Civirules_BAO_Rule extends CRM_Civirules_DAO_Rule {
private static $ruleCache = [];
/**
* Function to get values
*
......@@ -50,7 +52,7 @@ class CRM_Civirules_BAO_Rule extends CRM_Civirules_DAO_Rule {
public static function add($params) {
$result = array();
if (empty($params)) {
throw new Exception('Params can not be empty when adding or updating a civirule rule');
throw new Exception(ts('Params can not be empty when adding or updating a civirule rule'));
}
if (!empty($params['id'])) {
......@@ -95,71 +97,21 @@ class CRM_Civirules_BAO_Rule extends CRM_Civirules_DAO_Rule {
*/
public static function deleteWithId($ruleId) {
if (empty($ruleId)) {
throw new Exception('rule id can not be empty when attempting to delete a civirule rule');
throw new Exception(ts('rule id can not be empty when attempting to delete a civirule rule'));
}
CRM_Utils_Hook::pre('delete', 'CiviRuleRule', $ruleId, CRM_Core_DAO::$_nullArray);
// catch errors because rule might not have conditions or actions
try {
CRM_Civirules_BAO_RuleAction::deleteWithRuleId($ruleId);
CRM_Civirules_BAO_RuleCondition::deleteWithRuleId($ruleId);
CRM_Civirules_BAO_RuleTag::deleteWithRuleId($ruleId);
}
catch (Exception $ex) {
}
// also delete all references to the rule from logging if present
if (self::checkTableExists('civirule_rule_log')) {
$query = 'DELETE FROM civirule_rule_log WHERE rule_id = %1';
CRM_Core_DAO::executeQuery($query, array(1 => array($ruleId, 'Integer')));
CRM_Core_DAO::executeQuery($query, [1 => [$ruleId, 'Integer']]);
}
$rule = new CRM_Civirules_BAO_Rule();
$rule->id = $ruleId;
$rule->delete();
CRM_Utils_Hook::post('delete', 'CiviRuleRule', $ruleId, CRM_Core_DAO::$_nullArray);
return;
}
/**
* Function to disable a rule
*
* @param int $ruleId
* @throws Exception when ruleId is empty
* @access public
* @static
*/
public static function disable($ruleId) {
if (empty($ruleId)) {
throw new Exception('rule id can not be empty when attempting to disable a civirule rule');
}
$rule = new CRM_Civirules_BAO_Rule();
$rule->id = $ruleId;
$rule->find(true);
self::add(array('id' => $rule->id, 'is_active' => 0));
}
/**
* Function to enable an rule
*
* @param int $ruleId
* @throws Exception when ruleId is empty
* @access public
* @static
*/
public static function enable($ruleId) {
if (empty($ruleId)) {
throw new Exception('rule id can not be empty when attempting to enable a civirule rule');
}
$rule = new CRM_Civirules_BAO_Rule();
$rule->id = $ruleId;
$rule->find(true);
self::add(array('id' => $rule->id, 'is_active' => 1));
}
/**
* Function to retrieve the label of a rule with ruleId
*
......@@ -202,26 +154,26 @@ class CRM_Civirules_BAO_Rule extends CRM_Civirules_DAO_Rule {
* @param string $op op in the Post hook
* @return array
*/
public static function findRulesByObjectNameAndOp($objectName, $op)
{
$triggers = array();
public static function findRulesByObjectNameAndOp($objectName, $op) {
$triggers = [];
$sql = "SELECT r.id AS rule_id, t.id AS trigger_id, t.class_name, r.trigger_params
FROM `civirule_rule` r
INNER JOIN `civirule_trigger` t ON r.trigger_id = t.id AND t.is_active = 1";
// If $objectName is a Contact Type, also search for "Contact".
if ($objectName == 'Individual' || $objectName == 'Organization' || $objectName == 'Household') {
$sqlWhere = " WHERE r.`is_active` = 1 AND t.cron = 0 AND (t.object_name = %1 OR t.object_name = 'Contact') AND t.op = %2";
} else {
}
else {
$sqlWhere = " WHERE r.`is_active` = 1 AND t.cron = 0 AND t.object_name = %1 AND t.op = %2";
}
$sql .= $sqlWhere;
$params[1] = array($objectName, 'String');
$params[2] = array($op, 'String');
$params[1] = [$objectName, 'String'];
$params[2] = [$op, 'String'];
$dao = CRM_Core_DAO::executeQuery($sql, $params);
while ($dao->fetch()) {
$triggerObject = CRM_Civirules_BAO_Trigger::getPostTriggerObjectByClassName($dao->class_name, false);
if ($triggerObject !== false) {
$triggerObject = CRM_Civirules_BAO_Trigger::getPostTriggerObjectByClassName($dao->class_name, FALSE);
if ($triggerObject !== FALSE) {
$triggerObject->setTriggerId($dao->trigger_id);
$triggerObject->setRuleId($dao->rule_id);
$triggerObject->setTriggerParams($dao->trigger_params);
......@@ -238,7 +190,7 @@ class CRM_Civirules_BAO_Rule extends CRM_Civirules_DAO_Rule {
*/
public static function findRulesForCron()
{
$cronTriggers = array();
$cronTriggers = [];
$sql = "SELECT r.id AS rule_id, t.id AS trigger_id, t.class_name, r.trigger_params
FROM `civirule_rule` r
INNER JOIN `civirule_trigger` t ON r.trigger_id = t.id AND t.is_active = 1
......@@ -246,8 +198,8 @@ class CRM_Civirules_BAO_Rule extends CRM_Civirules_DAO_Rule {
$dao = CRM_Core_DAO::executeQuery($sql);
while ($dao->fetch()) {
$cronTriggerObject = CRM_Civirules_BAO_Trigger::getTriggerObjectByClassName($dao->class_name, false);
if ($cronTriggerObject !== false) {
$cronTriggerObject = CRM_Civirules_BAO_Trigger::getTriggerObjectByClassName($dao->class_name, FALSE);
if ($cronTriggerObject !== FALSE) {
$cronTriggerObject->setTriggerId($dao->trigger_id);
$cronTriggerObject->setRuleId($dao->rule_id);
$cronTriggerObject->setTriggerParams($dao->trigger_params);
......@@ -264,16 +216,16 @@ class CRM_Civirules_BAO_Rule extends CRM_Civirules_DAO_Rule {
*/
public static function findRulesByClassname($classname)
{
$triggers = array();
$triggers = [];
$sql = "SELECT r.id AS rule_id, t.id AS trigger_id, t.class_name, r.trigger_params
FROM `civirule_rule` r
INNER JOIN `civirule_trigger` t ON r.trigger_id = t.id AND t.is_active = 1
WHERE r.`is_active` = 1 AND t.class_name = %1";
$params[1] = array($classname, 'String');
$params[1] = [$classname, 'String'];
$dao = CRM_Core_DAO::executeQuery($sql, $params);
while ($dao->fetch()) {
$triggerObject = CRM_Civirules_BAO_Trigger::getTriggerObjectByClassName($dao->class_name, false);
if ($triggerObject !== false) {
$triggerObject = CRM_Civirules_BAO_Trigger::getTriggerObjectByClassName($dao->class_name, FALSE);
if ($triggerObject !== FALSE) {
$triggerObject->setTriggerId($dao->trigger_id);
$triggerObject->setRuleId($dao->rule_id);
$triggerObject->setTriggerParams($dao->trigger_params);
......@@ -310,15 +262,15 @@ class CRM_Civirules_BAO_Rule extends CRM_Civirules_DAO_Rule {
*/
public static function getRuleIdsByTriggerId($triggerId) {
if (!is_numeric($triggerId)) {
throw new Exception('You are passing a trigger id as a parameter into '.__METHOD__
.' which does not pass the PHP is_numeric test. An integer is required (only numbers allowed)! Contact your system administrator');
throw new Exception(ts('You are passing a trigger id as a parameter into ') . __METHOD__
. ts(' which does not pass the PHP is_numeric test. An integer is required (only numbers allowed)! Contact your system administrator'));
}
$ruleIds = array();
$ruleIds = [];
$sql = 'SELECT id FROM civirule_rule WHERE trigger_id = %1 AND is_active = %2';
$params = array(
1 => array($triggerId, 'Integer'),
2 => array(1, 'Integer')
);
$params = [
1 => [$triggerId, 'Integer'],
2 => [1, 'Integer']
];
$dao = CRM_Core_DAO::executeQuery($sql, $params);
while ($dao->fetch()) {
$ruleIds[] = $dao->id;
......@@ -334,14 +286,16 @@ class CRM_Civirules_BAO_Rule extends CRM_Civirules_DAO_Rule {
*/
public static function isRuleOnQueue($ruleId) {
$query = "SELECT * FROM civicrm_queue_item WHERE queue_name = %1";
$dao = CRM_Core_DAO::executeQuery($query, array(1 => array("org.civicoop.civirules.action", "String")));
$dao = CRM_Core_DAO::executeQuery($query, [1 => ["org.civicoop.civirules.action", "String"]]);
while ($dao->fetch()) {
if (isset($dao->data)) {
$queueItemData = unserialize($dao->data);
foreach($queueItemData->arguments as $dataArgument) {
if (is_subclass_of($dataArgument, 'CRM_Civirules_Action')) {
if ($dataArgument->getRuleId() == $ruleId) {
return TRUE;
$queueItemData = @unserialize($dao->data);
if ($queueItemData) {
foreach($queueItemData->arguments as $dataArgument) {
if (is_subclass_of($dataArgument, 'CRM_Civirules_Action')) {
if ($dataArgument->getRuleId() == $ruleId) {
return TRUE;
}
}
}
}
......@@ -349,4 +303,4 @@ class CRM_Civirules_BAO_Rule extends CRM_Civirules_DAO_Rule {
}
return FALSE;
}
}
\ No newline at end of file
}
......@@ -93,8 +93,13 @@ class CRM_Civirules_BAO_RuleTag extends CRM_Civirules_DAO_RuleTag {
public static function deleteWithRuleId($ruleId) {
$ruleTag = new CRM_Civirules_BAO_RuleTag();
$ruleTag->rule_id = $ruleId;
$ruleTag->find(false);
$ruleTagIds = [];
$ruleTag->find();
while ($ruleTag->fetch()) {
$ruleTagIds[] = $ruleTag->id;
}
foreach ($ruleTagIds as $ruleTagId) {
$ruleTag->id = $ruleTagId;
$ruleTag->delete();
}
}
......
......@@ -67,15 +67,18 @@ class CRM_Civirules_Engine {
* @access protected
* @static
*/
public static function executeAction(CRM_Civirules_TriggerData_TriggerData $triggerData, $ruleAction) {
public static function executeAction(CRM_Civirules_TriggerData_TriggerData &$triggerData, $ruleAction) {
$actionEngine = CRM_Civirules_ActionEngine_Factory::getEngine($ruleAction, $triggerData);
//determine if the action should be executed with a delay
$delay = self::getActionDelay($ruleAction, $actionEngine);
if ($delay instanceof DateTime) {
$triggerData->isDelayedExecution = TRUE;
$triggerData->delayedSubmitDateTime = CRM_Utils_Time::getTime('YmdHis');
self::delayAction($delay, $actionEngine);
} else {
//there is no delay so process action immediatly
$triggerData->isDelayedExecution = FALSE;
$actionEngine->execute();
}
}
......
......@@ -3,14 +3,14 @@
* Form controller class to manage CiviRule/Rule
*
* @see http://wiki.civicrm.org/confluence/display/CRMDOC43/QuickForm+Reference
*
*
* @author Erik Hommel (CiviCooP) <erik.hommel@civicoop.org>
* @license http://www.gnu.org/licenses/agpl-3.0.html
*/
require_once 'CRM/Core/Form.php';
class CRM_Civirules_Form_Rule extends CRM_Core_Form {
protected $ruleId = NULL;
protected $rule;
......@@ -26,7 +26,7 @@ class CRM_Civirules_Form_Rule extends CRM_Core_Form {
/**
* Function to buildQuickForm (extends parent function)
*
*
* @access public
*/
function buildQuickForm() {
......@@ -59,10 +59,14 @@ class CRM_Civirules_Form_Rule extends CRM_Core_Form {
/**
* Function to perform processing before displaying form (overrides parent function)
*
*
* @access public
*/
function preProcess() {
// make sure Cancel returns to the overview
$session = CRM_Core_Session::singleton();
$session->pushUserContext(CRM_Utils_System::url('civicrm/civirules/form/rulesview', 'reset=1'));
$this->ruleId = CRM_Utils_Request::retrieve('id', 'Integer');
$this->rule = new CRM_Civirules_BAO_Rule();
......@@ -97,38 +101,41 @@ class CRM_Civirules_Form_Rule extends CRM_Core_Form {
$this->assign('action', $this->_action);
$this->assign('rule', $this->rule);
$session = CRM_Core_Session::singleton();
switch($this->_action) {
case CRM_Core_Action::DISABLE:
CRM_Civirules_BAO_Rule::disable($this->ruleId);
$session->setStatus('CiviRule disabled', 'Disable', 'success');
CRM_Utils_System::redirect($session->readUserContext());
break;
case CRM_Core_Action::ENABLE:
CRM_Civirules_BAO_Rule::enable($this->ruleId);
$session->setStatus('CiviRule enabled', 'Enable', 'success');
CRM_Utils_System::redirect($session->readUserContext());
break;
if ($this->_action == CRM_Core_Action::UPDATE) {
$clones = civicrm_api3('CiviRuleRule', 'getclones', [
'id' => $this->ruleId,
]);
if ($clones['count'] > 0) {
$cloneLabels = [];
foreach ($clones['values'] as $key => $clone) {
$cloneLabels[$key] = $clone['label'];
}
$this->assign('clones', implode(',', $cloneLabels));
}
}
}
/**
* Function to perform post save processing (extends parent function)
*
*
* @access public
*/
function postProcess() {
$session = CRM_Core_Session::singleton();
$userId = $session->get('userID');
if ($this->_action == CRM_Core_Action::DELETE) {
CRM_Civirules_BAO_Rule::deleteWithId($this->ruleId);
$session->setStatus('CiviRule deleted', 'Delete', 'success');
CRM_Utils_System::redirect($session->readUserContext());
if (isset($this->_submitValues['_qf_Rule_next_clone'])) {
$result = civicrm_api3('CiviRuleRule', 'clone', [
'id' => $this->ruleId,
]);
$this->ruleId = $result['values']['clone_id'];