1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
16: class Operator_Driver_asterisksql extends Operator_Driver {
17:
18: 19: 20: 21: 22:
23: protected $_params = array();
24:
25: 26: 27: 28: 29:
30: protected $_db;
31:
32: 33: 34: 35: 36: 37:
38: protected $_write_db;
39:
40: 41: 42: 43: 44:
45: protected $_connected = false;
46:
47: 48: 49: 50: 51:
52: public function __construct($params = array())
53: {
54: $this->_params = $params;
55: }
56:
57: 58: 59: 60: 61: 62: 63:
64: protected function _getRecords($start, $end, $accountcode = null, $dcontext = null,
65: $rowstart = 0, $rowlimit = null)
66: {
67:
68:
69: $sql = 'SELECT accountcode, src, dst, dcontext, clid, channel, ' .
70: 'dstchannel, lastapp, lastdata, calldate AS start, ' .
71: 'calldate AS answer, calldate AS end, duration, ' .
72: 'billsec, disposition, amaflags, userfield, uniqueid ' .
73: ' FROM ' . $this->_params['table'] . ' WHERE %s';
74: $filter = array();
75: $values = array();
76:
77: if (!is_numeric($rowstart)) {
78: Horde::logMessage('Invalid start row requested.', 'ERR');
79: throw new Operator_Exception(_("Internal error. Details have been logged for the administrator."));
80: }
81: if (!is_null($rowlimit) && !is_numeric($rowlimit)) {
82: Horde::logMessage('Invalid row limit requested.', 'ERR');
83: throw new Operator_Exception(_("Internal error. Details have been logged for the administrator."));
84: }
85:
86: $filter[] = 'calldate >= ?';
87: $values[] = $start->strftime('%Y-%m-%d %T');
88: $filter[] = 'calldate < ?';
89: $values[] = $end->strftime('%Y-%m-%d %T');
90:
91:
92: if ($accountcode !== null) {
93: $filter[] = 'accountcode LIKE ?';
94: $values[] = $accountcode;
95: } else {
96: $filter[] = 'accountcode = ""';
97: }
98:
99:
100: if ($dcontext !== null) {
101: $filter[] = 'dcontext LIKE ?';
102: $values[] = $dcontext;
103: } else {
104: $filter[] = 'dcontext = ""';
105: }
106:
107:
108: $this->_connect();
109:
110: $filterstring = implode(' AND ', $filter);
111: $sql = sprintf($sql, $filterstring);
112:
113: Horde::logMessage(sprintf('Operator_Driver_asterisksql::getData(): %s', $sql), 'DEBUG');
114:
115:
116: if (is_null($rowlimit)) {
117: $res = $this->_db->query($sql, $values);
118: } else {
119: $res = $this->_db->limitQuery($sql, $rowstart, $rowlimit, $values);
120: }
121: if (is_a($res, 'PEAR_Error')) {
122: Horde::logMessage($res, 'ERR');
123: throw new Operator_Exception(_("Internal error. Details have been logged for the administrator."));
124: }
125:
126: $data = array();
127: while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
128: $data[] = $row;
129: }
130:
131:
132: $sql = 'SELECT COUNT(*) AS numcalls, SUM(duration)/60 AS minutes, ' .
133: 'SUM(CASE disposition WHEN "FAILED" THEN 1 ELSE 0 END) AS ' .
134: 'failed FROM ' . $this->_params['table'] . ' WHERE %s';
135: $sql = sprintf($sql, $filterstring);
136: Horde::logMessage(sprintf('Operator_Driver_asterisksql::getData(): %s', $sql), 'DEBUG');
137:
138:
139: $res = $this->_db->getRow($sql, $values, DB_FETCHMODE_ASSOC);
140: if (is_a($res, 'PEAR_Error')) {
141: Horde::logMessage($res, 'ERR');
142: throw new Operator_Exception(_("Internal error. Details have been logged for the administrator."));
143: }
144:
145: return array($res, $data);
146: }
147:
148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164:
165: protected function _getMonthlyCallStats($start, $end, $accountcode = null,
166: $dcontext = null)
167: {
168: if (!is_a($start, 'Horde_Date') || !is_a($end, 'Horde_Date')) {
169: Horde::logMessage('Start ane end date must be Horde_Date objects.', 'ERR');
170: throw new Operator_Exception(_("Internal error. Details have been logged for the administrator."));
171: }
172:
173:
174: $this->_connect();
175:
176:
177:
178: $numcalls_query = 'SELECT MONTH(calldate) AS month, ' .
179: 'YEAR(calldate) AS year, ' .
180: 'COUNT(*) AS numcalls FROM ' .
181: $this->_params['table'] . ' WHERE %s ' .
182: 'GROUP BY year, month';
183:
184: $minutes_query = 'SELECT MONTH(calldate) AS month, ' .
185: 'YEAR(calldate) AS year, ' .
186: 'SUM(duration)/60 AS minutes FROM ' .
187: $this->_params['table'] . ' WHERE %s ' .
188: 'GROUP BY year, month';
189:
190: $failed_query = 'SELECT MONTH(calldate) AS month, ' .
191: 'YEAR(calldate) AS year, ' .
192: 'COUNT(disposition) AS failed FROM ' .
193: $this->_params['table'] . ' ' .
194: 'WHERE disposition="failed" AND %s ' .
195: 'GROUP BY year, month';
196:
197:
198: $filter = array();
199: $values = array();
200:
201:
202: if ($accountcode !== null) {
203: $filter[] = 'accountcode LIKE ?';
204: $values[] = $accountcode;
205: } else {
206: $filter[] = 'accountcode = ""';
207: }
208:
209:
210: if ($dcontext !== null) {
211: $filter[] = 'dcontext LIKE ?';
212: $values[] = $dcontext;
213: } else {
214: $filter[] = 'dcontext = ""';
215: }
216:
217:
218: $filter[] = 'calldate >= ?';
219: $values[] = $start->strftime('%Y-%m-%d %T');
220: $filter[] = 'calldate < ?';
221: $values[] = $end->strftime('%Y-%m-%d %T');
222:
223: $filterstring = implode(' AND ', $filter);
224:
225: $stats = array();
226:
227:
228: $sql = sprintf($numcalls_query, $filterstring);
229: Horde::logMessage(sprintf('Operator_Driver_asterisksql::getCallStats(): Values: %s', print_r($values, true)), 'DEBUG');
230: Horde::logMessage(sprintf('Operator_Driver_asterisksql::getCallStats(): %s', $sql), 'DEBUG');
231: $numcalls_res = $this->_db->getAll($sql, $values, DB_FETCHMODE_ASSOC);
232: if (is_a($numcalls_res, 'PEAR_Error')) {
233: Horde::logMessage($numcalls_res, 'ERR');
234: throw new Operator_Exception(_("Internal error. Details have been logged for the administrator."));
235: }
236:
237: $sql = sprintf($minutes_query, $filterstring);
238: Horde::logMessage(sprintf('Operator_Driver_asterisksql::getCallStats(): %s', $sql), 'DEBUG');
239: $minutes_res = $this->_db->getAll($sql, $values, DB_FETCHMODE_ASSOC);
240: if (is_a($minutes_res, 'PEAR_Error')) {
241: Horde::logMessage($minutes_res, 'ERR');
242: throw new Operator_Exception(_("Internal error. Details have been logged for the administrator."));
243: }
244:
245: $sql = sprintf($failed_query, $filterstring);
246: Horde::logMessage(sprintf('Operator_Driver_asterisksql::getCallStats(): %s', $sql), 'DEBUG');
247: $failed_res = $this->_db->getAll($sql, $values, DB_FETCHMODE_ASSOC);
248: if (is_a($failed_res, 'PEAR_Error')) {
249: Horde::logMessage($failed_res, 'ERR');
250: throw new Operator_Exception(_("Internal error. Details have been logged for the administrator."));
251: }
252:
253:
254:
255:
256:
257:
258:
259:
260: $numcalls = array();
261: foreach ($numcalls_res as $row) {
262: $numcalls[$row['year']][$row['month']] = $row['numcalls'];
263: }
264: $minutes = array();
265: foreach ($minutes_res as $row) {
266: $minutes[$row['year']][$row['month']] = $row['minutes'];
267: }
268: $failed = array();
269: foreach ($failed_res as $row) {
270: $failed[$row['year']][$row['month']] = $row['failed'];
271: }
272:
273: $s_numcalls = array();
274: $s_minutes = array();
275: $s_failed = array();
276: while($start->compareDate($end) <= 0) {
277: $index = $start->strftime('%Y-%m');
278: $year = $start->year;
279: $month = $start->month;
280:
281: if (empty($numcalls[$year]) || empty($numcalls[$year][$month])) {
282: $s_numcalls[$index] = 0;
283: } else {
284: $s_numcalls[$index] = $numcalls[$year][$month];
285: }
286:
287: if (empty($minutes[$year]) || empty($minutes[$year][$month])) {
288: $s_minutes[$index] = 0;
289: } else {
290: $s_minutes[$index] = $minutes[$year][$month];
291: }
292:
293: if (empty($failed[$year]) || empty($failed[$year][$month])) {
294: $s_failed[$index] = 0;
295: } else {
296: $s_failed[$index] = $failed[$year][$month];
297: }
298:
299:
300: $start->month++;
301: }
302:
303: $info = Operator::getGraphInfo('numcalls');
304: $stats['numcalls'] = array($info['title'] => $s_numcalls);
305: $info = Operator::getGraphInfo('minutes');
306: $stats['minutes'] = array($info['title'] => $s_minutes);
307:
308:
309:
310: return $stats;
311: }
312:
313: public function getAccountCodes()
314: {
315:
316: $this->_connect();
317:
318: $sql = 'SELECT DISTINCT(accountcode) FROM ' . $this->_params['table'] .
319: ' ORDER BY accountcode';
320: Horde::logMessage(sprintf('Operator_Driver_asterisksql::getAccountCodes(): %s', $sql), 'DEBUG');
321: $res = $this->_db->getCol($sql, 'accountcode');
322: if (is_a($res, 'PEAR_Error')) {
323: Horde::logMessage($res, 'ERR');
324: throw new Operator_Exception(_("Internal error. Details have been logged for the administrator."));
325: }
326:
327: return $res;
328: }
329:
330: 331: 332: 333: 334: 335:
336: protected function _connect()
337: {
338: if ($this->_connected) {
339: return true;
340: }
341:
342: $this->_db = $GLOBALS['injector']->getInstance('Horde_Core_Factory_DbPear')->create('read', 'operator', 'storage');
343: $this->_write_db = $GLOBALS['injector']->getInstance('Horde_Core_Factory_DbPear')->create('rw', 'operator', 'storage');
344:
345: return true;
346: }
347:
348: 349: 350: 351: 352:
353: protected function _disconnect()
354: {
355: if ($this->_connected) {
356: $this->_connected = false;
357: $this->_db->disconnect();
358: $this->_write_db->disconnect();
359: }
360:
361: return true;
362: }
363:
364: }
365: