[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/core/ -> custom_field_api.php (source)

   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  }


Generated: Thu Jul 28 15:48:31 2011 Cross-referenced by PHPXref 0.7