| [ Index ] |
PHP Cross Reference of MantisBT |
[Summary view] [Print] [Text view]
1 <?php 2 # MantisBT - A PHP based bugtracking system 3 4 # MantisBT is free software: you can redistribute it and/or modify 5 # it under the terms of the GNU General Public License as published by 6 # the Free Software Foundation, either version 2 of the License, or 7 # (at your option) any later version. 8 # 9 # MantisBT is distributed in the hope that it will be useful, 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # GNU General Public License for more details. 13 # 14 # You should have received a copy of the GNU General Public License 15 # along with MantisBT. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Tag API 19 * 20 * @package CoreAPI 21 * @subpackage TagAPI 22 * @author John Reese 23 * @copyright Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org 24 * @copyright Copyright (C) 2002 - 2011 MantisBT Team - mantisbt-dev@lists.sourceforge.net 25 * @link http://www.mantisbt.org 26 * 27 * @uses access_api.php 28 * @uses authentication_api.php 29 * @uses bug_api.php 30 * @uses config_api.php 31 * @uses constant_inc.php 32 * @uses database_api.php 33 * @uses error_api.php 34 * @uses form_api.php 35 * @uses history_api.php 36 * @uses lang_api.php 37 * @uses string_api.php 38 * @uses user_api.php 39 * @uses utility_api.php 40 */ 41 42 require_api( 'access_api.php' ); 43 require_api( 'authentication_api.php' ); 44 require_api( 'bug_api.php' ); 45 require_api( 'config_api.php' ); 46 require_api( 'constant_inc.php' ); 47 require_api( 'database_api.php' ); 48 require_api( 'error_api.php' ); 49 require_api( 'form_api.php' ); 50 require_api( 'history_api.php' ); 51 require_api( 'lang_api.php' ); 52 require_api( 'string_api.php' ); 53 require_api( 'user_api.php' ); 54 require_api( 'utility_api.php' ); 55 56 /** 57 * Determine if a tag exists with the given ID. 58 * @param integer Tag ID 59 * @return boolean True if tag exists 60 */ 61 function tag_exists( $p_tag_id ) { 62 $c_tag_id = db_prepare_int( $p_tag_id ); 63 $t_tag_table = db_get_table( 'tag' ); 64 65 $query = "SELECT * FROM $t_tag_table WHERE id=" . db_param(); 66 $result = db_query_bound( $query, Array( $c_tag_id ) ); 67 68 return db_num_rows( $result ) > 0; 69 } 70 71 /** 72 * Ensure a tag exists with the given ID. 73 * @param integer Tag ID 74 */ 75 function tag_ensure_exists( $p_tag_id ) { 76 if( !tag_exists( $p_tag_id ) ) { 77 error_parameters( $p_tag_id ); 78 trigger_error( ERROR_TAG_NOT_FOUND, ERROR ); 79 } 80 } 81 82 /** 83 * Determine if a given name is unique (not already used). 84 * Uses a case-insensitive search of the database for existing tags with the same name. 85 * @param string Tag name 86 * @return boolean True if name is unique 87 */ 88 function tag_is_unique( $p_name ) { 89 $c_name = trim( $p_name ); 90 $t_tag_table = db_get_table( 'tag' ); 91 92 $query = 'SELECT id FROM ' . $t_tag_table . ' WHERE ' . db_helper_like( 'name' ); 93 $result = db_query_bound( $query, Array( $c_name ) ); 94 95 return db_num_rows( $result ) == 0; 96 } 97 98 /** 99 * Ensure that a name is unique. 100 * @param string Tag name 101 */ 102 function tag_ensure_unique( $p_name ) { 103 if( !tag_is_unique( $p_name ) ) { 104 trigger_error( ERROR_TAG_DUPLICATE, ERROR ); 105 } 106 } 107 108 /** 109 * Determine if a given name is valid. 110 * 111 * Name must not begin with '+' and '-' characters (they are used for 112 * filters) and must not contain the configured tag separator. 113 * The matches parameter allows to also receive an array of regex matches, 114 * which by default only includes the valid tag name itself. 115 * The prefix parameter is optional, but allows you to prefix the regex 116 * check, which is useful for filters, etc. 117 * @param string Tag name 118 * @param array Array reference for regex matches 119 * @param string Prefix regex pattern 120 * @return boolean True if the name is valid 121 */ 122 function tag_name_is_valid( $p_name, &$p_matches, $p_prefix = '' ) { 123 $t_separator = config_get( 'tag_separator' ); 124 $t_pattern = "/^$p_prefix([^\+\-{$t_separator}][^{$t_separator}]*)$/"; 125 return preg_match( $t_pattern, $p_name, $p_matches ); 126 } 127 128 /** 129 * Ensure a tag name is valid. 130 * @param string Tag name 131 */ 132 function tag_ensure_name_is_valid( $p_name ) { 133 $t_matches = array(); 134 if( !tag_name_is_valid( $p_name, $t_matches ) ) { 135 trigger_error( ERROR_TAG_NAME_INVALID, ERROR ); 136 } 137 } 138 139 /** 140 * Compare two tag rows based on tag name. 141 * @param array Tag row 1 142 * @param array Tag row 2 143 * @return integer -1 when Tag 1 < Tag 2, 1 when Tag 1 > Tag 2, 0 otherwise 144 */ 145 function tag_cmp_name( $p_tag1, $p_tag2 ) { 146 return strcasecmp( $p_tag1['name'], $p_tag2['name'] ); 147 } 148 149 /** 150 * Parse a form input string to extract existing and new tags. 151 * When given a string, parses for tag names separated by configured separator, 152 * then returns an array of tag rows for each tag. Existing tags get the full 153 * row of information returned. If the tag does not exist, a row is returned with 154 * id = -1 and the tag name, and if the name is invalid, a row is returned with 155 * id = -2 and the tag name. The resulting array is then sorted by tag name. 156 * @param string Input string to parse 157 * @return array Rows of tags parsed from input string 158 */ 159 function tag_parse_string( $p_string ) { 160 $t_tags = array(); 161 162 $t_strings = explode( config_get( 'tag_separator' ), $p_string ); 163 foreach( $t_strings as $t_name ) { 164 $t_name = trim( $t_name ); 165 if( is_blank( $t_name ) ) { 166 continue; 167 } 168 169 $t_matches = array(); 170 $t_tag_row = tag_get_by_name( $t_name ); 171 if( $t_tag_row !== false ) { 172 $t_tags[] = $t_tag_row; 173 } else { 174 if( tag_name_is_valid( $t_name, $t_matches ) ) { 175 $t_id = -1; 176 } else { 177 $t_id = -2; 178 } 179 $t_tags[] = array( 180 'id' => $t_id, 181 'name' => $t_name, 182 ); 183 } 184 } 185 usort( $t_tags, 'tag_cmp_name' ); 186 return $t_tags; 187 } 188 189 /** 190 * Parse a filter string to extract existing and new tags. 191 * When given a string, parses for tag names separated by configured separator, 192 * then returns an array of tag rows for each tag. Existing tags get the full 193 * row of information returned. If the tag does not exist, a row is returned with 194 * id = -1 and the tag name, and if the name is invalid, a row is returned with 195 * id = -2 and the tag name. The resulting array is then sorted by tag name. 196 * @param string Filter string to parse 197 * @return array Rows of tags parsed from filter string 198 */ 199 function tag_parse_filters( $p_string ) { 200 $t_tags = array(); 201 $t_prefix = '[+-]{0,1}'; 202 203 $t_strings = explode( config_get( 'tag_separator' ), $p_string ); 204 foreach( $t_strings as $t_name ) { 205 $t_name = trim( $t_name ); 206 $t_matches = array(); 207 208 if( !is_blank( $t_name ) && tag_name_is_valid( $t_name, $t_matches, $t_prefix ) ) { 209 $t_tag_row = tag_get_by_name( $t_matches[1] ); 210 if( $t_tag_row !== false ) { 211 $t_filter = utf8_substr( $t_name, 0, 1 ); 212 213 if( '+' == $t_filter ) { 214 $t_tag_row['filter'] = 1; 215 } else if( '-' == $t_filter ) { 216 $t_tag_row['filter'] = -1; 217 } else { 218 $t_tag_row['filter'] = 0; 219 } 220 221 $t_tags[] = $t_tag_row; 222 } 223 } else { 224 continue; 225 } 226 } 227 usort( $t_tags, 'tag_cmp_name' ); 228 return $t_tags; 229 } 230 231 # CRUD 232 /** 233 * Return a tag row for the given ID. 234 * @param integer Tag ID 235 * @return array Tag row 236 */ 237 function tag_get( $p_tag_id ) { 238 tag_ensure_exists( $p_tag_id ); 239 240 $c_tag_id = db_prepare_int( $p_tag_id ); 241 242 $t_tag_table = db_get_table( 'tag' ); 243 244 $query = "SELECT * FROM $t_tag_table 245 WHERE id=" . db_param(); 246 $result = db_query_bound( $query, Array( $c_tag_id ) ); 247 248 if( 0 == db_num_rows( $result ) ) { 249 return false; 250 } 251 $row = db_fetch_array( $result ); 252 253 return $row; 254 } 255 256 /** 257 * Return a tag row for the given name. 258 * @param string Tag name 259 * @return Tag row 260 */ 261 function tag_get_by_name( $p_name ) { 262 $t_tag_table = db_get_table( 'tag' ); 263 264 $query = "SELECT * FROM $t_tag_table 265 WHERE " . db_helper_like( 'name' ); 266 $result = db_query_bound( $query, Array( $p_name ) ); 267 268 if( 0 == db_num_rows( $result ) ) { 269 return false; 270 } 271 $row = db_fetch_array( $result ); 272 273 return $row; 274 } 275 276 /** 277 * Return a single field from a tag row for the given ID. 278 * @param integer Tag ID 279 * @param string Field name 280 * @return mixed Field value 281 */ 282 function tag_get_field( $p_tag_id, $p_field_name ) { 283 $row = tag_get( $p_tag_id ); 284 285 if( isset( $row[$p_field_name] ) ) { 286 return $row[$p_field_name]; 287 } else { 288 error_parameters( $p_field_name ); 289 trigger_error( ERROR_DB_FIELD_NOT_FOUND, WARNING ); 290 return ''; 291 } 292 } 293 294 /** 295 * Create a tag with the given name, creator, and description. 296 * Defaults to the currently logged in user, and a blank description. 297 * @param string Tag name 298 * @param integer User ID 299 * @param string Description 300 * @return integer Tag ID 301 */ 302 function tag_create( $p_name, $p_user_id = null, $p_description = '' ) { 303 access_ensure_global_level( config_get( 'tag_create_threshold' ) ); 304 305 tag_ensure_name_is_valid( $p_name ); 306 tag_ensure_unique( $p_name ); 307 308 if( null == $p_user_id ) { 309 $p_used_id = auth_get_current_user_id(); 310 } else { 311 user_ensure_exists( $p_user_id ); 312 } 313 314 $c_user_id = db_prepare_int( $p_user_id ); 315 $c_date_created = db_now(); 316 317 $t_tag_table = db_get_table( 'tag' ); 318 319 $query = "INSERT INTO $t_tag_table 320 ( user_id, 321 name, 322 description, 323 date_created, 324 date_updated 325 ) 326 VALUES 327 ( " . db_param() . ", 328 " . db_param() . ", 329 " . db_param() . ", 330 " . db_param() . ", 331 " . db_param() . " 332 )"; 333 334 db_query_bound( $query, Array( $c_user_id, trim( $p_name ), trim( $p_description ), $c_date_created, $c_date_created ) ); 335 return db_insert_id( $t_tag_table ); 336 } 337 338 /** 339 * Update a tag with given name, creator, and description. 340 * @param integer Tag ID 341 * @param string Tag name 342 * @param integer User ID 343 * @param string Description 344 */ 345 function tag_update( $p_tag_id, $p_name, $p_user_id, $p_description ) { 346 user_ensure_exists( $p_user_id ); 347 348 if( auth_get_current_user_id() == tag_get_field( $p_tag_id, 'user_id' ) ) { 349 $t_update_level = config_get( 'tag_edit_own_threshold' ); 350 } else { 351 $t_update_level = config_get( 'tag_edit_threshold' ); 352 } 353 354 access_ensure_global_level( $t_update_level ); 355 356 tag_ensure_name_is_valid( $p_name ); 357 358 $t_tag_name = tag_get_field( $p_tag_id, 'name' ); 359 360 $t_rename = false; 361 if( utf8_strtolower( $p_name ) != utf8_strtolower( $t_tag_name ) ) { 362 tag_ensure_unique( $p_name ); 363 $t_rename = true; 364 } 365 366 $c_tag_id = trim( db_prepare_int( $p_tag_id ) ); 367 $c_date_updated = db_now(); 368 369 $t_tag_table = db_get_table( 'tag' ); 370 371 $query = "UPDATE $t_tag_table 372 SET user_id=" . db_param() . ", 373 name=" . db_param() . ", 374 description=" . db_param() . ", 375 date_updated=" . db_param() . " 376 WHERE id=" . db_param(); 377 db_query_bound( $query, Array( (int)$p_user_id, $p_name, $p_description, $c_date_updated, $c_tag_id ) ); 378 379 if( $t_rename ) { 380 $t_bugs = tag_get_bugs_attached( $p_tag_id ); 381 382 foreach( $t_bugs as $t_bug_id ) { 383 history_log_event_special( $t_bug_id, TAG_RENAMED, $t_tag_name, $p_name ); 384 } 385 } 386 387 return true; 388 } 389 390 /** 391 * Delete a tag with the given ID. 392 * @param integer Tag ID 393 */ 394 function tag_delete( $p_tag_id ) { 395 tag_ensure_exists( $p_tag_id ); 396 397 access_ensure_global_level( config_get( 'tag_edit_threshold' ) ); 398 399 $t_bugs = tag_get_bugs_attached( $p_tag_id ); 400 foreach( $t_bugs as $t_bug_id ) { 401 tag_bug_detach( $p_tag_id, $t_bug_id ); 402 } 403 404 $c_tag_id = db_prepare_int( $p_tag_id ); 405 406 $t_tag_table = db_get_table( 'tag' ); 407 $t_bug_tag_table = db_get_table( 'bug_tag' ); 408 409 $query = "DELETE FROM $t_tag_table 410 WHERE id=" . db_param(); 411 db_query_bound( $query, Array( $c_tag_id ) ); 412 413 return true; 414 } 415 416 /** 417 * Gets the candidates for the specified bug. These are existing tags 418 * that are not associated with the bug already. 419 * 420 * @param int $p_bug_id The bug id, if 0 returns all tags. 421 * @returns The array of tag rows, each with id, name, and description. 422 */ 423 function tag_get_candidates_for_bug( $p_bug_id ) { 424 $t_tag_table = db_get_table( 'tag' ); 425 426 $t_params = array(); 427 if ( 0 != $p_bug_id ) { 428 $t_bug_tag_table = db_get_table( 'bug_tag' ); 429 430 if ( db_is_mssql() ) { 431 $t_params[] = $p_bug_id; 432 $query = "SELECT t.id FROM $t_tag_table t 433 LEFT JOIN $t_bug_tag_table b ON t.id=b.tag_id 434 WHERE b.bug_id IS NULL OR b.bug_id != " . db_param(); 435 $result = db_query_bound( $query, $t_params ); 436 437 $t_subquery_results = array(); 438 439 while( $row = db_fetch_array( $result ) ) { 440 $t_subquery_results[] = (int)$row; 441 } 442 $query = "SELECT id, name, description FROM $t_tag_table WHERE id IN ( " . implode( ', ', $t_subquery_results ) . ')'; 443 } else { 444 $query = "SELECT id, name, description FROM $t_tag_table WHERE id IN ( 445 SELECT t.id FROM $t_tag_table t 446 LEFT JOIN $t_bug_tag_table b ON t.id=b.tag_id 447 WHERE b.bug_id IS NULL OR b.bug_id != " . db_param() . 448 ')'; 449 } 450 $t_params[] = $p_bug_id; 451 } else { 452 $query = 'SELECT id, name, description FROM ' . $t_tag_table; 453 } 454 455 $query .= ' ORDER BY name ASC '; 456 $result = db_query_bound( $query, $t_params ); 457 458 $t_results_to_return = array(); 459 460 while( $row = db_fetch_array( $result ) ) { 461 $t_results_to_return[] = $row; 462 } 463 464 return $t_results_to_return; 465 } 466 467 # Associative 468 /** 469 * Determine if a tag is attached to a bug. 470 * @param integer Tag ID 471 * @param integer Bug ID 472 * @return boolean True if the tag is attached 473 */ 474 function tag_bug_is_attached( $p_tag_id, $p_bug_id ) { 475 $c_tag_id = db_prepare_int( $p_tag_id ); 476 $c_bug_id = db_prepare_int( $p_bug_id ); 477 478 $t_bug_tag_table = db_get_table( 'bug_tag' ); 479 480 $query = "SELECT * FROM $t_bug_tag_table 481 WHERE tag_id=" . db_param() . " AND bug_id=" . db_param(); 482 $result = db_query_bound( $query, Array( $c_tag_id, $c_bug_id ) ); 483 return( db_num_rows( $result ) > 0 ); 484 } 485 486 /** 487 * Return the tag attachment row. 488 * @param integer Tag ID 489 * @param integer Bug ID 490 * @return array Tag attachment row 491 */ 492 function tag_bug_get_row( $p_tag_id, $p_bug_id ) { 493 $c_tag_id = db_prepare_int( $p_tag_id ); 494 $c_bug_id = db_prepare_int( $p_bug_id ); 495 496 $t_bug_tag_table = db_get_table( 'bug_tag' ); 497 498 $query = "SELECT * FROM $t_bug_tag_table 499 WHERE tag_id=" . db_param() . " AND bug_id=" . db_param(); 500 $result = db_query_bound( $query, Array( $c_tag_id, $c_bug_id ) ); 501 502 if( db_num_rows( $result ) == 0 ) { 503 trigger_error( TAG_NOT_ATTACHED, ERROR ); 504 } 505 return db_fetch_array( $result ); 506 } 507 508 /** 509 * Return an array of tags attached to a given bug sorted by tag name. 510 * @param Bug ID 511 * @return array Array of tag rows with attachement information 512 */ 513 function tag_bug_get_attached( $p_bug_id ) { 514 $c_bug_id = db_prepare_int( $p_bug_id ); 515 516 $t_tag_table = db_get_table( 'tag' ); 517 $t_bug_tag_table = db_get_table( 'bug_tag' ); 518 519 $query = "SELECT t.*, b.user_id as user_attached, b.date_attached 520 FROM $t_tag_table as t 521 LEFT JOIN $t_bug_tag_table as b 522 on t.id=b.tag_id 523 WHERE b.bug_id=" . db_param(); 524 $result = db_query_bound( $query, Array( $c_bug_id ) ); 525 526 $rows = array(); 527 while( $row = db_fetch_array( $result ) ) { 528 $rows[] = $row; 529 } 530 531 usort( $rows, 'tag_cmp_name' ); 532 return $rows; 533 } 534 535 /** 536 * Return an array of bugs that a tag is attached to. 537 * @param integer Tag ID 538 * @return array Array of bug ID's. 539 */ 540 function tag_get_bugs_attached( $p_tag_id ) { 541 $c_tag_id = db_prepare_int( $p_tag_id ); 542 543 $t_bug_tag_table = db_get_table( 'bug_tag' ); 544 545 $query = "SELECT bug_id FROM $t_bug_tag_table 546 WHERE tag_id=" . db_param(); 547 $result = db_query_bound( $query, Array( $c_tag_id ) ); 548 549 $bugs = array(); 550 while( $row = db_fetch_array( $result ) ) { 551 $bugs[] = $row['bug_id']; 552 } 553 554 return $bugs; 555 } 556 557 /** 558 * Attach a tag to a bug. 559 * @param integer Tag ID 560 * @param integer Bug ID 561 * @param integer User ID 562 */ 563 function tag_bug_attach( $p_tag_id, $p_bug_id, $p_user_id = null ) { 564 access_ensure_bug_level( config_get( 'tag_attach_threshold' ), $p_bug_id, $p_user_id ); 565 566 tag_ensure_exists( $p_tag_id ); 567 568 if( tag_bug_is_attached( $p_tag_id, $p_bug_id ) ) { 569 trigger_error( TAG_ALREADY_ATTACHED, ERROR ); 570 } 571 572 if( null == $p_user_id ) { 573 $p_used_id = auth_get_current_user_id(); 574 } else { 575 user_ensure_exists( $p_user_id ); 576 } 577 578 $c_tag_id = db_prepare_int( $p_tag_id ); 579 $c_bug_id = db_prepare_int( $p_bug_id ); 580 $c_user_id = db_prepare_int( $p_user_id ); 581 582 $t_bug_tag_table = db_get_table( 'bug_tag' ); 583 584 $query = "INSERT INTO $t_bug_tag_table 585 ( tag_id, 586 bug_id, 587 user_id, 588 date_attached 589 ) 590 VALUES 591 ( " . db_param() . ", 592 " . db_param() . ", 593 " . db_param() . ", 594 " . db_param() . " 595 )"; 596 db_query_bound( $query, Array( $c_tag_id, $c_bug_id, $c_user_id, db_now() ) ); 597 598 $t_tag_name = tag_get_field( $p_tag_id, 'name' ); 599 history_log_event_special( $p_bug_id, TAG_ATTACHED, $t_tag_name ); 600 601 # updated the last_updated date 602 bug_update_date( $p_bug_id ); 603 604 return true; 605 } 606 607 /** 608 * Detach a tag from a bug. 609 * @param integer Tag ID 610 * @param integer Bug ID 611 * @param boolean Add history entries to bug 612 * @param integer User Id (or null for current logged in user) 613 */ 614 function tag_bug_detach( $p_tag_id, $p_bug_id, $p_add_history = true, $p_user_id = null ) { 615 if( $p_user_id === null ) { 616 $t_user_id = auth_get_current_user_id(); 617 } else { 618 $t_user_id = $p_user_id; 619 } 620 621 if( !tag_bug_is_attached( $p_tag_id, $p_bug_id ) ) { 622 trigger_error( TAG_NOT_ATTACHED, ERROR ); 623 } 624 625 $t_tag_row = tag_bug_get_row( $p_tag_id, $p_bug_id); 626 if( $t_user_id == tag_get_field( $p_tag_id, 'user_id' ) || $t_user_id == $t_tag_row[ 'user_id' ] ) { 627 $t_detach_level = config_get( 'tag_detach_own_threshold' ); 628 } else { 629 $t_detach_level = config_get( 'tag_detach_threshold' ); 630 } 631 632 access_ensure_bug_level( $t_detach_level, $p_bug_id, $t_user_id ); 633 634 $c_tag_id = db_prepare_int( $p_tag_id ); 635 $c_bug_id = db_prepare_int( $p_bug_id ); 636 637 $t_bug_tag_table = db_get_table( 'bug_tag' ); 638 639 $query = "DELETE FROM $t_bug_tag_table 640 WHERE tag_id=" . db_param() . ' AND bug_id=' . db_param(); 641 db_query_bound( $query, Array( $c_tag_id, $c_bug_id ) ); 642 643 if( $p_add_history ) { 644 $t_tag_name = tag_get_field( $p_tag_id, 'name' ); 645 history_log_event_special( $p_bug_id, TAG_DETACHED, $t_tag_name ); 646 } 647 648 # updated the last_updated date 649 bug_update_date( $p_bug_id ); 650 651 return true; 652 } 653 654 /** 655 * Detach all tags from a given bug. 656 * @param integer Bug ID 657 * @param boolean Add history entries to bug 658 * @param integer User Id (or null for current logged in user) 659 */ 660 function tag_bug_detach_all( $p_bug_id, $p_add_history = true, $p_user_id = null ) { 661 $t_tags = tag_bug_get_attached( $p_bug_id ); 662 foreach( $t_tags as $t_tag_row ) { 663 tag_bug_detach( $t_tag_row['id'], $p_bug_id, $p_add_history, $p_user_id ); 664 } 665 } 666 667 # Display 668 /** 669 * Display a tag hyperlink. 670 * If a bug ID is passed, the tag link will include a detach link if the 671 * user has appropriate privileges. 672 * @param array Tag row 673 * @param integer Bug ID 674 */ 675 function tag_display_link( $p_tag_row, $p_bug_id = 0 ) { 676 static $t_security_token = null; 677 if( is_null( $t_security_token ) ) { 678 $t_security_token = htmlspecialchars( form_security_param( 'tag_detach' ) ); 679 } 680 681 if( auth_get_current_user_id() == $p_tag_row['user_attached'] || auth_get_current_user_id() == $p_tag_row['user_id'] ) { 682 $t_detach = config_get( 'tag_detach_own_threshold' ); 683 } else { 684 $t_detach = config_get( 'tag_detach_threshold' ); 685 } 686 687 $t_name = string_display_line( $p_tag_row['name'] ); 688 $t_description = string_display_line( $p_tag_row['description'] ); 689 690 echo "<a href='tag_view_page.php?tag_id=$p_tag_row[id]' title='$t_description'>$t_name</a>"; 691 692 if( $p_bug_id > 0 && access_has_bug_level( $t_detach, $p_bug_id ) ) { 693 $t_tooltip = string_html_specialchars( sprintf( lang_get( 'tag_detach' ), $t_name ) ); 694 echo " <a href='tag_detach.php?bug_id=$p_bug_id&tag_id=$p_tag_row[id]$t_security_token'><img src='images/delete.png' class='delete-icon' title=\"$t_tooltip\" alt=\"X\"/></a>"; 695 } 696 697 return true; 698 } 699 700 /** 701 * Display a list of attached tag hyperlinks separated by the configured hyperlinks. 702 * @param Bug ID 703 */ 704 function tag_display_attached( $p_bug_id ) { 705 $t_tag_rows = tag_bug_get_attached( $p_bug_id ); 706 707 if( count( $t_tag_rows ) == 0 ) { 708 echo lang_get( 'tag_none_attached' ); 709 } else { 710 $i = 0; 711 foreach( $t_tag_rows as $t_tag ) { 712 echo( $i > 0 ? config_get( 'tag_separator' ) . ' ' : '' ); 713 tag_display_link( $t_tag, $p_bug_id ); 714 $i++; 715 } 716 } 717 718 return true; 719 } 720 721 # Statistics 722 /** 723 * Get the number of bugs a given tag is attached to. 724 * @param integer Tag ID 725 * @return integer Number of attached bugs 726 */ 727 function tag_stats_attached( $p_tag_id ) { 728 $c_tag_id = db_prepare_int( $p_tag_id ); 729 $t_bug_tag_table = db_get_table( 'bug_tag' ); 730 731 $query = "SELECT COUNT(*) FROM $t_bug_tag_table 732 WHERE tag_id=" . db_param(); 733 $result = db_query_bound( $query, Array( $c_tag_id ) ); 734 735 return db_result( $result ); 736 } 737 738 /** 739 * Get a list of related tags. 740 * Returns a list of tags that are the most related to the given tag, 741 * based on the number of times they have been attached to the same bugs. 742 * Defaults to a list of five tags. 743 * @param integer Tag ID 744 * @param integer List size 745 * @return array Array of tag rows, with share count added 746 */ 747 function tag_stats_related( $p_tag_id, $p_limit = 5 ) { 748 $t_bug_table = db_get_table( 'bug' ); 749 $t_tag_table = db_get_table( 'tag' ); 750 $t_bug_tag_table = db_get_table( 'bug_tag' ); 751 $t_project_user_list_table = db_get_table( 'project_user_list' ); 752 $t_user_table = db_get_table( 'user' ); 753 754 $c_tag_id = db_prepare_int( $p_tag_id ); 755 $c_user_id = auth_get_current_user_id(); 756 757 $subquery = "SELECT b.id FROM $t_bug_table AS b 758 LEFT JOIN $t_project_user_list_table AS p 759 ON p.project_id=b.project_id AND p.user_id=" . db_param() . " 760 JOIN $t_user_table AS u 761 ON u.id=" . db_param() . " 762 JOIN $t_bug_tag_table AS t 763 ON t.bug_id=b.id 764 WHERE ( p.access_level>b.view_state OR u.access_level>b.view_state ) 765 AND t.tag_id=" . db_param(); 766 767 $query = "SELECT * FROM $t_bug_tag_table 768 WHERE tag_id != " . db_param() . " 769 AND bug_id IN ( $subquery ) "; 770 771 $result = db_query_bound( $query, Array( /*query*/ $c_tag_id, /*subquery*/ $c_user_id, $c_user_id, $c_tag_id ) ); 772 773 $t_tag_counts = array(); 774 while( $row = db_fetch_array( $result ) ) { 775 if( !isset( $t_tag_counts[$row['tag_id']] ) ) { 776 $t_tag_counts[$row['tag_id']] = 1; 777 } else { 778 $t_tag_counts[$row['tag_id']]++; 779 } 780 } 781 782 arsort( $t_tag_counts ); 783 784 $t_tags = array(); 785 $i = 1; 786 foreach( $t_tag_counts as $t_tag_id => $t_count ) { 787 $t_tag_row = tag_get( $t_tag_id ); 788 $t_tag_row['count'] = $t_count; 789 $t_tags[] = $t_tag_row; 790 $i++; 791 if( $i > $p_limit ) { 792 break; 793 } 794 } 795 796 return $t_tags; 797 } 798
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Jul 28 15:48:31 2011 | Cross-referenced by PHPXref 0.7 |