[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/core/ -> category_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   * Category API
  19   *
  20   * @package CoreAPI
  21   * @subpackage CategoryAPI
  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 config_api.php
  27   * @uses constant_inc.php
  28   * @uses database_api.php
  29   * @uses error_api.php
  30   * @uses helper_api.php
  31   * @uses history_api.php
  32   * @uses lang_api.php
  33   * @uses project_api.php
  34   * @uses project_hierarchy_api.php
  35   * @uses utility_api.php
  36   */
  37  
  38  require_api( 'config_api.php' );
  39  require_api( 'constant_inc.php' );
  40  require_api( 'database_api.php' );
  41  require_api( 'error_api.php' );
  42  require_api( 'helper_api.php' );
  43  require_api( 'history_api.php' );
  44  require_api( 'lang_api.php' );
  45  require_api( 'project_api.php' );
  46  require_api( 'project_hierarchy_api.php' );
  47  require_api( 'utility_api.php' );
  48  
  49  # Category data cache (to prevent excessive db queries)
  50  $g_category_cache = array();
  51  
  52  /**
  53   * Check whether the category exists in the project
  54   * @param int $p_category_id category id
  55   * @return bool Return true if the category exists, false otherwise
  56   * @access public
  57   */
  58  function category_exists( $p_category_id ) {
  59      global $g_category_cache;
  60      if( isset( $g_category_cache[(int) $p_category_id] ) ) {
  61          return true;
  62      }
  63  
  64      $c_category_id = db_prepare_int( $p_category_id );
  65  
  66      $t_category_table = db_get_table( 'category' );
  67  
  68      $query = "SELECT COUNT(*) FROM $t_category_table
  69                      WHERE id=" . db_param();
  70      $count = db_result( db_query_bound( $query, array( $c_category_id ) ) );
  71  
  72      if( 0 < $count ) {
  73          return true;
  74      } else {
  75          return false;
  76      }
  77  }
  78  
  79  /**
  80   * Check whether the category exists in the project
  81   * Trigger an error if it does not
  82   * @param int $p_category_id category id
  83   * @access public
  84   */
  85   function category_ensure_exists( $p_category_id ) {
  86      if( !category_exists( $p_category_id ) ) {
  87          trigger_error( ERROR_CATEGORY_NOT_FOUND, ERROR );
  88      }
  89  }
  90  
  91  /**
  92   * Check whether the category is unique within a project
  93   * @param int $p_project_id project id
  94   * @param string $p_name project name
  95   * @return bool Returns true if the category is unique, false otherwise
  96   * @access public
  97   */
  98   function category_is_unique( $p_project_id, $p_name ) {
  99      $c_project_id = db_prepare_int( $p_project_id );
 100  
 101      $t_category_table = db_get_table( 'category' );
 102  
 103      $query = "SELECT COUNT(*) FROM $t_category_table
 104                      WHERE project_id=" . db_param() . " AND " . db_helper_like( 'name' );
 105      $count = db_result( db_query_bound( $query, array( $c_project_id, $p_name ) ) );
 106  
 107      if( 0 < $count ) {
 108          return false;
 109      } else {
 110          return true;
 111      }
 112  }
 113  
 114  /**
 115   * Check whether the category is unique within a project
 116   * Trigger an error if it is not
 117   * @param int $p_project_id Project id
 118   * @param string $p_name Category Name
 119   * @return null
 120   * @access public
 121   */
 122   function category_ensure_unique( $p_project_id, $p_name ) {
 123      if( !category_is_unique( $p_project_id, $p_name ) ) {
 124          trigger_error( ERROR_CATEGORY_DUPLICATE, ERROR );
 125      }
 126  }
 127  
 128  /**
 129   * Add a new category to the project
 130   * @param int $p_project_id Project id
 131   * @param string $p_name Category Name
 132   * @return int Category ID
 133   * @access public
 134   */
 135   function category_add( $p_project_id, $p_name ) {
 136      $c_project_id = db_prepare_int( $p_project_id );
 137  
 138      if( is_blank( $p_name ) ) {
 139          error_parameters( lang_get( 'category' ) );
 140          trigger_error( ERROR_EMPTY_FIELD, ERROR );
 141      }
 142  
 143      category_ensure_unique( $p_project_id, $p_name );
 144  
 145      $t_category_table = db_get_table( 'category' );
 146  
 147      $query = "INSERT INTO $t_category_table
 148                      ( project_id, name )
 149                    VALUES
 150                      ( " . db_param() . ', ' . db_param() . ' )';
 151      db_query_bound( $query, array( $c_project_id, $p_name ) );
 152  
 153      # db_query errors on failure so:
 154      return db_insert_id( $t_category_table );
 155  }
 156  
 157  /**
 158   * Update the name and user associated with the category
 159   * @param int $p_category_id Category id
 160   * @param string $p_name Category Name
 161   * @param int $p_assigned_to User ID that category is assigned to
 162   * @return bool
 163   * @access public
 164   */
 165   function category_update( $p_category_id, $p_name, $p_assigned_to ) {
 166      if( is_blank( $p_name ) ) {
 167          error_parameters( lang_get( 'category' ) );
 168          trigger_error( ERROR_EMPTY_FIELD, ERROR );
 169      }
 170  
 171      $t_old_category = category_get_row( $p_category_id );
 172  
 173      $c_category_id = db_prepare_int( $p_category_id );
 174      $c_assigned_to = db_prepare_int( $p_assigned_to );
 175  
 176      $t_category_table = db_get_table( 'category' );
 177      $t_bug_table = db_get_table( 'bug' );
 178  
 179      $query = "UPDATE $t_category_table
 180                    SET name=" . db_param() . ',
 181                      user_id=' . db_param() . '
 182                    WHERE id=' . db_param();
 183      db_query_bound( $query, array( $p_name, $c_assigned_to, $c_category_id ) );
 184  
 185      # Add bug history entries if we update the category's name
 186      if( $t_old_category['name'] != $p_name ) {
 187          $query = "SELECT id FROM $t_bug_table WHERE category_id=" . db_param();
 188          $t_result = db_query_bound( $query, array( $c_category_id ) );
 189  
 190          while( $t_bug_row = db_fetch_array( $t_result ) ) {
 191              history_log_event_direct( $t_bug_row['id'], 'category', $t_old_category['name'], $p_name );
 192          }
 193      }
 194  
 195      # db_query errors on failure so:
 196      return true;
 197  }
 198  
 199  /**
 200   * Remove a category from the project
 201   * @param int $p_category_id Category id
 202   * @param int $p_new_category_id new category id (to replace existing category)
 203   * @return bool
 204   * @access public
 205   */
 206   function category_remove( $p_category_id, $p_new_category_id = 0 ) {
 207      $t_category_row = category_get_row( $p_category_id );
 208  
 209      $c_category_id = db_prepare_int( $p_category_id );
 210      $c_new_category_id = db_prepare_int( $p_new_category_id );
 211  
 212      category_ensure_exists( $p_category_id );
 213      if( 0 != $p_new_category_id ) {
 214          category_ensure_exists( $p_new_category_id );
 215      }
 216  
 217      $t_category_table = db_get_table( 'category' );
 218      $t_bug_table = db_get_table( 'bug' );
 219  
 220      $query = "DELETE FROM $t_category_table
 221                    WHERE id=" . db_param();
 222      db_query_bound( $query, array( $c_category_id ) );
 223  
 224      # update bug history entries
 225      $query = "SELECT id FROM $t_bug_table WHERE category_id=" . db_param();
 226      $t_result = db_query_bound( $query, array( $c_category_id ) );
 227  
 228      while( $t_bug_row = db_fetch_array( $t_result ) ) {
 229          history_log_event_direct( $t_bug_row['id'], 'category', $t_category_row['name'], category_full_name( $p_new_category_id, false ) );
 230      }
 231  
 232      # update bug data
 233      $query = "UPDATE $t_bug_table
 234                    SET category_id=" . db_param() . "
 235                    WHERE category_id=" . db_param();
 236      db_query_bound( $query, array( $c_new_category_id, $c_category_id ) );
 237  
 238      # db_query errors on failure so:
 239      return true;
 240  }
 241  
 242  /**
 243   * Remove all categories associated with a project
 244   * @param int $p_project_id Project ID
 245   * @param int $p_new_category_id new category id (to replace existing category)
 246   * @return bool
 247   * @access public
 248   */
 249   function category_remove_all( $p_project_id, $p_new_category_id = 0 ) {
 250  
 251      project_ensure_exists( $p_project_id );
 252      if( 0 != $p_new_category_id ) {
 253          category_ensure_exists( $p_new_category_id );
 254      }
 255  
 256      # cache category names
 257      category_get_all_rows( $p_project_id );
 258  
 259      $t_category_table = db_get_table( 'category' );
 260      $t_bug_table = db_get_table( 'bug' );
 261  
 262      # get a list of affected categories
 263      $t_query = "SELECT id FROM $t_category_table WHERE project_id=" . db_param();
 264      $t_result = db_query_bound( $t_query, array( $p_project_id ) );
 265  
 266      $t_category_ids = array();
 267      while( $t_row = db_fetch_array( $t_result ) ) {
 268          $t_category_ids[] = $t_row['id'];
 269      }
 270  
 271      # Handle projects with no categories
 272      if( count( $t_category_ids ) < 1 ) {
 273          return true;
 274      }
 275  
 276      $t_category_ids = join( ',', $t_category_ids );
 277  
 278      # update bug history entries
 279      $t_query = "SELECT id, category_id FROM $t_bug_table WHERE category_id IN ( $t_category_ids )";
 280      $t_result = db_query_bound( $t_query );
 281  
 282      while( $t_bug_row = db_fetch_array( $t_result ) ) {
 283          history_log_event_direct( $t_bug_row['id'], 'category', category_full_name( $t_bug_row['category_id'], false ), category_full_name( $p_new_category_id, false ) );
 284      }
 285  
 286      # update bug data
 287      $t_query = "UPDATE $t_bug_table SET category_id=" . db_param() . " WHERE category_id IN ( $t_category_ids )";
 288      db_query_bound( $t_query, array( $p_new_category_id ) );
 289  
 290      # delete categories
 291      $t_query = "DELETE FROM $t_category_table WHERE project_id=" . db_param();
 292      db_query_bound( $t_query, array( $p_project_id ) );
 293  
 294      return true;
 295  }
 296  
 297  /**
 298   * Return the definition row for the category
 299   * @param int $p_category_id Category id
 300   * @return array array containing category details
 301   * @access public
 302   */
 303   function category_get_row( $p_category_id ) {
 304      global $g_category_cache;
 305      if( isset( $g_category_cache[$p_category_id] ) ) {
 306          return $g_category_cache[$p_category_id];
 307      }
 308  
 309      $c_category_id = db_prepare_int( $p_category_id );
 310  
 311      $t_category_table = db_get_table( 'category' );
 312      $t_project_table = db_get_table( 'project' );
 313  
 314      $query = "SELECT * FROM $t_category_table
 315                  WHERE id=" . db_param();
 316      $result = db_query_bound( $query, array( $c_category_id ) );
 317      $count = db_num_rows( $result );
 318      if( 0 == $count ) {
 319          trigger_error( ERROR_CATEGORY_NOT_FOUND, ERROR );
 320      }
 321  
 322      $row = db_fetch_array( $result );
 323      $g_category_cache[$p_category_id] = $row;
 324      return $row;
 325  }
 326  
 327  /**
 328   * Sort categories based on what project they're in.
 329   * Call beforehand with a single parameter to set a 'preferred' project.
 330   * @param array $p_category1 array containing category details
 331   * @param array $p_category2 array containing category details
 332   * @return int integer representing sort order
 333   * @access public
 334   */
 335   function category_sort_rows_by_project( $p_category1, $p_category2 = null ) {
 336      static $p_project_id = null;
 337      if( is_null( $p_category2 ) ) {
 338  
 339          # Set a target project
 340          $p_project_id = $p_category1;
 341          return;
 342      }
 343  
 344      if( !is_null( $p_project_id ) ) {
 345          if( $p_category1['project_id'] == $p_project_id && $p_category2['project_id'] != $p_project_id ) {
 346              return -1;
 347          }
 348          if( $p_category1['project_id'] != $p_project_id && $p_category2['project_id'] == $p_project_id ) {
 349              return 1;
 350          }
 351      }
 352  
 353      $t_proj_cmp = strcasecmp( $p_category1['project_name'], $p_category2['project_name'] );
 354      if( $t_proj_cmp != 0 ) {
 355          return $t_proj_cmp;
 356      }
 357  
 358      return strcasecmp( $p_category1['name'], $p_category2['name'] );
 359  }
 360  
 361  $g_cache_category_project = null;
 362  
 363  function category_cache_array_rows_by_project( $p_project_id_array ) {
 364      global $g_category_cache, $g_cache_category_project;
 365  
 366      $c_project_id_array = array();
 367  
 368      foreach( $p_project_id_array as $t_project_id ) {
 369          if( !isset( $g_cache_category_project[(int) $t_project_id] ) ) {
 370              $c_project_id_array[] = (int) $t_project_id;
 371              $g_cache_category_project[(int) $t_project_id] = array();
 372          }
 373      }
 374  
 375      if( empty( $c_project_id_array ) ) {
 376          return;
 377      }
 378  
 379      $t_category_table = db_get_table( 'category' );
 380      $t_project_table = db_get_table( 'project' );
 381  
 382      $query = "SELECT c.*, p.name AS project_name FROM $t_category_table c
 383                  LEFT JOIN $t_project_table p
 384                      ON c.project_id=p.id
 385                  WHERE project_id IN ( " . implode( ', ', $c_project_id_array ) . " )
 386                  ORDER BY c.name ";
 387      $result = db_query_bound( $query );
 388  
 389      $rows = array();
 390      while( $row = db_fetch_array( $result ) ) {
 391          $g_category_cache[(int) $row['id']] = $row;
 392  
 393          $rows[ (int)$row[ 'project_id' ] ][] = $row['id'];
 394      }
 395  
 396      foreach( $rows as $t_project_id => $t_row ) {
 397          $g_cache_category_project[ (int)$t_project_id ] = $t_row;
 398      }
 399      return;
 400  }
 401  
 402  /**
 403   *    Get a distinct array of categories accessible to the current user for
 404   *    the specified projects.  If no project is specified, use the current project.
 405   *    If the current project is ALL_PROJECTS get all categories for all accessible projects.
 406   *    For all cases, get global categories and subproject categories according to configured inheritance settings.
 407   *    @param mixed $p_project_id A specific project or null
 408   *    @return array A unique array of category names
 409   */
 410  function category_get_filter_list( $p_project_id = null ) {
 411      if( null === $p_project_id ) {
 412          $t_project_id = helper_get_current_project();
 413      } else {
 414          $t_project_id = $p_project_id;
 415      }
 416  
 417      if( $t_project_id == ALL_PROJECTS ) {
 418          $t_project_ids = current_user_get_accessible_projects();
 419      } else {
 420          $t_project_ids = array( $t_project_id );
 421      }
 422  
 423      $t_subproject_ids = array();
 424      foreach( $t_project_ids as $t_project_id ) {
 425          $t_subproject_ids = array_merge( $t_subproject_ids, current_user_get_all_accessible_subprojects( $t_project_id ) );
 426      }
 427  
 428      $t_project_ids = array_merge( $t_project_ids, $t_subproject_ids );
 429  
 430      $t_categories = array();
 431      foreach( $t_project_ids AS $t_id ) {
 432          $t_categories = array_merge( $t_categories, category_get_all_rows( $t_id ) );
 433      }
 434  
 435      $t_unique = array();
 436      foreach( $t_categories AS $t_category ) {
 437          if( !in_array( $t_category['name'], $t_unique ) ) {
 438              $t_unique[] = $t_category['name'];
 439          }
 440      }
 441  
 442      return $t_unique;
 443  }
 444  
 445  /**
 446   * Return all categories for the specified project id.
 447   * Obeys project hierarchies and such.
 448   * @param int $p_project_id Project id
 449   * @param bool $p_inherit indicates whether to inherit categories from parent projects, or null to use configuration default.
 450   * @param bool $p_sort_by_project
 451   * @return array array of categories
 452   * @access public
 453   */
 454   function category_get_all_rows( $p_project_id, $p_inherit = null, $p_sort_by_project = false ) {
 455      global $g_category_cache, $g_cache_category_project;
 456  
 457      if( isset( $g_cache_category_project[ (int)$p_project_id ] ) ) {
 458          if( !empty( $g_cache_category_project[ (int)$p_project_id ]) ) {
 459              foreach( $g_cache_category_project[ (int)$p_project_id ] as $t_id ) {
 460                  $t_categories[] = category_get_row( $t_id );
 461              }
 462  
 463              if( $p_sort_by_project ) {
 464                  category_sort_rows_by_project( $p_project_id );
 465                  usort( $t_categories, 'category_sort_rows_by_project' );
 466                  category_sort_rows_by_project( null );
 467              }
 468              return $t_categories;
 469          } else {
 470              return array();
 471          }
 472      }
 473  
 474      $c_project_id = db_prepare_int( $p_project_id );
 475  
 476      $t_category_table = db_get_table( 'category' );
 477      $t_project_table = db_get_table( 'project' );
 478  
 479      if ( $c_project_id == ALL_PROJECTS ) {
 480          $t_inherit = false;
 481      } else {
 482          if ( $p_inherit === null ) {
 483              $t_inherit = config_get( 'subprojects_inherit_categories' );
 484          } else {
 485              $t_inherit = $p_inherit;
 486          }
 487      }
 488  
 489      if ( $t_inherit ) {
 490          $t_project_ids = project_hierarchy_inheritance( $p_project_id );
 491          $t_project_where = ' project_id IN ( ' . implode( ', ', $t_project_ids ) . ' ) ';
 492      } else {
 493          $t_project_where = ' project_id=' . $p_project_id . ' ';
 494      }
 495  
 496      $query = "SELECT c.*, p.name AS project_name FROM $t_category_table c
 497                  LEFT JOIN $t_project_table p
 498                      ON c.project_id=p.id
 499                  WHERE $t_project_where
 500                  ORDER BY c.name ";
 501      $result = db_query_bound( $query );
 502      $count = db_num_rows( $result );
 503      $rows = array();
 504      for( $i = 0;$i < $count;$i++ ) {
 505          $row = db_fetch_array( $result );
 506  
 507          $rows[] = $row;
 508          $g_category_cache[(int) $row['id']] = $row;
 509      }
 510  
 511      if( $p_sort_by_project ) {
 512          category_sort_rows_by_project( $p_project_id );
 513          usort( $rows, 'category_sort_rows_by_project' );
 514          category_sort_rows_by_project( null );
 515      }
 516  
 517      return $rows;
 518  }
 519  
 520  /**
 521   *
 522   * @param array $p_cat_id_array array of category id's
 523   * @return null
 524   * @access public
 525   */
 526  function category_cache_array_rows( $p_cat_id_array ) {
 527      global $g_category_cache;
 528      $c_cat_id_array = array();
 529  
 530      foreach( $p_cat_id_array as $t_cat_id ) {
 531          if( !isset( $g_category_cache[(int) $t_cat_id] ) ) {
 532              $c_cat_id_array[] = (int) $t_cat_id;
 533          }
 534      }
 535  
 536      if( empty( $c_cat_id_array ) ) {
 537          return;
 538      }
 539  
 540      $t_category_table = db_get_table( 'category' );
 541      $t_project_table = db_get_table( 'project' );
 542  
 543      $query = "SELECT c.*, p.name AS project_name FROM $t_category_table c
 544                  LEFT JOIN $t_project_table p
 545                      ON c.project_id=p.id
 546                  WHERE c.id IN (" . implode( ',', $c_cat_id_array ) . ')';
 547      $result = db_query_bound( $query );
 548  
 549      while( $row = db_fetch_array( $result ) ) {
 550          $g_category_cache[(int) $row['id']] = $row;
 551      }
 552      return;
 553  }
 554  
 555  /**
 556   * Given a category id and a field name, this function returns the field value.
 557   * An error will be triggered for a non-existent category id or category id = 0.
 558   * @param int $p_category_id category id
 559   * @param string $p_name field name
 560   * @return string field value
 561   * @access public
 562   */
 563  function category_get_field( $p_category_id, $p_field_name ) {
 564      $t_row = category_get_row( $p_category_id );
 565      return $t_row[$p_field_name];
 566  }
 567  
 568  /**
 569   * Given a category id, this function returns the category name.
 570   * An error will be triggered for a non-existent category id or category id = 0.
 571   * @param int $p_category_id category id
 572   * @return string category name
 573   * @access public
 574   */
 575   function category_get_name( $p_category_id ) {
 576      return category_get_field( $p_category_id, 'name' );
 577  }
 578  
 579  /**
 580   * Given a category name and project, this function returns the category id.
 581   * An error will be triggered if the specified project does not have a
 582   * category with that name.
 583   * @param string $p_category_name category name
 584   * @param int $p_project_id project id
 585   * @param bool $p_trigger_errors trigger error on failure
 586   * @return bool
 587   * @access public
 588   */
 589   function category_get_id_by_name( $p_category_name, $p_project_id, $p_trigger_errors = true ) {
 590      $t_category_table = db_get_table( 'category' );
 591      $t_project_name = project_get_name( $p_project_id );
 592  
 593      $t_query = "SELECT id FROM $t_category_table
 594                  WHERE name=" . db_param() . " AND project_id=" . db_param();
 595      $t_result = db_query_bound( $t_query, array( $p_category_name, (int) $p_project_id ) );
 596      $t_count = db_num_rows( $t_result );
 597      if( 1 > $t_count ) {
 598          if( $p_trigger_errors ) {
 599              error_parameters( $p_category_name, $t_project_name );
 600              trigger_error( ERROR_CATEGORY_NOT_FOUND_FOR_PROJECT, ERROR );
 601          } else {
 602              return false;
 603          }
 604      }
 605  
 606      return db_result( $t_result );
 607  }
 608  
 609  /**
 610   * Retrieves category name (including project name if required)
 611   * @param string $p_category_id category id
 612   * @param bool $p_show_project show project details
 613   * @param int $p_project_id current project id override
 614   * @return string category full name
 615   * @access public
 616   */
 617  function category_full_name( $p_category_id, $p_show_project = true, $p_current_project = null ) {
 618      if( 0 == $p_category_id ) {
 619          # No Category
 620          return lang_get( 'no_category' );
 621      } else {
 622          $t_row = category_get_row( $p_category_id );
 623          $t_project_id = $t_row['project_id'];
 624  
 625          $t_current_project = is_null( $p_current_project ) ? helper_get_current_project() : $p_current_project;
 626  
 627          if( $p_show_project && $t_project_id != $t_current_project ) {
 628              return '[' . project_get_name( $t_project_id ) . '] ' . $t_row['name'];
 629          }
 630  
 631          return $t_row['name'];
 632      }
 633  }


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