| [ 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 * Custom Field API 19 * 20 * @package CoreAPI 21 * @subpackage CustomFieldAPI 22 * @copyright Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org 23 * @copyright Copyright (C) 2002 - 2011 MantisBT Team - mantisbt-dev@lists.sourceforge.net 24 * @link http://www.mantisbt.org 25 * 26 * @uses access_api.php 27 * @uses authentication_api.php 28 * @uses bug_api.php 29 * @uses config_api.php 30 * @uses constant_inc.php 31 * @uses database_api.php 32 * @uses email_api.php 33 * @uses error_api.php 34 * @uses helper_api.php 35 * @uses history_api.php 36 * @uses project_api.php 37 * @uses string_api.php 38 * @uses utility_api.php 39 */ 40 41 require_api( 'access_api.php' ); 42 require_api( 'authentication_api.php' ); 43 require_api( 'bug_api.php' ); 44 require_api( 'config_api.php' ); 45 require_api( 'constant_inc.php' ); 46 require_api( 'database_api.php' ); 47 require_api( 'email_api.php' ); 48 require_api( 'error_api.php' ); 49 require_api( 'helper_api.php' ); 50 require_api( 'history_api.php' ); 51 require_api( 'project_api.php' ); 52 require_api( 'string_api.php' ); 53 require_api( 'utility_api.php' ); 54 55 # ## Custom Fields API ### 56 # ******************************************* 57 # TODO 58 # - add an object to store field data like BugData and UserPrefs ? 59 # - add caching functions like user, bug, etc 60 # - make existing api functions use caching functions 61 # - add functions to return individual db columns for a field definition 62 # ******************************************* 63 64 $g_custom_field_types[CUSTOM_FIELD_TYPE_STRING] = 'standard'; 65 $g_custom_field_types[CUSTOM_FIELD_TYPE_TEXTAREA] = 'standard'; 66 $g_custom_field_types[CUSTOM_FIELD_TYPE_NUMERIC] = 'standard'; 67 $g_custom_field_types[CUSTOM_FIELD_TYPE_FLOAT] = 'standard'; 68 $g_custom_field_types[CUSTOM_FIELD_TYPE_ENUM] = 'standard'; 69 $g_custom_field_types[CUSTOM_FIELD_TYPE_EMAIL] = 'standard'; 70 $g_custom_field_types[CUSTOM_FIELD_TYPE_CHECKBOX] = 'standard'; 71 $g_custom_field_types[CUSTOM_FIELD_TYPE_LIST] = 'standard'; 72 $g_custom_field_types[CUSTOM_FIELD_TYPE_MULTILIST] = 'standard'; 73 $g_custom_field_types[CUSTOM_FIELD_TYPE_DATE] = 'standard'; 74 75 foreach( $g_custom_field_types as $type ) { 76 require_once( config_get_global( 'core_path' ) . 'cfdefs' . DIRECTORY_SEPARATOR . 'cfdef_' . $type . '.php' ); 77 } 78 79 function custom_field_allow_manage_display( $p_type, $p_display ) { 80 global $g_custom_field_type_definition; 81 if( isset( $g_custom_field_type_definition[$p_type]['#display_' . $p_display] ) ) { 82 return $g_custom_field_type_definition[$p_type]['#display_' . $p_display]; 83 } 84 return false; 85 } 86 87 88 # ######################################## 89 # SECURITY NOTE: cache globals are initialized here to prevent them 90 # being spoofed if register_globals is turned on 91 92 $g_cache_custom_field = array(); 93 $g_cache_cf_list = NULL; 94 $g_cache_cf_linked = array(); 95 $g_cache_name_to_id_map = array(); 96 97 /** 98 * Cache a custom field row if necessary and return the cached copy 99 * If the second parameter is true (default), trigger an error 100 * if the field can't be found. If the second parameter is 101 * false, return false if the field can't be found. 102 * @param int $p_field_id integer representing custom field id 103 * @param bool $p_trigger_errors indicates whether to trigger an error if the field is not found 104 * @return array array representing custom field 105 * @access public 106 */ 107 function custom_field_cache_row( $p_field_id, $p_trigger_errors = true ) { 108 global $g_cache_custom_field, $g_cache_name_to_id_map; 109 110 $c_field_id = db_prepare_int( $p_field_id ); 111 112 $t_custom_field_table = db_get_table( 'custom_field' ); 113 114 if( isset( $g_cache_custom_field[$c_field_id] ) ) { 115 return $g_cache_custom_field[$c_field_id]; 116 } 117 118 $query = "SELECT * 119 FROM $t_custom_field_table 120 WHERE id=" . db_param(); 121 $result = db_query_bound( $query, Array( $c_field_id ) ); 122 123 if( 0 == db_num_rows( $result ) ) { 124 if( $p_trigger_errors ) { 125 error_parameters( 'Custom ' . $p_field_id ); 126 trigger_error( ERROR_CUSTOM_FIELD_NOT_FOUND, ERROR ); 127 } else { 128 return false; 129 } 130 } 131 132 $row = db_fetch_array( $result ); 133 134 $g_cache_custom_field[$c_field_id] = $row; 135 $g_cache_name_to_id_map[$row['name']] = $c_field_id; 136 137 return $row; 138 } 139 140 /** 141 * Cache custom fields contained within an array of field id's 142 * @param array $p_cf_id_array array of custom field id's 143 * @return null 144 * @access public 145 */ 146 function custom_field_cache_array_rows( $p_cf_id_array ) { 147 global $g_cache_custom_field; 148 $c_cf_id_array = array(); 149 150 foreach( $p_cf_id_array as $t_cf_id ) { 151 if( !isset( $g_cache_custom_field[(int) $t_cf_id] ) ) { 152 $c_cf_id_array[] = (int) $t_cf_id; 153 } 154 } 155 156 if( empty( $c_cf_id_array ) ) { 157 return; 158 } 159 160 $t_custom_field_table = db_get_table( 'custom_field' ); 161 162 $query = "SELECT * 163 FROM $t_custom_field_table 164 WHERE id IN (" . implode( ',', $c_cf_id_array ) . ')'; 165 $result = db_query_bound( $query ); 166 167 while( $row = db_fetch_array( $result ) ) { 168 $g_cache_custom_field[(int) $row['id']] = $row; 169 } 170 return; 171 } 172 173 /** 174 * Clear the custom field cache (or just the given id if specified) 175 * @param int $p_field_id custom field id 176 * @return bool 177 * @access public 178 */ 179 function custom_field_clear_cache( $p_field_id = null ) { 180 global $g_cache_custom_field, $g_cached_custom_field_lists; 181 182 $g_cached_custom_field_lists = null; 183 184 if( null === $p_field_id ) { 185 $g_cache_custom_field = array(); 186 } else { 187 $c_field_id = db_prepare_int( $p_field_id ); 188 unset( $g_cache_custom_field[$c_field_id] ); 189 } 190 191 return true; 192 } 193 194 /** 195 * Check to see whether the field is included in the given project 196 * return true if the field is included, false otherwise 197 * @param int $p_field_id custom field id 198 * @param int $p_project_id project id 199 * @return bool 200 * @access public 201 */ 202 function custom_field_is_linked( $p_field_id, $p_project_id ) { 203 global $g_cache_cf_linked; 204 205 $c_project_id = db_prepare_int( $p_project_id ); 206 $c_field_id = db_prepare_int( $p_field_id ); 207 208 if( isset( $g_cache_cf_linked[$c_project_id] ) ) { 209 if( in_array( $c_field_id, $g_cache_cf_linked[$p_project_id] ) ) { 210 return true; 211 } 212 return false; 213 } 214 215 # figure out if this bug_id/field_id combination exists 216 $t_custom_field_project_table = db_get_table( 'custom_field_project' ); 217 $query = "SELECT COUNT(*) 218 FROM $t_custom_field_project_table 219 WHERE field_id=" . db_param() . " AND 220 project_id=" . db_param(); 221 $result = db_query_bound( $query, Array( $c_field_id, $c_project_id ) ); 222 $count = db_result( $result ); 223 224 if( $count > 0 ) { 225 return true; 226 } else { 227 return false; 228 } 229 } 230 231 /** 232 * Check to see whether the field id is defined 233 * return true if the field is defined, false otherwise 234 * @param int $p_field_id custom field id 235 * @return bool 236 * @access public 237 */ 238 function custom_field_exists( $p_field_id ) { 239 if( false == custom_field_cache_row( $p_field_id, false ) ) { 240 return false; 241 } else { 242 return true; 243 } 244 } 245 246 /** 247 * Return the type of a custom field if it exists. 248 * @param int $p_field_id custom field id 249 * @return int custom field type 250 * @access public 251 */ 252 function custom_field_type( $p_field_id ) { 253 $t_field = custom_field_cache_row( $p_field_id, false ); 254 if( $t_field == false ) { 255 return - 1; 256 } else { 257 return $t_field['type']; 258 } 259 } 260 261 /** 262 * Check to see whether the field id is defined 263 * return true if the field is defined, error otherwise 264 * @param int $p_field_id custom field id 265 * @return bool 266 * @access public 267 */ 268 function custom_field_ensure_exists( $p_field_id ) { 269 if( custom_field_exists( $p_field_id ) ) { 270 return true; 271 } else { 272 error_parameters( 'Custom ' . $p_field_id ); 273 trigger_error( ERROR_CUSTOM_FIELD_NOT_FOUND, ERROR ); 274 } 275 } 276 277 /** 278 * Check to see whether the name is unique 279 * return false if a field with the name already exists, true otherwise 280 * if an id is specified, then the corresponding record is excluded from the 281 * uniqueness test. 282 * @param string $p_name custom field name 283 * @param int $p_custom_field_id custom field id 284 * @return bool 285 * @access public 286 */ 287 function custom_field_is_name_unique( $p_name, $p_custom_field_id = null ) { 288 $t_custom_field_table = db_get_table( 'custom_field' ); 289 $query = "SELECT COUNT(*) 290 FROM $t_custom_field_table 291 WHERE name=" . db_param(); 292 if( $p_custom_field_id !== null ) { 293 $c_id = db_prepare_int( $p_custom_field_id ); 294 $query .= ' AND (id <> ' . db_param() . ')'; 295 } 296 $result = db_query_bound( $query, ( ($p_custom_field_id !== null) ? Array( $p_name, $c_id ) : Array( $p_name ) ) ); 297 $count = db_result( $result ); 298 299 if( $count > 0 ) { 300 return false; 301 } else { 302 return true; 303 } 304 } 305 306 /** 307 * Check to see whether the name is unique 308 * return true if the name has not been used, error otherwise 309 * @param string $p_name Custom field name 310 * @return bool 311 * @access public 312 */ 313 function custom_field_ensure_name_unique( $p_name ) { 314 if( custom_field_is_name_unique( $p_name ) ) { 315 return true; 316 } else { 317 trigger_error( ERROR_CUSTOM_FIELD_NAME_NOT_UNIQUE, ERROR ); 318 } 319 } 320 321 /** 322 * Return true if the user can read the value of the field for the given bug, 323 * false otherwise. 324 * @param int $p_field_id custom field id 325 * @param int $p_bug_id bug id 326 * @param int $p_user_id user id 327 * @return bool 328 * @access public 329 */ 330 function custom_field_has_read_access( $p_field_id, $p_bug_id, $p_user_id = null ) { 331 custom_field_ensure_exists( $p_field_id ); 332 333 if( null === $p_user_id ) { 334 $p_user_id = auth_get_current_user_id(); 335 } 336 337 $t_access_level_r = custom_field_get_field( $p_field_id, 'access_level_r' ); 338 339 $t_project_id = bug_get_field( $p_bug_id, 'project_id' ); 340 341 return access_has_project_level( $t_access_level_r, $t_project_id, $p_user_id ); 342 } 343 344 /** 345 * Return true if the user can read the value of the field for the given project, 346 * false otherwise. 347 * @param int $p_field_id custom field id 348 * @param int $p_project_id bug id 349 * @param int $p_user_id user id 350 * @return bool 351 * @access public 352 */ 353 function custom_field_has_read_access_by_project_id( $p_field_id, $p_project_id, $p_user_id = null ) { 354 custom_field_ensure_exists( $p_field_id ); 355 356 if( null === $p_user_id ) { 357 $p_user_id = auth_get_current_user_id(); 358 } 359 360 $t_access_level_r = custom_field_get_field( $p_field_id, 'access_level_r' ); 361 362 return access_has_project_level( $t_access_level_r, $p_project_id, $p_user_id ); 363 } 364 365 /** 366 * Return true if the user can modify the value of the field for the given project, 367 * false otherwise. 368 * @param int $p_field_id custom field id 369 * @param int $p_project_id bug id 370 * @param int $p_user_id user id 371 * @return bool 372 * @access public 373 */ 374 function custom_field_has_write_access_to_project( $p_field_id, $p_project_id, $p_user_id = null ) { 375 custom_field_ensure_exists( $p_field_id ); 376 377 if( null === $p_user_id ) { 378 $p_user_id = auth_get_current_user_id(); 379 } 380 381 $t_access_level_rw = custom_field_get_field( $p_field_id, 'access_level_rw' ); 382 383 return access_has_project_level( $t_access_level_rw, $p_project_id, $p_user_id ); 384 } 385 386 /** 387 * Return true if the user can modify the value of the field for the given bug, 388 * false otherwise. 389 * @param int $p_field_id custom field id 390 * @param int $p_bug_id bug id 391 * @param int $p_user_id user id 392 * @return bool 393 * @access public 394 */ 395 function custom_field_has_write_access( $p_field_id, $p_bug_id, $p_user_id = null ) { 396 $t_project_id = bug_get_field( $p_bug_id, 'project_id' ); 397 return( custom_field_has_write_access_to_project( $p_field_id, $t_project_id, $p_user_id ) ); 398 } 399 400 /** 401 * create a new custom field with the name $p_name 402 * the definition are the default values and can be changes later 403 * return the ID of the new definition 404 * @param string $p_name custom field name 405 * @return int custom field id 406 * @access public 407 */ 408 function custom_field_create( $p_name ) { 409 410 $c_name = trim( $p_name ); 411 412 if( is_blank( $c_name ) ) { 413 error_parameters( 'name' ); 414 trigger_error( ERROR_EMPTY_FIELD, ERROR ); 415 } 416 417 custom_field_ensure_name_unique( $c_name ); 418 419 $t_custom_field_table = db_get_table( 'custom_field' ); 420 $query = "INSERT INTO $t_custom_field_table 421 ( name, possible_values ) 422 VALUES 423 ( " . db_param() . ',' . db_param() . ')'; 424 425 db_query_bound( $query, Array( $c_name, '' ) ); 426 427 return db_insert_id( $t_custom_field_table ); 428 } 429 430 /** 431 * Update the field definition 432 * return true on success, false on failure 433 * @param int $p_field_id custom field id 434 * @param array custom field definition 435 * @return bool 436 * @access public 437 */ 438 function custom_field_update( $p_field_id, $p_def_array ) { 439 $c_field_id = db_prepare_int( $p_field_id ); 440 $c_name = db_prepare_string( trim( $p_def_array['name'] ) ); 441 $c_type = db_prepare_int( $p_def_array['type'] ); 442 $c_possible_values = db_prepare_string( $p_def_array['possible_values'] ); 443 $c_default_value = db_prepare_string( $p_def_array['default_value'] ); 444 $c_valid_regexp = db_prepare_string( $p_def_array['valid_regexp'] ); 445 $c_access_level_r = db_prepare_int( $p_def_array['access_level_r'] ); 446 $c_access_level_rw = db_prepare_int( $p_def_array['access_level_rw'] ); 447 $c_length_min = db_prepare_int( $p_def_array['length_min'] ); 448 $c_length_max = db_prepare_int( $p_def_array['length_max'] ); 449 $c_filter_by = db_prepare_bool( $p_def_array['filter_by'] ); 450 $c_display_report = db_prepare_bool( $p_def_array['display_report'] ); 451 $c_display_update = db_prepare_bool( $p_def_array['display_update'] ); 452 $c_display_resolved = db_prepare_bool( $p_def_array['display_resolved'] ); 453 $c_display_closed = db_prepare_bool( $p_def_array['display_closed'] ); 454 $c_require_report = db_prepare_bool( $p_def_array['require_report'] ); 455 $c_require_update = db_prepare_bool( $p_def_array['require_update'] ); 456 $c_require_resolved = db_prepare_bool( $p_def_array['require_resolved'] ); 457 $c_require_closed = db_prepare_bool( $p_def_array['require_closed'] ); 458 459 if( is_blank( $c_name ) ) { 460 error_parameters( 'name' ); 461 trigger_error( ERROR_EMPTY_FIELD, ERROR ); 462 } 463 464 if(( $c_access_level_rw < $c_access_level_r ) || ( $c_length_min < 0 ) || (( $c_length_max != 0 ) && ( $c_length_min > $c_length_max ) ) ) { 465 trigger_error( ERROR_CUSTOM_FIELD_INVALID_DEFINITION, ERROR ); 466 } 467 468 if( !custom_field_is_name_unique( $c_name, $c_field_id ) ) { 469 trigger_error( ERROR_CUSTOM_FIELD_NAME_NOT_UNIQUE, ERROR ); 470 } 471 472 $t_update_something = false; 473 $t_mantis_custom_field_table = db_get_table( 'custom_field' ); 474 $query = "UPDATE $t_mantis_custom_field_table 475 SET "; 476 if( array_key_exists( 'name', $p_def_array ) ) { 477 if( !$t_update_something ) { 478 $t_update_something = true; 479 } else { 480 $query .= ', '; 481 } 482 $query .= "name='$c_name'"; 483 } 484 if( array_key_exists( 'type', $p_def_array ) ) { 485 if( !$t_update_something ) { 486 $t_update_something = true; 487 } else { 488 $query .= ', '; 489 } 490 $query .= "type='$c_type'"; 491 } 492 if( array_key_exists( 'possible_values', $p_def_array ) ) { 493 if( !$t_update_something ) { 494 $t_update_something = true; 495 } else { 496 $query .= ', '; 497 } 498 $query .= "possible_values='$c_possible_values'"; 499 } 500 if( array_key_exists( 'default_value', $p_def_array ) ) { 501 if( !$t_update_something ) { 502 $t_update_something = true; 503 } else { 504 $query .= ', '; 505 } 506 $query .= "default_value='$c_default_value'"; 507 } 508 if( array_key_exists( 'valid_regexp', $p_def_array ) ) { 509 if( !$t_update_something ) { 510 $t_update_something = true; 511 } else { 512 $query .= ', '; 513 } 514 $query .= "valid_regexp='$c_valid_regexp'"; 515 } 516 if( array_key_exists( 'access_level_r', $p_def_array ) ) { 517 if( !$t_update_something ) { 518 $t_update_something = true; 519 } else { 520 $query .= ', '; 521 } 522 $query .= "access_level_r='$c_access_level_r'"; 523 } 524 if( array_key_exists( 'access_level_rw', $p_def_array ) ) { 525 if( !$t_update_something ) { 526 $t_update_something = true; 527 } else { 528 $query .= ', '; 529 } 530 $query .= "access_level_rw='$c_access_level_rw'"; 531 } 532 if( array_key_exists( 'length_min', $p_def_array ) ) { 533 if( !$t_update_something ) { 534 $t_update_something = true; 535 } else { 536 $query .= ', '; 537 } 538 $query .= "length_min='$c_length_min'"; 539 } 540 if( array_key_exists( 'length_max', $p_def_array ) ) { 541 if( !$t_update_something ) { 542 $t_update_something = true; 543 } else { 544 $query .= ', '; 545 } 546 $query .= "length_max='$c_length_max'"; 547 } 548 if( array_key_exists( 'filter_by', $p_def_array ) ) { 549 if( !$t_update_something ) { 550 $t_update_something = true; 551 } else { 552 $query .= ', '; 553 } 554 $query .= "filter_by='$c_filter_by'"; 555 } 556 if( array_key_exists( 'display_report', $p_def_array ) ) { 557 if( !$t_update_something ) { 558 $t_update_something = true; 559 } else { 560 $query .= ', '; 561 } 562 $query .= "display_report='$c_display_report'"; 563 } 564 if( array_key_exists( 'display_update', $p_def_array ) ) { 565 if( !$t_update_something ) { 566 $t_update_something = true; 567 } else { 568 $query .= ', '; 569 } 570 $query .= "display_update='$c_display_update'"; 571 } 572 if( array_key_exists( 'display_resolved', $p_def_array ) ) { 573 if( !$t_update_something ) { 574 $t_update_something = true; 575 } else { 576 $query .= ', '; 577 } 578 $query .= "display_resolved='$c_display_resolved'"; 579 } 580 if( array_key_exists( 'display_closed', $p_def_array ) ) { 581 if( !$t_update_something ) { 582 $t_update_something = true; 583 } else { 584 $query .= ', '; 585 } 586 $query .= "display_closed='$c_display_closed'"; 587 } 588 if( array_key_exists( 'require_report', $p_def_array ) ) { 589 if( !$t_update_something ) { 590 $t_update_something = true; 591 } else { 592 $query .= ', '; 593 } 594 $query .= "require_report='$c_require_report'"; 595 } 596 if( array_key_exists( 'require_update', $p_def_array ) ) { 597 if( !$t_update_something ) { 598 $t_update_something = true; 599 } else { 600 $query .= ', '; 601 } 602 $query .= "require_update='$c_require_update'"; 603 } 604 if( array_key_exists( 'require_resolved', $p_def_array ) ) { 605 if( !$t_update_something ) { 606 $t_update_something = true; 607 } else { 608 $query .= ', '; 609 } 610 $query .= "require_resolved='$c_require_resolved'"; 611 } 612 if( array_key_exists( 'require_closed', $p_def_array ) ) { 613 if( !$t_update_something ) { 614 $t_update_something = true; 615 } else { 616 $query .= ', '; 617 } 618 $query .= "require_closed='$c_require_closed'"; 619 } 620 621 $query .= " WHERE id='$c_field_id'"; 622 623 if( $t_update_something ) { 624 db_query( $query ); 625 custom_field_clear_cache( $p_field_id ); 626 } else { 627 return false; 628 629 # there is nothing to update... 630 } 631 632 # db_query errors on failure so: 633 return true; 634 } 635 636 /** 637 * Add a custom field to a project 638 * return true on success, false on failure or if already added 639 * @param int $p_field_id custom field id 640 * @param int $p_project_id project id 641 * @return bool 642 * @access public 643 */ 644 function custom_field_link( $p_field_id, $p_project_id ) { 645 $c_field_id = db_prepare_int( $p_field_id ); 646 $c_project_id = db_prepare_int( $p_project_id ); 647 648 custom_field_ensure_exists( $p_field_id ); 649 project_ensure_exists( $p_project_id ); 650 651 if( custom_field_is_linked( $p_field_id, $p_project_id ) ) { 652 return false; 653 } 654 655 $t_custom_field_project_table = db_get_table( 'custom_field_project' ); 656 $query = "INSERT INTO $t_custom_field_project_table 657 ( field_id, project_id ) 658 VALUES 659 ( " . db_param() . ', ' . db_param() . ')'; 660 db_query_bound( $query, Array( $c_field_id, $c_project_id ) ); 661 662 # db_query errors on failure so: 663 return true; 664 } 665 666 /** 667 * Remove a custom field from a project 668 * return true on success, false on failure 669 * 670 * The values for the custom fields are not deleted. This is to allow for the 671 * case where a bug is moved to another project that has the field, or the 672 * field is linked again to the project. 673 * @param int $p_field_id custom field id 674 * @param int $p_project_id project id 675 * @return bool 676 * @access public 677 */ 678 function custom_field_unlink( $p_field_id, $p_project_id ) { 679 $c_field_id = db_prepare_int( $p_field_id ); 680 $c_project_id = db_prepare_int( $p_project_id ); 681 682 $t_custom_field_project_table = db_get_table( 'custom_field_project' ); 683 $query = "DELETE FROM $t_custom_field_project_table 684 WHERE field_id = " . db_param() . " AND 685 project_id = " . db_param(); 686 db_query_bound( $query, Array( $c_field_id, $c_project_id ) ); 687 688 # db_query errors on failure so: 689 return true; 690 } 691 692 /** 693 * Delete the field definition and all associated values and project associations 694 * return true on success, false on failure 695 * @param int $p_field_id custom field id 696 * @return bool 697 * @access public 698 */ 699 function custom_field_destroy( $p_field_id ) { 700 $c_field_id = db_prepare_int( $p_field_id ); 701 702 # delete all values 703 $t_custom_field_string_table = db_get_table( 'custom_field_string' ); 704 $query = "DELETE FROM $t_custom_field_string_table 705 WHERE field_id=" . db_param(); 706 db_query_bound( $query, Array( $c_field_id ) ); 707 708 # delete all project associations 709 $t_custom_field_project_table = db_get_table( 'custom_field_project' ); 710 $query = "DELETE FROM $t_custom_field_project_table 711 WHERE field_id=" . db_param(); 712 db_query_bound( $query, Array( $c_field_id ) ); 713 714 $t_custom_field_table = db_get_table( 'custom_field' ); 715 716 # delete the definition 717 $query = "DELETE FROM $t_custom_field_table 718 WHERE id=" . db_param(); 719 db_query_bound( $query, Array( $c_field_id ) ); 720 721 custom_field_clear_cache( $p_field_id ); 722 723 # db_query errors on failure so: 724 return true; 725 } 726 727 /** 728 * Delete all associations of custom fields to the specified project 729 * return true on success, false on failure 730 * 731 * To be called from within project_delete(). 732 * @param int $p_project_id project id 733 * @return bool 734 * @access public 735 */ 736 function custom_field_unlink_all( $p_project_id ) { 737 $c_project_id = db_prepare_int( $p_project_id ); 738 739 # delete all project associations 740 $t_custom_field_project_table = db_get_table( 'custom_field_project' ); 741 $query = "DELETE FROM $t_custom_field_project_table 742 WHERE project_id=" . db_param(); 743 db_query_bound( $query, Array( $c_project_id ) ); 744 745 # db_query errors on failure so: 746 return true; 747 } 748 749 /** 750 * Delete all custom values associated with the specified bug. 751 * return true on success, false on failure 752 * 753 * To be called from bug_delete(). 754 * @param int $p_bug_id bug id 755 * @return bool 756 * @access public 757 */ 758 function custom_field_delete_all_values( $p_bug_id ) { 759 $c_bug_id = db_prepare_int( $p_bug_id ); 760 761 $t_custom_field_string_table = db_get_table( 'custom_field_string' ); 762 $query = "DELETE FROM $t_custom_field_string_table 763 WHERE bug_id=" . db_param(); 764 db_query_bound( $query, Array( $c_bug_id ) ); 765 766 # db_query errors on failure so: 767 return true; 768 } 769 770 /** 771 * Get the id of the custom field with the specified name. 772 * false is returned if no custom field found with the specified name. 773 * @param string $p_field_name custom field name 774 * @param int $p_truncated_length 775 * @return bool|int false or custom field id 776 * @access public 777 */ 778 function custom_field_get_id_from_name( $p_field_name, $p_truncated_length = null ) { 779 global $g_cache_name_to_id_map; 780 781 if ( is_blank( $p_field_name ) ) { 782 return false; 783 } 784 785 if ( isset( $g_cache_name_to_id_map[$p_field_name] ) ) { 786 return $g_cache_name_to_id_map[$p_field_name]; 787 } 788 789 $t_custom_field_table = db_get_table( 'custom_field' ); 790 791 $c_field_name = db_prepare_string( $p_field_name ); 792 793 if(( null === $p_truncated_length ) || ( utf8_strlen( $c_field_name ) != $p_truncated_length ) ) { 794 $query = "SELECT id FROM $t_custom_field_table WHERE name = '$c_field_name'"; 795 } else { 796 /** @todo This is to handle the case where we only have a truncated part of the name. This happens in the case where 797 * we are getting the custom field name from the history logs, since history is 32 and custom field name is 64. 798 * This fix will handle entries already in the database, future entries should be handled by making the field name max lengths match. 799 */ 800 $query = "SELECT id FROM $t_custom_field_table WHERE name LIKE '$c_field_name%'"; 801 } 802 803 $t_result = db_query( $query, 1 ); 804 805 if( db_num_rows( $t_result ) == 0 ) { 806 return false; 807 } 808 809 $row = db_fetch_array( $t_result ); 810 $g_cache_name_to_id_map[$p_field_name] = $row['id']; 811 812 return $row['id']; 813 } 814 815 /** 816 * Return an array of ids of custom fields bound to the specified project 817 * 818 * The ids will be sorted based on the sequence number associated with the binding 819 * @param int $p_project_id project id 820 * @return array 821 * @access public 822 */ 823 function custom_field_get_linked_ids( $p_project_id = ALL_PROJECTS ) { 824 global $g_cache_cf_linked, $g_cache_custom_field; 825 826 if( !isset( $g_cache_cf_linked[$p_project_id] ) ) { 827 828 $t_custom_field_table = db_get_table( 'custom_field' ); 829 $t_custom_field_project_table = db_get_table( 'custom_field_project' ); 830 831 if( ALL_PROJECTS == $p_project_id ) { 832 $t_project_user_list_table = db_get_table( 'project_user_list' ); 833 $t_project_table = db_get_table( 'project' ); 834 $t_user_table = db_get_table( 'user' ); 835 $t_user_id = auth_get_current_user_id(); 836 $t_pub = VS_PUBLIC; 837 $t_priv = VS_PRIVATE; 838 839 $t_private_access = config_get( 'private_project_threshold' ); 840 if( is_array( $t_private_access ) ) { 841 if( 1 == count( $t_private_access ) ) { 842 $t_access_clause = '= ' . array_shift( $t_private_access ) . ' '; 843 } else { 844 $t_access_clause = 'IN (' . implode( ',', $t_private_access ) . ')'; 845 } 846 } else { 847 $t_access_clause = ">= $t_private_access "; 848 } 849 850 # select only the ids that the user has some access to 851 # e.g., all fields in public projects, or private projects where the user is listed 852 # or private projects where the user is implicitly listed 853 $query = "SELECT DISTINCT cft.id 854 FROM $t_custom_field_table cft, $t_user_table ut, $t_project_table pt, $t_custom_field_project_table cfpt 855 LEFT JOIN $t_project_user_list_table pult 856 on cfpt.project_id = pult.project_id and pult.user_id = $t_user_id 857 WHERE cft.id = cfpt.field_id AND cfpt.project_id = pt.id AND ut.id = $t_user_id AND 858 ( pt.view_state = $t_pub OR 859 ( pt.view_state = $t_priv and pult.user_id = $t_user_id ) OR 860 ( pult.user_id is null and ut.access_level $t_access_clause ) )"; 861 } else { 862 if( is_array( $p_project_id ) ) { 863 if( 1 == count( $p_project_id ) ) { 864 $t_project_clause = '= ' . array_shift( $p_project_id ) . ' '; 865 } else { 866 $t_project_clause = 'IN (' . implode( ',', $p_project_id ) . ')'; 867 } 868 } else { 869 $t_project_clause = '= ' . $p_project_id; 870 } 871 $query = "SELECT cft.id 872 FROM $t_custom_field_table cft, $t_custom_field_project_table cfpt 873 WHERE cfpt.project_id $t_project_clause AND 874 cft.id = cfpt.field_id 875 ORDER BY sequence ASC, name ASC"; 876 } 877 $result = db_query( $query ); 878 $t_row_count = db_num_rows( $result ); 879 $t_ids = array(); 880 881 for( $i = 0;$i < $t_row_count;$i++ ) { 882 $row = db_fetch_array( $result ); 883 array_push( $t_ids, $row['id'] ); 884 } 885 custom_field_cache_array_rows( $t_ids ); 886 887 $g_cache_cf_linked[$p_project_id] = $t_ids; 888 } else { 889 $t_ids = $g_cache_cf_linked[$p_project_id]; 890 } 891 return $t_ids; 892 } 893 894 /** 895 * Return an array all custom field ids sorted by name 896 * @return array 897 * @access public 898 */ 899 function custom_field_get_ids() { 900 global $g_cache_cf_list, $g_cache_custom_field; 901 902 if( $g_cache_cf_list === NULL ) { 903 $t_custom_field_table = db_get_table( 'custom_field' ); 904 $query = "SELECT * 905 FROM $t_custom_field_table 906 ORDER BY name ASC"; 907 $result = db_query_bound( $query ); 908 $t_row_count = db_num_rows( $result ); 909 $t_ids = array(); 910 911 for( $i = 0;$i < $t_row_count;$i++ ) { 912 $row = db_fetch_array( $result ); 913 914 $g_cache_custom_field[(int) $row['id']] = $row; 915 916 array_push( $t_ids, $row['id'] ); 917 } 918 $g_cache_cf_list = $t_ids; 919 } else { 920 $t_ids = $g_cache_cf_list; 921 } 922 return $t_ids; 923 } 924 925 /** 926 * Return an array of ids of projects related to the specified custom field 927 * (the array may be empty) 928 * @param int $p_field_id custom field id 929 * @return array 930 * @access public 931 */ 932 function custom_field_get_project_ids( $p_field_id ) { 933 $c_field_id = db_prepare_int( $p_field_id ); 934 935 $t_custom_field_project_table = db_get_table( 'custom_field_project' ); 936 $query = "SELECT project_id 937 FROM $t_custom_field_project_table 938 WHERE field_id = " . db_param(); 939 $result = db_query_bound( $query, Array( $c_field_id ) ); 940 941 $t_row_count = db_num_rows( $result ); 942 $t_ids = array(); 943 944 for( $i = 0;$i < $t_row_count;$i++ ) { 945 $row = db_fetch_array( $result ); 946 947 array_push( $t_ids, $row['project_id'] ); 948 } 949 950 return $t_ids; 951 } 952 953 /** 954 * Return a field definition row for the field or error if the field does not exist 955 * @param int $p_field_id custom field id 956 * @return array custom field definition 957 * @access public 958 */ 959 function custom_field_get_definition( $p_field_id ) { 960 return custom_field_cache_row( $p_field_id ); 961 } 962 963 /** 964 * Return a single database field from a custom field definition row for the field 965 * if the database field does not exist, display a warning and return '' 966 * @param int $p_field_id custom field id 967 * @param int $p_field_name custom field name 968 * @return string 969 * @access public 970 */ 971 function custom_field_get_field( $p_field_id, $p_field_name ) { 972 $row = custom_field_get_definition( $p_field_id ); 973 974 if( isset( $row[$p_field_name] ) ) { 975 return $row[$p_field_name]; 976 } else { 977 error_parameters( $p_field_name ); 978 trigger_error( ERROR_DB_FIELD_NOT_FOUND, WARNING ); 979 return ''; 980 } 981 } 982 983 /** 984 * Get the value of a custom field for the given bug 985 * @todo return values are unclear... should we error when access is denied 986 * and provide an api to check whether it will be? 987 * @param int $p_field_id custom field id 988 * @param int $p_bug_id bug id 989 * @return mixed: value is defined, null: no value is defined, false: read access is denied 990 * @access public 991 */ 992 function custom_field_get_value( $p_field_id, $p_bug_id ) { 993 $c_field_id = db_prepare_int( $p_field_id ); 994 $c_bug_id = db_prepare_int( $p_bug_id ); 995 996 $row = custom_field_cache_row( $p_field_id ); 997 998 $t_access_level_r = $row['access_level_r']; 999 $t_default_value = $row['default_value']; 1000 1001 if( !custom_field_has_read_access( $p_field_id, $p_bug_id, auth_get_current_user_id() ) ) { 1002 return false; 1003 } 1004 1005 $t_value_field = ( $row['type'] == CUSTOM_FIELD_TYPE_TEXTAREA ? 'text' : 'value' ); 1006 1007 $t_custom_field_string_table = db_get_table( 'custom_field_string' ); 1008 $query = "SELECT $t_value_field 1009 FROM $t_custom_field_string_table 1010 WHERE bug_id=" . db_param() . " AND 1011 field_id=" . db_param(); 1012 $result = db_query_bound( $query, Array( $c_bug_id, $c_field_id ) ); 1013 1014 if( db_num_rows( $result ) > 0 ) { 1015 return custom_field_database_to_value( db_result( $result ), $row['type'] ); 1016 } else { 1017 return null; 1018 } 1019 } 1020 1021 /** 1022 * Gets the custom fields array for the given bug readable by specified level. 1023 * Array keys are custom field names. Array is sorted by custom field sequence number; 1024 * Array items are arrays with the next keys: 1025 * 'type', 'value', 'access_level_r' 1026 * @param int $p_bug_id bug id 1027 * @param int $p_user_access_level Access level 1028 * @return array 1029 * @access public 1030 */ 1031 function custom_field_get_linked_fields( $p_bug_id, $p_user_access_level ) { 1032 $t_custom_fields = custom_field_get_all_linked_fields( $p_bug_id ); 1033 1034 # removing restricted fields 1035 foreach( $t_custom_fields as $t_custom_field_name => $t_custom_field_data ) { 1036 if( $p_user_access_level < $t_custom_field_data['access_level_r'] ) { 1037 unset( $t_custom_fields[$t_custom_field_name] ); 1038 } 1039 } 1040 return $t_custom_fields; 1041 } 1042 1043 /** 1044 * Gets the custom fields array for the given bug. Array keys are custom field names. 1045 * Array is sorted by custom field sequence number; Array items are arrays with the next keys: 1046 * 'type', 'value', 'access_level_r' 1047 * @param int $p_bug_id bug id 1048 * @return array 1049 * @access public 1050 */ 1051 function custom_field_get_all_linked_fields( $p_bug_id ) { 1052 global $g_cached_custom_field_lists; 1053 1054 if( !is_array( $g_cached_custom_field_lists ) ) { 1055 $g_cached_custom_field_lists = array(); 1056 } 1057 1058 # is the list in cache ? 1059 if( !array_key_exists( $p_bug_id, $g_cached_custom_field_lists ) ) { 1060 $c_bug_id = db_prepare_int( $p_bug_id ); 1061 $c_project_id = db_prepare_int( bug_get_field( $p_bug_id, 'project_id' ) ); 1062 1063 $t_custom_field_project_table = db_get_table( 'custom_field_project' ); 1064 $t_custom_field_table = db_get_table( 'custom_field' ); 1065 $t_custom_field_string_table = db_get_table( 'custom_field_string' ); 1066 1067 $query = "SELECT f.name, f.type, f.access_level_r, f.default_value, f.type, s.value 1068 FROM $t_custom_field_project_table p INNER JOIN $t_custom_field_table f 1069 ON p.field_id = f.id 1070 LEFT JOIN $t_custom_field_string_table s 1071 ON p.field_id=s.field_id AND s.bug_id='$c_bug_id' 1072 WHERE p.project_id = '$c_project_id' 1073 ORDER BY p.sequence ASC, f.name ASC"; 1074 1075 $result = db_query( $query ); 1076 1077 $t_row_count = db_num_rows( $result ); 1078 1079 $t_custom_fields = array(); 1080 1081 for( $i = 0;$i < $t_row_count;++$i ) { 1082 $row = db_fetch_array( $result ); 1083 1084 if( is_null( $row['value'] ) ) { 1085 $t_value = $row['default_value']; 1086 } else { 1087 $t_value = custom_field_database_to_value( $row['value'], $row['type'] ); 1088 } 1089 1090 $t_custom_fields[$row['name']] = array( 1091 'type' => $row['type'], 1092 'value' => $t_value, 1093 'access_level_r' => $row['access_level_r'], 1094 ); 1095 } 1096 1097 $g_cached_custom_field_lists[$p_bug_id] = $t_custom_fields; 1098 } 1099 1100 return $g_cached_custom_field_lists[$p_bug_id]; 1101 } 1102 1103 /** 1104 * Gets the sequence number for the specified custom field for the specified 1105 * project. Returns false in case of error. 1106 * @param int $p_field_id custom field id 1107 * @param int $p_project_id project id 1108 * @return int|bool 1109 * @access public 1110 */ 1111 function custom_field_get_sequence( $p_field_id, $p_project_id ) { 1112 $c_field_id = db_prepare_int( $p_field_id ); 1113 $c_project_id = db_prepare_int( $p_project_id ); 1114 1115 $t_custom_field_project_table = db_get_table( 'custom_field_project' ); 1116 $query = "SELECT sequence 1117 FROM $t_custom_field_project_table 1118 WHERE field_id=" . db_param() . " AND 1119 project_id=" . db_param(); 1120 $result = db_query_bound( $query, Array( $c_field_id, $c_project_id ), 1 ); 1121 1122 if( 0 == db_num_rows( $result ) ) { 1123 return false; 1124 } 1125 1126 $t_row = db_fetch_array( $result ); 1127 1128 return $t_row['sequence']; 1129 } 1130 1131 /** 1132 * Allows the validation of a custom field value without setting it 1133 * or needing a bug to exist. 1134 * @param int $p_field_id custom field id 1135 * @param string $p_value custom field value 1136 * @return bool 1137 * @access public 1138 */ 1139 function custom_field_validate( $p_field_id, $p_value ) { 1140 $c_field_id = db_prepare_int( $p_field_id ); 1141 1142 custom_field_ensure_exists( $p_field_id ); 1143 1144 $t_custom_field_table = db_get_table( 'custom_field' ); 1145 $query = "SELECT name, type, possible_values, valid_regexp, 1146 access_level_rw, length_min, length_max, default_value 1147 FROM $t_custom_field_table 1148 WHERE id=" . db_param(); 1149 $result = db_query_bound( $query, Array( $c_field_id ) ); 1150 $row = db_fetch_array( $result ); 1151 1152 $t_name = $row['name']; 1153 $t_type = $row['type']; 1154 $t_possible_values = $row['possible_values']; 1155 $t_valid_regexp = $row['valid_regexp']; 1156 $t_length_min = $row['length_min']; 1157 $t_length_max = $row['length_max']; 1158 $t_default_value = $row['default_value']; 1159 1160 $t_valid = true; 1161 $t_length = utf8_strlen( $p_value ); 1162 switch ($t_type) { 1163 case CUSTOM_FIELD_TYPE_STRING: 1164 # Regular expression string validation 1165 if( !is_blank( $t_valid_regexp ) && !is_blank( $p_value ) ) { 1166 $t_valid &= preg_match( "/$t_valid_regexp/", $p_value ); 1167 } 1168 # Check the length of the string 1169 $t_valid &= ( 0 == $t_length_min ) || ( $t_length >= $t_length_min ); 1170 $t_valid &= ( 0 == $t_length_max ) || ( $t_length <= $t_length_max ); 1171 break; 1172 case CUSTOM_FIELD_TYPE_NUMERIC: 1173 $t_valid &= ( $t_length == 0 ) || is_numeric( $p_value ); 1174 break; 1175 case CUSTOM_FIELD_TYPE_FLOAT: 1176 # Allow both integer and float numbers 1177 $t_valid &= ( $t_length == 0 ) || is_numeric( $p_value ) || is_float( $p_value ); 1178 break; 1179 case CUSTOM_FIELD_TYPE_DATE: 1180 # gpc_get_cf for date returns the value from strftime 1181 # Either false (php >= 5.1) or -1 (php < 5.1) for failure 1182 $t_valid &= ( $p_value == null ) || ( ( $p_value !== false ) && ( $p_value > 0 ) ); 1183 break; 1184 case CUSTOM_FIELD_TYPE_CHECKBOX: 1185 # Checkbox fields can hold a null value (when no checkboxes are ticked) 1186 if( $p_value === '' ) { 1187 break; 1188 } 1189 # If checkbox field value is not null then we need to validate it... (note: no "break" statement here!) 1190 case CUSTOM_FIELD_TYPE_MULTILIST: 1191 $t_values = explode( '|', $p_value ); 1192 $t_possible_values = custom_field_prepare_possible_values( $row['possible_values'] ); 1193 $t_possible_values = explode( '|', $t_possible_values ); 1194 $t_invalid_values = array_diff( $t_values, $t_possible_values ); 1195 $t_valid &= ( count( $t_invalid_values ) == 0 ); 1196 break; 1197 case CUSTOM_FIELD_TYPE_ENUM: 1198 case CUSTOM_FIELD_TYPE_LIST: 1199 case CUSTOM_FIELD_TYPE_RADIO: 1200 $t_possible_values = custom_field_prepare_possible_values( $row['possible_values'] ); 1201 $t_values_arr = explode( '|', $t_possible_values ); 1202 $t_valid &= in_array( $p_value, $t_values_arr ); 1203 break; 1204 case CUSTOM_FIELD_TYPE_EMAIL: 1205 if ( $p_value !== '' ) { 1206 $t_valid &= email_is_valid( $p_value ); 1207 } 1208 break; 1209 default: 1210 break; 1211 } 1212 return (bool)$t_valid; 1213 } 1214 1215 /** 1216 * $p_possible_values: possible values to be pre-processed. If it has enum values, 1217 * it will be left as is. If it has a method, it will be replaced by the list. 1218 * @param string $p_possible_values 1219 * @return string|array 1220 * @access public 1221 */ 1222 function custom_field_prepare_possible_values( $p_possible_values ) { 1223 $t_possible_values = $p_possible_values; 1224 1225 if( !is_blank( $t_possible_values ) && ( $t_possible_values[0] == '=' ) ) { 1226 $t_possible_values = helper_call_custom_function( 'enum_' . utf8_substr( $t_possible_values, 1 ), array() ); 1227 } 1228 1229 return $t_possible_values; 1230 } 1231 1232 /** 1233 * Get All Possible Values for a Field. 1234 * @param array $p_field_def custom field definition 1235 * @param int $p_project_id project id 1236 * @return bool|array 1237 * @access public 1238 */ 1239 function custom_field_distinct_values( $p_field_def, $p_project_id = ALL_PROJECTS ) { 1240 global $g_custom_field_type_definition; 1241 $c_field_id = $p_field_def['id']; 1242 $c_project_id = db_prepare_int( $p_project_id ); 1243 $t_custom_field_string_table = db_get_table( 'custom_field_string' ); 1244 $t_mantis_bug_table = db_get_table( 'bug' ); 1245 $t_return_arr = array(); 1246 1247 # If an enumeration type, we get all possible values, not just used values 1248 if( isset( $g_custom_field_type_definition[$p_field_def['type']]['#function_return_distinct_values'] ) ) { 1249 return call_user_func( $g_custom_field_type_definition[$p_field_def['type']]['#function_return_distinct_values'], $p_field_def ); 1250 } else { 1251 $t_where = ''; 1252 $t_from = $t_custom_field_string_table; 1253 if( ALL_PROJECTS != $p_project_id ) { 1254 $t_where = " AND $t_mantis_bug_table.id = $t_custom_field_string_table.bug_id AND 1255 $t_mantis_bug_table.project_id = '$p_project_id'"; 1256 $t_from = $t_from . ", $t_mantis_bug_table"; 1257 } 1258 $query2 = "SELECT $t_custom_field_string_table.value FROM $t_from 1259 WHERE $t_custom_field_string_table.field_id='$c_field_id' $t_where 1260 GROUP BY $t_custom_field_string_table.value"; 1261 $result2 = db_query( $query2 ); 1262 $t_row_count = db_num_rows( $result2 ); 1263 if( 0 == $t_row_count ) { 1264 return false; 1265 } 1266 1267 for( $i = 0;$i < $t_row_count;$i++ ) { 1268 $row = db_fetch_array( $result2 ); 1269 if( !is_blank( trim( $row['value'] ) ) ) { 1270 array_push( $t_return_arr, $row['value'] ); 1271 } 1272 } 1273 } 1274 return $t_return_arr; 1275 } 1276 1277 /** 1278 * Convert the value to save it into the database, depending of the type 1279 * return value for database 1280 * @param mixed $p_value 1281 * @param int $p_type 1282 * @return mixed 1283 * @access public 1284 */ 1285 function custom_field_value_to_database( $p_value, $p_type ) { 1286 global $g_custom_field_type_definition; 1287 if( isset( $g_custom_field_type_definition[$p_type]['#function_value_to_database'] ) ) { 1288 return call_user_func( $g_custom_field_type_definition[$p_type]['#function_value_to_database'], $p_value ); 1289 } 1290 return $p_value; 1291 } 1292 1293 /** 1294 * Convert the database-value to value, depending of the type 1295 * return value for further operation 1296 * @param mixed $p_value 1297 * @param int $p_type 1298 * @return mixed 1299 * @access public 1300 */ 1301 function custom_field_database_to_value( $p_value, $p_type ) { 1302 global $g_custom_field_type_definition; 1303 if( isset( $g_custom_field_type_definition[$p_type]['#function_database_to_value'] ) ) { 1304 return call_user_func( $g_custom_field_type_definition[$p_type]['#function_database_to_value'], $p_value ); 1305 } 1306 return $p_value; 1307 } 1308 1309 /** 1310 * Convert the default-value to value depending on the type. For example, in case of date, this 1311 * would translate 'tomorrow' to tomorrow's date. 1312 * @param mixed $p_value 1313 * @param int $p_type 1314 * @return mixed 1315 * @access public 1316 */ 1317 function custom_field_default_to_value( $p_value, $p_type ) { 1318 global $g_custom_field_type_definition; 1319 1320 if( isset( $g_custom_field_type_definition[$p_type]['#function_default_to_value'] ) ) { 1321 return call_user_func( $g_custom_field_type_definition[$p_type]['#function_default_to_value'], $p_value ); 1322 } 1323 1324 return $p_value; 1325 } 1326 1327 /** 1328 * Set the value of a custom field for a given bug 1329 * return true on success, false on failure 1330 * @param int $p_field_id custom field id 1331 * @param int $p_bug_id bug id 1332 * @param mixed $p_value 1333 * @param boolean $p_log create history logs for new values 1334 * @return bool 1335 * @access public 1336 */ 1337 function custom_field_set_value( $p_field_id, $p_bug_id, $p_value, $p_log_insert=true ) { 1338 $c_field_id = db_prepare_int( $p_field_id ); 1339 $c_bug_id = db_prepare_int( $p_bug_id ); 1340 1341 custom_field_ensure_exists( $p_field_id ); 1342 1343 if ( !custom_field_validate( $p_field_id, $p_value ) ) 1344 return false; 1345 1346 $t_name = custom_field_get_field( $p_field_id, 'name' ); 1347 $t_type = custom_field_get_field( $p_field_id, 'type' ); 1348 $t_custom_field_string_table = db_get_table( 'custom_field_string' ); 1349 1350 $t_value_field = ( $t_type == CUSTOM_FIELD_TYPE_TEXTAREA ) ? 'text' : 'value'; 1351 1352 # Determine whether an existing value needs to be updated or a new value inserted 1353 $query = "SELECT $t_value_field 1354 FROM $t_custom_field_string_table 1355 WHERE field_id=" . db_param() . " AND 1356 bug_id=" . db_param(); 1357 $result = db_query_bound( $query, Array( $c_field_id, $c_bug_id ) ); 1358 1359 if( db_num_rows( $result ) > 0 ) { 1360 $query = "UPDATE $t_custom_field_string_table 1361 SET $t_value_field=" . db_param() . " 1362 WHERE field_id=" . db_param() . " AND 1363 bug_id=" . db_param(); 1364 db_query_bound( $query, Array( custom_field_value_to_database( $p_value, $t_type ), $c_field_id, $c_bug_id ) ); 1365 1366 $row = db_fetch_array( $result ); 1367 history_log_event_direct( $c_bug_id, $t_name, custom_field_database_to_value( $row[$t_value_field], $t_type ), $p_value ); 1368 } else { 1369 $query = "INSERT INTO $t_custom_field_string_table 1370 ( field_id, bug_id, $t_value_field ) 1371 VALUES 1372 ( " . db_param() . ', ' . db_param() . ', ' . db_param() . ')'; 1373 db_query_bound( $query, Array( $c_field_id, $c_bug_id, custom_field_value_to_database( $p_value, $t_type ) ) ); 1374 # Don't log history events for new bug reports or on other special occasions 1375 if ( $p_log_insert ) { 1376 history_log_event_direct( $c_bug_id, $t_name, '', $p_value ); 1377 } 1378 } 1379 1380 custom_field_clear_cache( $p_field_id ); 1381 1382 # db_query errors on failure so: 1383 return true; 1384 } 1385 1386 /** 1387 * Sets the sequence number for the specified custom field for the specified 1388 * project. 1389 * @param int $p_field_id custom field id 1390 * @param int $p_project_id project id 1391 * @param int $p_sequence 1392 * @return bool 1393 * @access public 1394 */ 1395 function custom_field_set_sequence( $p_field_id, $p_project_id, $p_sequence ) { 1396 $c_field_id = db_prepare_int( $p_field_id ); 1397 $c_project_id = db_prepare_int( $p_project_id ); 1398 $c_sequence = db_prepare_int( $p_sequence ); 1399 1400 $t_custom_field_project_table = db_get_table( 'custom_field_project' ); 1401 1402 $query = "UPDATE $t_custom_field_project_table 1403 SET sequence=" . db_param() . " 1404 WHERE field_id=" . db_param() . " AND 1405 project_id=" . db_param(); 1406 $result = db_query_bound( $query, Array( $c_sequence, $c_field_id, $c_project_id ) ); 1407 1408 custom_field_clear_cache( $p_field_id ); 1409 1410 return true; 1411 } 1412 1413 /** 1414 * Print an input field 1415 * $p_field_def contains the definition of the custom field (including it's field id 1416 * $p_bug_id contains the bug where this field belongs to. If it's left 1417 * away, it'll default to 0 and thus belongs to a new (i.e. non-existant) bug 1418 * NOTE: This probably belongs in the print_api.php 1419 * @param array $p_field_def custom field definition 1420 * @param int $p_bug_id bug id 1421 * @access public 1422 */ 1423 function print_custom_field_input( $p_field_def, $p_bug_id = null ) { 1424 if( null === $p_bug_id ) { 1425 $t_custom_field_value = custom_field_default_to_value( $p_field_def['default_value'], $p_field_def['type'] ); 1426 } else { 1427 $t_custom_field_value = custom_field_get_value( $p_field_def['id'], $p_bug_id ); 1428 # If the custom field value is undefined and the field cannot hold a null value, use the default value instead 1429 if( $t_custom_field_value === null && 1430 ( $p_field_def['type'] == CUSTOM_FIELD_TYPE_ENUM || 1431 $p_field_def['type'] == CUSTOM_FIELD_TYPE_LIST || 1432 $p_field_def['type'] == CUSTOM_FIELD_TYPE_MULTILIST || 1433 $p_field_def['type'] == CUSTOM_FIELD_TYPE_RADIO ) ) { 1434 $t_custom_field_value = custom_field_default_to_value( $p_field_def['default_value'], $p_field_def['type'] ); 1435 } 1436 } 1437 1438 global $g_custom_field_type_definition; 1439 if( isset( $g_custom_field_type_definition[$p_field_def['type']]['#function_print_input'] ) ) { 1440 call_user_func( $g_custom_field_type_definition[$p_field_def['type']]['#function_print_input'], $p_field_def, $t_custom_field_value ); 1441 } else { 1442 trigger_error( ERROR_CUSTOM_FIELD_INVALID_DEFINITION, ERROR ); 1443 } 1444 } 1445 1446 /** 1447 * Prepare a string containing a custom field value for display 1448 * @todo This probably belongs in the string_api.php 1449 * @param array $p_def contains the definition of the custom field 1450 * @param int $p_field_id contains the id of the field 1451 * @param int $p_bug_id contains the bug id to display the custom field value for 1452 * @return string 1453 * @access public 1454 */ 1455 function string_custom_field_value( $p_def, $p_field_id, $p_bug_id ) { 1456 $t_custom_field_value = custom_field_get_value( $p_field_id, $p_bug_id ); 1457 if( $t_custom_field_value === null ) { 1458 return ''; 1459 } 1460 global $g_custom_field_type_definition; 1461 if( isset( $g_custom_field_type_definition[$p_def['type']]['#function_string_value'] ) ) { 1462 return call_user_func( $g_custom_field_type_definition[$p_def['type']]['#function_string_value'], $t_custom_field_value ); 1463 } 1464 return string_display_links( $t_custom_field_value ); 1465 } 1466 1467 /** 1468 * Print a custom field value for display 1469 * NOTE: This probably belongs in the print_api.php 1470 * @param array $p_def contains the definition of the custom field 1471 * @param int $p_field_id contains the id of the field 1472 * @param int $p_bug_id contains the bug id to display the custom field value for 1473 * @return null 1474 * @access public 1475 */ 1476 function print_custom_field_value( $p_def, $p_field_id, $p_bug_id ) { 1477 echo string_custom_field_value( $p_def, $p_field_id, $p_bug_id ); 1478 } 1479 1480 /** 1481 * Prepare a string containing a custom field value for email 1482 * NOTE: This probably belongs in the string_api.php 1483 * @param string $p_value value of custom field 1484 * @param int $p_type type of custom field 1485 * @return string value ready for sending via email 1486 * @access public 1487 */ 1488 function string_custom_field_value_for_email( $p_value, $p_type ) { 1489 global $g_custom_field_type_definition; 1490 if( isset( $g_custom_field_type_definition[$p_type]['#function_string_value_for_email'] ) ) { 1491 return call_user_func( $g_custom_field_type_definition[$p_type]['#function_string_value_for_email'], $p_value ); 1492 } 1493 return $p_value; 1494 }
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 |