[ Index ] |
PHP Cross Reference of Eventum |
[Summary view] [Print] [Text view]
1 <?php 2 /* vim: set expandtab tabstop=4 shiftwidth=4 encoding=utf-8: */ 3 // +----------------------------------------------------------------------+ 4 // | Eventum - Issue Tracking System | 5 // +----------------------------------------------------------------------+ 6 // | Copyright (c) 2003, 2004, 2005, 2006, 2007 MySQL AB | 7 // | | 8 // | This program is free software; you can redistribute it and/or modify | 9 // | it under the terms of the GNU General Public License as published by | 10 // | the Free Software Foundation; either version 2 of the License, or | 11 // | (at your option) any later version. | 12 // | | 13 // | This program is distributed in the hope that it will be useful, | 14 // | but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 // | GNU General Public License for more details. | 17 // | | 18 // | You should have received a copy of the GNU General Public License | 19 // | along with this program; if not, write to: | 20 // | | 21 // | Free Software Foundation, Inc. | 22 // | 59 Temple Place - Suite 330 | 23 // | Boston, MA 02111-1307, USA. | 24 // +----------------------------------------------------------------------+ 25 // | Authors: João Prado Maia <jpm@mysql.com> | 26 // +----------------------------------------------------------------------+ 27 // 28 // @(#) $Id: class.history.php 3394 2007-11-04 08:33:06Z balsdorf $ 29 // 30 31 require_once (APP_INC_PATH . "class.error_handler.php"); 32 require_once (APP_INC_PATH . "class.misc.php"); 33 require_once (APP_INC_PATH . "class.mime_helper.php"); 34 require_once (APP_INC_PATH . "class.date.php"); 35 36 /** 37 * Class to handle the business logic related to the history information for 38 * the issues entered in the system. 39 * 40 * @version 1.0 41 * @author João Prado Maia <jpm@mysql.com> 42 */ 43 44 class History 45 { 46 /** 47 * Method used to format the changes done to an issue. 48 * 49 * @access public 50 * @param string $old_value The old value for a specific issue parameter 51 * @param string $new_value The new value for a specific issue parameter 52 * @return string The formatted string 53 */ 54 function formatChanges($old_value, $new_value) 55 { 56 if (empty($old_value)) { 57 return 'no value set -> ' . $new_value; 58 } elseif (empty($new_value)) { 59 return $old_value . ' -> no value set'; 60 } else { 61 return $old_value . ' -> ' . $new_value; 62 } 63 } 64 65 66 /** 67 * Method used to log the changes made against a specific issue. 68 * 69 * @access public 70 * @param integer $iss_id The issue ID 71 * @param integer $usr_id The ID of the user. 72 * @param integer $htt_id The type ID of this history event. 73 * @param string $summary The summary of the changes 74 * @param boolean $hide If this history item should be hidden. 75 * @return void 76 */ 77 function add($iss_id, $usr_id, $htt_id, $summary, $hide = false) 78 { 79 $stmt = "INSERT INTO 80 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history 81 ( 82 his_iss_id, 83 his_usr_id, 84 his_created_date, 85 his_summary, 86 his_htt_id"; 87 if ($hide == true) { 88 $stmt .= ", his_is_hidden"; 89 } 90 $stmt .= ") VALUES ( 91 " . Misc::escapeInteger($iss_id) . ", 92 " . Misc::escapeInteger($usr_id) . ", 93 '" . Date_API::getCurrentDateGMT() . "', 94 '" . Misc::escapeString($summary) . "', 95 $htt_id"; 96 if ($hide == true) { 97 $stmt .= ", 1"; 98 } 99 $stmt .= ")"; 100 $res = $GLOBALS["db_api"]->dbh->query($stmt); 101 if (PEAR::isError($res)) { 102 Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); 103 return -1; 104 } 105 } 106 107 108 /** 109 * Method used to get the list of changes made against a specific issue. 110 * 111 * @access public 112 * @param integer $iss_id The issue ID 113 * @param string $order_by The order to sort the history 114 * @return array The list of changes 115 */ 116 function getListing($iss_id, $order_by = 'DESC') 117 { 118 $stmt = "SELECT 119 * 120 FROM 121 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history, 122 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "history_type 123 WHERE 124 htt_id = his_htt_id AND 125 his_is_hidden != 1 AND 126 his_iss_id=" . Misc::escapeInteger($iss_id) . " AND 127 htt_role <= " . Auth::getCurrentRole() . " 128 ORDER BY 129 his_id $order_by"; 130 $res = $GLOBALS["db_api"]->dbh->getAll($stmt, DB_FETCHMODE_ASSOC); 131 if (PEAR::isError($res)) { 132 Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); 133 return ""; 134 } else { 135 for ($i = 0; $i < count($res); $i++) { 136 $res[$i]["his_created_date"] = Date_API::getFormattedDate($res[$i]["his_created_date"]); 137 $res[$i]["his_summary"] = Mime_Helper::fixEncoding($res[$i]["his_summary"]); 138 } 139 return $res; 140 } 141 } 142 143 144 /** 145 * Method used to remove all history entries associated with a 146 * given set of issues. 147 * 148 * @access public 149 * @param array $ids The array of issue IDs 150 * @return boolean 151 */ 152 function removeByIssues($ids) 153 { 154 $items = implode(", ", $ids); 155 $stmt = "DELETE FROM 156 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history 157 WHERE 158 his_iss_id IN ($items)"; 159 $res = $GLOBALS["db_api"]->dbh->query($stmt); 160 if (PEAR::isError($res)) { 161 Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); 162 return false; 163 } else { 164 return true; 165 } 166 } 167 168 169 /** 170 * Returns the id for the history type based on name. 171 * 172 * @access public 173 * @param string The name of the history type 174 * @return integer The id of this type. 175 */ 176 function getTypeID($name) 177 { 178 static $returns; 179 180 181 $serialized = serialize($name); 182 if (!empty($returns[$serialized])) { 183 return $returns[$serialized]; 184 } 185 186 if (!is_array($name)) { 187 $name = array($name); 188 } 189 190 $stmt = "SELECT 191 htt_id 192 FROM 193 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "history_type 194 WHERE 195 htt_name IN('" . join("','", $name) . "')"; 196 $res = $GLOBALS["db_api"]->dbh->getCol($stmt); 197 if (PEAR::isError($res)) { 198 Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); 199 return "unknown"; 200 } else { 201 if (count($name) == 1) { 202 $res = current($res); 203 } 204 $returns[$serialized] = $res; 205 return $res; 206 } 207 } 208 209 210 /** 211 * Returns a list of issues touched by the specified user in the specified time frame. 212 * 213 * @access public 214 * @param integer $usr_id The id of the user. 215 * @param date $start The start date 216 * @param date $end The end date 217 * @param date $separate_closed If closed issues should be included in a separate array 218 * @param array $htt_exclude Addtional History Types to ignore 219 * @return array An array of issues touched by the user. 220 */ 221 function getTouchedIssuesByUser($usr_id, $start, $end, $separate_closed = false, $htt_exclude = array()) 222 { 223 224 $htt_list = History::getTypeID( 225 array_merge(array( 226 'notification_removed', 227 'notification_added', 228 'notification_updated', 229 'remote_replier_added', 230 'replier_added', 231 'replier_removed', 232 'replier_other_added', 233 ), $htt_exclude) 234 ); 235 236 $stmt = "SELECT 237 iss_id, 238 iss_prj_id, 239 iss_summary, 240 iss_customer_id, 241 iss_customer_contract_id, 242 sta_title, 243 pri_title, 244 sta_is_closed 245 FROM 246 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history, 247 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue 248 LEFT JOIN 249 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "status 250 ON 251 iss_sta_id = sta_id 252 LEFT JOIN 253 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "project_priority 254 ON 255 iss_pri_id = pri_id 256 WHERE 257 his_iss_id = iss_id AND 258 his_usr_id = " . Misc::escapeInteger($usr_id) . " AND 259 his_created_date BETWEEN '" . Misc::escapeString($start) . "' AND '" . Misc::escapeString($end) . "' AND 260 his_htt_id NOT IN(" . join(',', $htt_list) . ") AND 261 iss_prj_id = " . Auth::getCurrentProject() . " 262 GROUP BY 263 iss_id 264 ORDER BY 265 iss_id ASC"; 266 $res = $GLOBALS["db_api"]->dbh->getAll($stmt, DB_FETCHMODE_ASSOC); 267 if (PEAR::isError($res)) { 268 Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); 269 return ""; 270 } else { 271 $data = array( 272 "closed" => array(), 273 "other" => array() 274 ); 275 if (count($res) > 0) { 276 if (isset($_POST['show_per_issue'])) { 277 Time_Tracking::fillTimeSpentByIssueAndTime($res, $usr_id, $start, $end); 278 } 279 if (isset($_POST['separate_status_changed'])) { 280 History::fillStatusChangedOnlyIssues($res, $usr_id, $start, $end); 281 } 282 foreach ($res as $index => $row) { 283 if ((!empty($row["iss_customer_id"])) && (Customer::hasCustomerIntegration($row['iss_prj_id']))) { 284 $details = Customer::getDetails($row["iss_prj_id"], $row["iss_customer_id"], $res['iss_customer_contract_id']); 285 $row["customer_name"] = $details["customer_name"]; 286 } 287 if (($separate_closed) && ($row['sta_is_closed'] == 1)) { 288 $data['closed'][] = $row; 289 } elseif ((isset($_POST['separate_status_changed'])) && $row['only_stat_changed']) { 290 $data['status_changed'][] = $row; 291 } else { 292 $data['other'][] = $row; 293 } 294 } 295 $sort_function = create_function('$a,$b', 'return strcasecmp(@$a["customer_name"], @$b["customer_name"]);'); 296 @usort($data['closed'], $sort_function); 297 @usort($data['other'], $sort_function); 298 } 299 } 300 return $data; 301 } 302 303 304 /** 305 * Returns the number of issues for the specified user that are currently set to the specified status(es). 306 * 307 * @access public 308 * @param integer $usr_id The id of the user. 309 * @param date $start The start date 310 * @param date $end The end date 311 * @param array $statuses An array of status abreviations to return counts for. 312 * @return array An array containing the number of issues for the user set tothe specified statuses. 313 */ 314 function getTouchedIssueCountByStatus($usr_id, $start, $end, $statuses = false) 315 { 316 $stmt = "SELECT 317 sta_title, 318 count(DISTINCT iss_id) as total 319 FROM 320 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue, 321 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "status, 322 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history 323 WHERE 324 his_iss_id = iss_id AND 325 iss_sta_id = sta_id AND 326 iss_prj_id = " . Auth::getCurrentProject() . " AND 327 his_usr_id = " . Misc::escapeInteger($usr_id) . " AND 328 his_created_date BETWEEN '" . Misc::escapeString($start) . "' AND '" . Misc::escapeString($end) . "'"; 329 if ($statuses != false) { 330 $stmt .= " AND 331 ( 332 sta_abbreviation IN('" . join("','", $statuses) . "') OR 333 sta_is_closed = 1 334 )"; 335 } 336 $stmt .= " 337 GROUP BY 338 sta_title 339 ORDER BY 340 sta_rank"; 341 $res = $GLOBALS["db_api"]->dbh->getAll($stmt, DB_FETCHMODE_ASSOC); 342 if (PEAR::isError($res)) { 343 Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); 344 return array(); 345 } else { 346 return $res; 347 } 348 } 349 350 351 /** 352 * Returns the history for a specified user in a specified time frame for an optional type 353 * 354 * @access public 355 * @param integer $usr_id The id of the user. 356 * @param date $start The start date 357 * @param date $end The end date 358 * @param array $htt_id The htt_id or id's to to return history for. 359 * @return array An array of history items 360 */ 361 function getHistoryByUser($usr_id, $start, $end, $htt_id = false) 362 { 363 $stmt = "SELECT 364 his_id, 365 his_iss_id, 366 his_created_date, 367 his_summary, 368 his_htt_id 369 FROM 370 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history 371 WHERE 372 his_usr_id = " . Misc::escapeInteger($usr_id) . " AND 373 his_created_date BETWEEN '" . date("Y/m/d", $start) . "' AND '" . date("Y/m/d", $end) . "'"; 374 if ($htt_id != false) { 375 $stmt .= " 376 AND his_htt_id IN(" . join(",", Misc::escapeInteger($htt_id)) . ")"; 377 } 378 $res = $GLOBALS["db_api"]->dbh->getAll($stmt, DB_FETCHMODE_ASSOC); 379 if (PEAR::isError($res)) { 380 Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); 381 return array(); 382 } 383 return $res; 384 } 385 386 387 /** 388 * Returns the last person to close the issue 389 * 390 * @param integer $issue_id The ID of the issue 391 * @return integer usr_id 392 */ 393 function getIssueCloser($issue_id) 394 { 395 $sql = "SELECT 396 his_usr_id 397 FROM 398 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history 399 WHERE 400 his_iss_id = " . Misc::escapeInteger($issue_id) . " AND 401 his_htt_id = '" . History::getTypeID('issue_closed') . "' 402 ORDER BY 403 his_created_date DESC 404 LIMIT 1"; 405 $res = $GLOBALS["db_api"]->dbh->getOne($sql); 406 if (PEAR::isError($res)) { 407 Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); 408 return 0; 409 } 410 return $res; 411 } 412 413 /** 414 * Fills a result set with a flag indicating if this issue only had it's status 415 * changed in the given time period. 416 * 417 * @access public 418 * @param array $res User issues 419 * @param integer $usr_id The ID of the user this report is for. 420 * @param integer $start The timestamp of the beginning of the report. 421 * @param integer $end The timestamp of the end of this report. 422 * @return boolean True if only status changed else false 423 */ 424 function fillStatusChangedOnlyIssues(&$res, $usr_id, $start, $end) { 425 426 $issue_ids = array(); 427 for ($i = 0; $i < count($res); $i++) { 428 $issue_ids[] = Misc::escapeInteger($res[$i]["iss_id"]); 429 } 430 $ids = implode(", ", $issue_ids); 431 432 $sql = "SELECT 433 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history.his_iss_id, 434 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history.his_htt_id 435 FROM 436 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history 437 WHERE 438 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history.his_htt_id != " . History::getTypeID('status_changed') . " AND 439 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history.his_htt_id != " . History::getTypeID('issue_updated') . " AND 440 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history.his_iss_id IN (" . $ids . ") AND 441 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history.his_usr_id = " . Misc::escapeInteger($usr_id) . " AND 442 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_history.his_created_date BETWEEN '" . Misc::escapeString($start) . "' AND '" . Misc::escapeString($end) . "' 443 GROUP BY his_iss_id"; 444 445 $result = $GLOBALS["db_api"]->dbh->getAssoc($sql); 446 if (PEAR::isError($result)) { 447 Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); 448 } else { 449 foreach($res as $key => $item) { 450 @$res[$key]['only_stat_changed'] = (array_key_exists($item['iss_id'], $result) ? false : true); 451 } 452 } 453 } 454 } 455 456 // benchmarking the included file (aka setup time) 457 if (APP_BENCHMARK) { 458 $GLOBALS['bench']->setMarker('Included History Class'); 459 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Dec 19 21:21:33 2007 | Cross-referenced by PHPXref 0.7 |