From 6d5661196e5320e80b0ba32d4852e963a540e0d5 Mon Sep 17 00:00:00 2001
From: Jaap Jansma <jaap@edeveloper.nl>
Date: Thu, 12 Mar 2015 15:54:45 +0100
Subject: [PATCH] update cron events

---
 CRM/Civirules/BAO/Event.php         | 27 +++++++++++++++++++
 CRM/Civirules/BAO/Rule.php          | 27 ++++++++++++++++++-
 CRM/Civirules/Engine.php            | 15 +++++++++++
 CRM/Civirules/Event/Cron.php        | 42 ++++++++++++++++++++++++++++-
 CRM/Civirules/EventData/Cron.php    | 20 ++++++++++++++
 CRM/CivirulesCronEvent/Birthday.php | 42 +++++++++++++++++++++++++++++
 api/v3/Civirules/Cron.php           | 10 +++++++
 7 files changed, 181 insertions(+), 2 deletions(-)
 create mode 100644 CRM/Civirules/EventData/Cron.php
 create mode 100644 CRM/CivirulesCronEvent/Birthday.php

diff --git a/CRM/Civirules/BAO/Event.php b/CRM/Civirules/BAO/Event.php
index 33dd196..f9a0519 100755
--- a/CRM/Civirules/BAO/Event.php
+++ b/CRM/Civirules/BAO/Event.php
@@ -134,4 +134,31 @@ class CRM_Civirules_BAO_Event extends CRM_Civirules_DAO_Event {
     $event->find(true);
     return $event->label;
   }
+
+  /**
+   * Get the cron event class for this event
+   *
+   * @param $className
+   * @param bool $abort if true this function will throw an exception if class could not be instanciated
+   * @return CRM_Civirules_Event_Cron
+   * @throws Exception if abort is set to true and class does not exist or is not valid
+   */
+  public static function getCronEventObjectByClassName($className, $abort=true) {
+    if (!class_exists($className)) {
+      if ($abort) {
+
+        throw new Exception('CiviRule cron event class "' . $className . '" does not exist');
+      }
+      return false;
+    }
+
+    $object = new $className();
+    if (!$object instanceof CRM_Civirules_Event_Cron) {
+      if ($abort) {
+        throw new Exception('CiviRule cron event class "' . $className . '" is not a subclass of CRM_Civirules_Event_Cron');
+      }
+      return false;
+    }
+    return $object;
+  }
 }
\ No newline at end of file
diff --git a/CRM/Civirules/BAO/Rule.php b/CRM/Civirules/BAO/Rule.php
index 7f7442d..7614b3c 100755
--- a/CRM/Civirules/BAO/Rule.php
+++ b/CRM/Civirules/BAO/Rule.php
@@ -155,7 +155,7 @@ class CRM_Civirules_BAO_Rule extends CRM_Civirules_DAO_Rule {
   }
 
   /**
-   * Returns an array with rules which should be triggered
+   * Returns an array with rules which should be triggered imeditaly
    *
    * @param $objectName ObjectName in the Post hook
    * @param $op op in the Post hook
@@ -182,6 +182,31 @@ class CRM_Civirules_BAO_Rule extends CRM_Civirules_DAO_Rule {
     return $rules;
   }
 
+  /**
+   * Returns an array with cron events which should be triggered in the cron
+   *
+   * @return array
+   */
+  public static function findRulesForCron()
+  {
+    $rules = array();
+    $sql = "SELECT r.id AS rule_id, e.id AS event_id, e.class_name
+            FROM `civirule_rule` r
+            INNER JOIN `civirule_event` e ON r.event_id = e.id AND e.is_active = 1
+            WHERE r.`is_active` = 1 AND e.cron = 1";
+
+    $dao = CRM_Core_DAO::executeQuery($sql);
+    while ($dao->fetch()) {
+      $cronEventObject = CRM_Civirules_BAO_Event::getCronEventObjectByClassName($dao->class_name, false);
+      if ($cronEventObject !== false) {
+        $cronEventObject->setEventId($dao->event_id);
+        $cronEventObject->setRuleId($dao->rule_id);
+        $cronEvents[] = $cronEventObject;
+      }
+    }
+    return $cronEvents;
+  }
+
   /*
    * Function to get latest rule id
    *
diff --git a/CRM/Civirules/Engine.php b/CRM/Civirules/Engine.php
index 4c432ff..1af4dcf 100644
--- a/CRM/Civirules/Engine.php
+++ b/CRM/Civirules/Engine.php
@@ -18,7 +18,9 @@ class CRM_Civirules_Engine {
     $isRuleValid = self::areConditionsValid($eventData, $ruleId);
 
     if ($isRuleValid) {
+      self::logRule($eventData, $ruleId);
       self::executeActions($eventData, $ruleId);
+
     }
   }
 
@@ -84,4 +86,17 @@ class CRM_Civirules_Engine {
     return $isValid ? true : false;
   }
 
+  /**
+   * This function writes a record to the log table to indicate that this rule for this event is triggered
+   *
+   * @param CRM_Civirules_EventData_EventData $eventData
+   * @param $ruleId
+   */
+  protected static function logRule(CRM_Civirules_EventData_EventData $eventData, $ruleId) {
+    $sql = "INSERT INTO `civirule_rule_log` (`rule_id`, `contact_id`, `log_date`) VALUES (%1, %2, NOW())";
+    $params[1] = array($ruleId, 'Integer');
+    $params[2] = array($eventData->getContactId(), 'Integer');
+    CRM_Core_DAO::executeQuery($sql, $params);
+  }
+
 }
