Newer
Older
<?php
/*+***********************************************************************************
* The contents of this file are subject to the vtiger CRM Public License Version 1.0
* ("License"); You may not use this file except in compliance with the License
* The Original Code is: vtiger CRM Open Source
* The Initial Developer of the Original Code is vtiger.
* Portions created by vtiger are Copyright (C) vtiger.
* All Rights Reserved.
*************************************************************************************/
require_once 'include/events/VTBatchEventTrigger.inc';
require_once("include/events/SqlResultIterator.inc");
class VTEventTrigger{
/* EventTrigger cache management */
private static $cache = array();
private static $cacheLookupType = '';
private static $mandatoryEventClass = array('VTEntityDelta', 'ModTrackerHandler', 'PBXManagerBatchHandler');
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
const CACHE_LOOKUP_TYPE_ALL = 'ALL';
static function initCache($name = false, $force = false) {
global $adb;
if($name) {
$names = $name;
if(!is_array($names)) $names = array($name);
$evtinfos = self::getActiveEventInfos($adb, $names);
foreach($evtinfos as $k=>$v) {
if(!self::isCached($k) || $force) {
self::$cache[$forname] = $evtinfos;
}
}
} else {
if(!self::isCached() || $force) {
self::$cache = self::getActiveEventInfos($adb, $name);
self::$cacheLookupType = self::CACHE_LOOKUP_TYPE_ALL;
}
}
}
static function isCached($name = false) {
if($name === false) {
if(self::$cacheLookupType == self::CACHE_LOOKUP_TYPE_ALL) {
// Was init cache done for ALL earlier?
return true;
}
} else {
return isset(self::$cache[$name]);
}
return false;
}
static function clearCache($name = false) {
if($name === false) {
self::$cache = array();
self::$cacheLookupType = '';
} else if(self::isCached($name)) {
unset(self::$cache[$name]);
}
}
static function lookupCache($name) {
if(self::isCached($name)) {
return self::$cache[$name];
} else if(self::$cacheLookupType == self::CACHE_LOOKUP_TYPE_ALL) {
return array();
}
return false;
}
static function getActiveEventInfos($adb, $name = false) {
$params = array();
$query = "SELECT * FROM vtiger_eventhandlers WHERE is_active=true";
if($name !== false) {
if(is_array($name)) {
$query .= " AND event_name IN (" . generateQuestionMarks($name) . ")";
} else {
$query .= " AND event_name = ?";
}
$params[] = $name;
}
if(CRMEntity::isBulkSaveMode()) {
$query .= " AND handler_class IN (" . generateQuestionMarks(self::$mandatoryEventClass) . ")";
array_push($params, self::$mandatoryEventClass);
}
$evtinfosbyname = array();
$result= $adb->pquery($query, $params);
$it = new SqlResultIterator($adb, $result);
foreach($it as $row) {
$evtinfosbyname[$row->event_name][] = array(
'condition' => $row->cond,
'handler_class' => $row->handler_class,
'handler_path' => $row->handler_path,
'dependent_on' => $row->dependent_on,
);
}
if($name) return $evtinfosbyname[$name];
else return $evtinfosbyname;
}
/** END **/
function __construct($adb, $name){
$this->name=$name;
$this->adb = $adb;
}
function trigger($data){
$adb = $this->adb;
$eventInfos = self::lookupCache($this->name);
if($eventInfos === false) {
$eventInfos = self::getActiveEventInfos($this->adb, $this->name);
}
$completedEvents = array();
if($eventInfos) {
while(count($eventInfos) > count($completedEvents)) {
$handlerCounter = 0; // Tracks the number of handlers triggered for the current iteration.
foreach($eventInfos as $eventInfo){
$condition = new VTEventCondition($eventInfo['condition']);
if($condition->test($data)){
$handler_class = $eventInfo['handler_class'];
if(in_array($handler_class, $completedEvents)) {
continue;
}
$dependentEventsNotCompleted = false;
$dependentOn = $eventInfo['dependent_on'];
$dependentEvents = Zend_Json::decode($dependentOn);
foreach($dependentEvents as $eventHandlerClass) {
if(!in_array($eventHandlerClass, $completedEvents)) {
$dependentEventsNotCompleted = true;
}
}
if($dependentEventsNotCompleted) continue;
require_once($eventInfo['handler_path']);
$handler = new $handler_class();
$handler->handleEvent($this->name, $data);
$completedEvents[] = $handler_class;
$handlerCounter++;
} else {
// Mark the event-handler as finished - without actually invoking.
$completedEvents[] = $eventInfo['handler_class'];
}
}
if($handlerCounter == 0 && count($eventInfos) > count($completedEvents)) {
$uncompletedEvents = array();
foreach($eventInfos as $eventInfo){
if(!in_array($eventInfo['handler_class'], $completedEvents)) {
$uncompletedEvents[] = $eventInfo['handler_class'];
}
}
throw new Exception("Deadlock occured for events: ". implode(' , ', $uncompletedEvents));
}
}
}
}
public static function getInstance($adb, $triggerName) {
if(stripos($triggerName, 'batch')) {
return new VTBatchEventTrigger($adb, $triggerName);
}
return new self($adb, $triggerName);
}
}
?>