\ No newline at end of file
diff --git a/CRM/Civirules/Event/Cron.php b/CRM/Civirules/Event/Cron.php
index 793c4d9..f67f74c 100644
--- a/CRM/Civirules/Event/Cron.php
+++ b/CRM/Civirules/Event/Cron.php
@@ -1,7 +1,47 @@
 <?php
 
-class CRM_Civirules_Event_Cron {
+abstract class CRM_Civirules_Event_Cron {
 
+  protected $ruleId;
+
+  protected $eventId;
+
+  public function setRuleId($ruleId) {
+    $this->ruleId = $ruleId;
+  }
+
+  public function getRuleId() {
+    return $this->ruleId;
+  }
+
+  public function setEventId($eventId) {
+    $this->eventId = $eventId;
+  }
+
+  public function getEventId() {
+    return $this->eventId;
+  }
+
+  /**
+   * This function returns a CRM_Civirules_EventData_EventData this entity is used for triggering the rule
+   *
+   * Return false when no next entity is available
+   *
+   * @return CRM_Civirules_EventData_EventData|false
+   */
+  abstract protected function getNextEntityEventData();
+
+  /**
+   * @return int
+   */
+  public function process() {
+    $count = 0;
+    while($eventData = $this->getNextEntityEventData()) {
+      CRM_Civirules_Engine::triggerRule($eventData, $this->ruleId, $this->eventId);
+      $count ++;
+    }
+    return $count;
+  }
 
 
 }
\ No newline at end of file
diff --git a/CRM/Civirules/EventData/Cron.php b/CRM/Civirules/EventData/Cron.php
new file mode 100644
index 0000000..37e04f5
--- /dev/null
+++ b/CRM/Civirules/EventData/Cron.php
@@ -0,0 +1,20 @@
+<?php
+
+class CRM_Civirules_EventData_Cron extends CRM_Civirules_EventData_EventData {
+
+  protected $entity;
+
+  public function __construct($contactId, $entity, $data) {
+    parent::__construct();
+
+    $this->entity = $entity;
+    $this->contact_id = $contactId;
+
+    $this->setEntityData($entity, $data);
+  }
+
+  public function getEntity() {
+    return $this->entity;
+  }
+
+}
\ No newline at end of file
diff --git a/CRM/CivirulesCronEvent/Birthday.php b/CRM/CivirulesCronEvent/Birthday.php
new file mode 100644
index 0000000..317c635
--- /dev/null
+++ b/CRM/CivirulesCronEvent/Birthday.php
@@ -0,0 +1,42 @@
+<?php
+
+class CRM_CivirulesCronEvent_Birthday extends CRM_Civirules_Event_Cron {
+
+  private $dao = false;
+
+  /**
+   * This function returns a CRM_Civirules_EventData_EventData this entity is used for triggering the rule
+   *
+   * Return false when no next entity is available
+   *
+   * @return CRM_Civirules_EventData_EventData|false
+   */
+  protected function getNextEntityEventData() {
+    if (!$this->dao) {
+      $this->queryForEventEntities();
+    }
+    if ($this->dao->fetch()) {
+      $data = array();
+      CRM_Core_DAO::storeValues($this->dao, $data);
+      $eventData = new CRM_Civirules_EventData_Cron($this->dao->id, 'contact', $data);
+      return $eventData;
+    }
+    return false;
+  }
+
+  private function queryForEventEntities() {
+    $sql = "SELECT c.*
+            FROM `civicrm_contact` `c`
+            WHERE `c`.`birth_date` IS NOT NULL
+            AND DAY(`c`.`birth_date`) = DAY(NOW())
+            AND MONTH(`c`.`birth_date`) = MONTH(NOW())
+            AND `c`.`id` NOT IN (
+              SELECT `rule_log`.`contact_id`
+              FROM `civirule_rule_log` `rule_log`
+              WHERE `rule_log`.`rule_id` = %1 AND DATE(`rule_log`.`log_date`) = DATE(NOW())
+            )";
+    $params[1] = array($this->ruleId, 'Integer');
+    $this->dao = CRM_Core_DAO::executeQuery($sql, $params, 'CRM_Contact_BAO_Contact');
+  }
+
+}
\ No newline at end of file
diff --git a/api/v3/Civirules/Cron.php b/api/v3/Civirules/Cron.php
index 9ca1081..a8594dd 100644
--- a/api/v3/Civirules/Cron.php
+++ b/api/v3/Civirules/Cron.php
@@ -23,6 +23,16 @@ function _civicrm_api3_civirules_cron_spec(&$spec) {
  */
 function civicrm_api3_civirules_cron($params) {
   $returnValues = array();
+
+  $rules = CRM_Civirules_BAO_Rule::findRulesForCron();
+  foreach($rules as $rule) {
+    $triggeredEntities = $rule->process();
+    $returnValues[$rule->getRuleId()] = array(
+      'rule' => CRM_Civirules_BAO_Rule::getRuleLabelWithId($rule->getRuleId()),
+      'triggered_entities' => $triggeredEntities,
+    );
+  }
+
   return civicrm_api3_create_success($returnValues, $params, 'Civirules', 'cron');
 
 }
-- 
GitLab