[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/core/ -> relationship_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   * Relationship API
  19   *
  20   * RELATIONSHIP DEFINITIONS
  21   * * Child/parent relationship:
  22   *    the child bug is generated by the parent bug or is directly linked with the parent with the following meaning
  23   *    the child bug has to be resolved before resolving the parent bug (the child bug "blocks" the parent bug)
  24   *    example: bug A is child bug of bug B. It means: A blocks B and B is blocked by A
  25   * * General relationship:
  26   *    two bugs related each other without any hierarchy dependance
  27   *    bugs A and B are related
  28   * * Duplicates:
  29   *    it's used to mark a bug as duplicate of an other bug already stored in the database
  30   *    bug A is marked as duplicate of B. It means: A duplicates B, B has duplicates
  31   *
  32   * Relations are always visible in the email body
  33   * --------------------------------------------------------------------
  34   * ADD NEW RELATIONSHIP
  35   * - Permission: user can update the source bug and at least view the destination bug
  36   * - Action recorded in the history of both the bugs
  37   * - Email notification sent to the users of both the bugs based based on the 'updated' bug notify type.
  38   * --------------------------------------------------------
  39   * DELETE RELATIONSHIP
  40   * - Permission: user can update the source bug and at least view the destination bug
  41   * - Action recorded in the history of both the bugs
  42   * - Email notification sent to the users of both the bugs based based on the 'updated' bug notify type.
  43   * --------------------------------------------------------
  44   * RESOLVE/CLOSE BUGS WITH BLOCKING CHILD BUGS STILL OPEN
  45   * Just a warning is print out on the form when an user attempts to resolve or close a bug with
  46   * related bugs in relation BUG_DEPENDANT still not resolved.
  47   * Anyway the user can force the resolving/closing action.
  48   * --------------------------------------------------------
  49   * EMAIL NOTIFICATION TO PARENT BUGS WHEN CHILDREN BUGS ARE RESOLVED/CLOSED
  50   * Every time a child bug is resolved or closed, an email notification is sent directly to all the handlers
  51   * of the parent bugs. The notification is sent to bugs not already marked as resolved or closed.
  52   * --------------------------------------------------------
  53   * ADD CHILD
  54   * This function gives the opportunity to generate a child bug. In details the function:
  55   * - create a new bug with the same basic information of the parent bug (plus the custom fields)
  56   * - copy all the attachment of the parent bug to the child
  57   * - not copy history, bugnotes, monitoring users
  58   * - set a relationship between parent and child
  59   *
  60   * @package CoreAPI
  61   * @subpackage RelationshipAPI
  62   * @author Marcello Scata' <marcelloscata at users.sourceforge.net> ITALY
  63   * @copyright Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
  64   * @copyright Copyright (C) 2002 - 2011  MantisBT Team - mantisbt-dev@lists.sourceforge.net
  65   * @link http://www.mantisbt.org
  66   *
  67   * @uses access_api.php
  68   * @uses bug_api.php
  69   * @uses collapse_api.php
  70   * @uses config_api.php
  71   * @uses constant_api.php
  72   * @uses current_user_api.php
  73   * @uses database_api.php
  74   * @uses form_api.php
  75   * @uses helper_api.php
  76   * @uses lang_api.php
  77   * @uses prepare_api.php
  78   * @uses print_api.php
  79   * @uses project_api.php
  80   * @uses string_api.php
  81   * @uses utility_api.php
  82   */
  83  
  84  require_api( 'access_api.php' );
  85  require_api( 'bug_api.php' );
  86  require_api( 'collapse_api.php' );
  87  require_api( 'config_api.php' );
  88  require_api( 'constant_inc.php' );
  89  require_api( 'current_user_api.php' );
  90  require_api( 'database_api.php' );
  91  require_api( 'form_api.php' );
  92  require_api( 'helper_api.php' );
  93  require_api( 'lang_api.php' );
  94  require_api( 'prepare_api.php' );
  95  require_api( 'print_api.php' );
  96  require_api( 'project_api.php' );
  97  require_api( 'string_api.php' );
  98  require_api( 'utility_api.php' );
  99  
 100  require_css( 'status_config.php' );
 101  
 102  /**
 103   * RelationshipData Structure Definition
 104   * @package MantisBT
 105   * @subpackage classes
 106   */
 107  class BugRelationshipData {
 108      var $id;
 109      var $src_bug_id;
 110      var $src_project_id;
 111      var $dest_bug_id;
 112      var $dest_project_id;
 113      var $type;
 114  }
 115  
 116  $g_relationships = array();
 117  $g_relationships[BUG_DEPENDANT] = array(
 118      '#forward' => TRUE,
 119      '#complementary' => BUG_BLOCKS,
 120      '#description' => 'dependant_on',
 121      '#notify_added' => 'email_notification_title_for_action_dependant_on_relationship_added',
 122      '#notify_deleted' => 'email_notification_title_for_action_dependant_on_relationship_deleted',
 123      '#edge_style' => array(
 124          'color' => '#C00000',
 125          'dir' => 'back',
 126      ),
 127  );
 128  $g_relationships[BUG_BLOCKS] = array(
 129      '#forward' => FALSE,
 130      '#complementary' => BUG_DEPENDANT,
 131      '#description' => 'blocks',
 132      '#notify_added' => 'email_notification_title_for_action_blocks_relationship_added',
 133      '#notify_deleted' => 'email_notification_title_for_action_blocks_relationship_deleted',
 134      '#edge_style' => array(
 135          'color' => '#C00000',
 136          'dir' => 'forward',
 137      ),
 138  );
 139  $g_relationships[BUG_DUPLICATE] = array(
 140      '#forward' => TRUE,
 141      '#complementary' => BUG_HAS_DUPLICATE,
 142      '#description' => 'duplicate_of',
 143      '#notify_added' => 'email_notification_title_for_action_duplicate_of_relationship_added',
 144      '#notify_deleted' => 'email_notification_title_for_action_duplicate_of_relationship_deleted',
 145      '#edge_style' => array(
 146          'style' => 'dashed',
 147          'color' => '#808080',
 148      ),
 149  );
 150  $g_relationships[BUG_HAS_DUPLICATE] = array(
 151      '#forward' => FALSE,
 152      '#complementary' => BUG_DUPLICATE,
 153      '#description' => 'has_duplicate',
 154      '#notify_added' => 'email_notification_title_for_action_has_duplicate_relationship_added',
 155      '#notify_deleted' => 'email_notification_title_for_action_has_duplicate_relationship_deleted',
 156  );
 157  $g_relationships[BUG_RELATED] = array(
 158      '#forward' => TRUE,
 159      '#complementary' => BUG_RELATED,
 160      '#description' => 'related_to',
 161      '#notify_added' => 'email_notification_title_for_action_related_to_relationship_added',
 162      '#notify_deleted' => 'email_notification_title_for_action_related_to_relationship_deleted',
 163  );
 164  
 165  if( file_exists( config_get_global( 'absolute_path' ) . 'custom_relationships_inc.php' ) ) {
 166      require_once( config_get_global( 'absolute_path' ) . 'custom_relationships_inc.php' );
 167  }
 168  
 169  /**
 170   * Return the complementary type of the provided relationship
 171   * @param int $p_relationship_type Relationship type
 172   * @return int Complementary type
 173   */
 174  function relationship_get_complementary_type( $p_relationship_type ) {
 175      global $g_relationships;
 176      if( !isset( $g_relationships[$p_relationship_type] ) ) {
 177          trigger_error( ERROR_GENERIC, ERROR );
 178      }
 179      return $g_relationships[$p_relationship_type]['#complementary'];
 180  }
 181  
 182  /**
 183   * Add a new relationship
 184   * @param int $p_src_bug_id Source Bug Id
 185   * @param int $p_dest_bug_id Destination Bug Id
 186   * @param int $p_relationship_type Relationship type
 187   * @return BugRelationshipData Bug Relationship
 188   */
 189  function relationship_add( $p_src_bug_id, $p_dest_bug_id, $p_relationship_type ) {
 190      $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
 191  
 192      global $g_relationships;
 193      if( $g_relationships[$p_relationship_type]['#forward'] === FALSE ) {
 194          $c_src_bug_id = db_prepare_int( $p_dest_bug_id );
 195          $c_dest_bug_id = db_prepare_int( $p_src_bug_id );
 196          $c_relationship_type = db_prepare_int( relationship_get_complementary_type( $p_relationship_type ) );
 197      } else {
 198          $c_src_bug_id = db_prepare_int( $p_src_bug_id );
 199          $c_dest_bug_id = db_prepare_int( $p_dest_bug_id );
 200          $c_relationship_type = db_prepare_int( $p_relationship_type );
 201      }
 202  
 203      $query = "INSERT INTO $t_mantis_bug_relationship_table
 204                  ( source_bug_id, destination_bug_id, relationship_type )
 205                  VALUES
 206                  ( " . db_param() . ',' . db_param() . ',' . db_param() . ')';
 207      $result = db_query_bound( $query, Array( $c_src_bug_id, $c_dest_bug_id, $c_relationship_type ) );
 208      $t_relationship = db_fetch_array( $result );
 209  
 210      $t_bug_relationship_data = new BugRelationshipData;
 211      $t_bug_relationship_data->id = $t_relationship['id'];
 212      $t_bug_relationship_data->src_bug_id = $t_relationship['source_bug_id'];
 213      $t_bug_relationship_data->dest_bug_id = $t_relationship['destination_bug_id'];
 214      $t_bug_relationship_data->type = $t_relationship['relationship_type'];
 215  
 216      return $t_bug_relationship_data;
 217  }
 218  
 219  /**
 220   * Update a relationship
 221   * @param int $p_relationship_id Relationship Id to update
 222   * @param int $p_src_bug_id Source Bug Id
 223   * @param int $p_dest_bug_id Destination Bug Id
 224   * @param int $p_relationship_type Relationship type
 225   * @return BugRelationshipData Bug Relationship
 226   */
 227  function relationship_update( $p_relationship_id, $p_src_bug_id, $p_dest_bug_id, $p_relationship_type ) {
 228      $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
 229  
 230      global $g_relationships;
 231      if( $g_relationships[$p_relationship_type]['#forward'] === FALSE ) {
 232          $c_src_bug_id = db_prepare_int( $p_dest_bug_id );
 233          $c_dest_bug_id = db_prepare_int( $p_src_bug_id );
 234          $c_relationship_type = db_prepare_int( relationship_get_complementary_type( $p_relationship_type ) );
 235      } else {
 236          $c_src_bug_id = db_prepare_int( $p_src_bug_id );
 237          $c_dest_bug_id = db_prepare_int( $p_dest_bug_id );
 238          $c_relationship_type = db_prepare_int( $p_relationship_type );
 239      }
 240      $c_relationship_id = db_prepare_int( $p_relationship_id );
 241  
 242      $query = "UPDATE $t_mantis_bug_relationship_table
 243                  SET source_bug_id=" . db_param() . ",
 244                      destination_bug_id=" . db_param() . ",
 245                      relationship_type=" . db_param() . "
 246                  WHERE id=" . db_param();
 247      $result = db_query_bound( $query, array( $c_src_bug_id, $c_dest_bug_id, $c_relationship_type, $c_relationship_id ) );
 248      $t_relationship = db_fetch_array( $result );
 249  
 250      $t_bug_relationship_data = new BugRelationshipData;
 251      $t_bug_relationship_data->id = $t_relationship['id'];
 252      $t_bug_relationship_data->src_bug_id = $t_relationship['source_bug_id'];
 253      $t_bug_relationship_data->dest_bug_id = $t_relationship['destination_bug_id'];
 254      $t_bug_relationship_data->type = $t_relationship['relationship_type'];
 255  
 256      return $t_bug_relationship_data;
 257  }
 258  
 259  /**
 260   * Delete a relationship
 261   * @param int $p_relationship_id Relationship Id to update
 262   */
 263  function relationship_delete( $p_relationship_id ) {
 264      $c_relationship_id = db_prepare_int( $p_relationship_id );
 265  
 266      $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
 267  
 268      $query = "DELETE FROM $t_mantis_bug_relationship_table
 269                  WHERE id=" . db_param();
 270      $result = db_query_bound( $query, array( $c_relationship_id ) );
 271  }
 272  
 273  /**
 274   * Deletes all the relationships related to a specific bug (both source and destination)
 275   * @param int $p_bug_id Bug Id
 276   */
 277  function relationship_delete_all( $p_bug_id ) {
 278      $c_bug_id = db_prepare_int( $p_bug_id );
 279  
 280      $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
 281  
 282      $query = "DELETE FROM $t_mantis_bug_relationship_table
 283                  WHERE source_bug_id=" . db_param() . " OR
 284                  destination_bug_id=" . db_param();
 285      $result = db_query_bound( $query, array( $c_bug_id, $c_bug_id ) );
 286  }
 287  
 288  /**
 289   * copy all the relationships related to a specific bug to a new bug
 290   * @param int $p_bug_id Source Bug Id
 291   * @param int $p_new_bug_id Destination Bug Id
 292   */
 293  function relationship_copy_all( $p_bug_id, $p_new_bug_id ) {
 294      $c_bug_id = db_prepare_int( $p_bug_id );
 295      $c_new_bug_id = db_prepare_int( $p_new_bug_id );
 296  
 297      $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
 298  
 299      $t_relationship = relationship_get_all_src( $p_bug_id );
 300      $t_relationship_count = count( $t_relationship );
 301      for( $i = 0;$i < $t_relationship_count;$i++ ) {
 302          relationship_add( $p_new_bug_id, $t_relationship[$i]->dest_bug_id, $t_relationship[$i]->type );
 303      }
 304  
 305      $t_relationship = relationship_get_all_dest( $p_bug_id );
 306      $t_relationship_count = count( $t_relationship );
 307      for( $i = 0;$i < $t_relationship_count;$i++ ) {
 308          relationship_add( $t_relationship[$i]->src_bug_id, $p_new_bug_id, $t_relationship[$i]->type );
 309      }
 310  
 311      return;
 312  }
 313  
 314  /**
 315   * get a relationship from id
 316   * @param int $p_relationship_id Relationship ID
 317   * @return null|BugRelationshipData BugRelationshipData object
 318   */
 319  function relationship_get( $p_relationship_id ) {
 320      $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
 321  
 322      $query = "SELECT *
 323                  FROM $t_mantis_bug_relationship_table
 324                  WHERE id=" . db_param();
 325      $result = db_query_bound( $query, array( (int) $p_relationship_id ) );
 326  
 327      $t_relationship_count = db_num_rows( $result );
 328  
 329      if( $t_relationship_count == 1 ) {
 330          $t_relationship = db_fetch_array( $result );
 331  
 332          $t_bug_relationship_data = new BugRelationshipData;
 333          $t_bug_relationship_data->id = $t_relationship['id'];
 334          $t_bug_relationship_data->src_bug_id = $t_relationship['source_bug_id'];
 335          $t_bug_relationship_data->dest_bug_id = $t_relationship['destination_bug_id'];
 336          $t_bug_relationship_data->type = $t_relationship['relationship_type'];
 337      } else {
 338          $t_bug_relationship_data = null;
 339      }
 340  
 341      return $t_bug_relationship_data;
 342  }
 343  
 344  /**
 345   * get all relationships with the given bug as source
 346   * @param int $p_src_bug_id Source Bug id
 347   * @return array Array of BugRelationshipData objects
 348   */
 349  function relationship_get_all_src( $p_src_bug_id ) {
 350      $c_src_bug_id = db_prepare_int( $p_src_bug_id );
 351  
 352      $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
 353      $t_mantis_bug_table = db_get_table( 'bug' );
 354  
 355      $query = "SELECT $t_mantis_bug_relationship_table.id, $t_mantis_bug_relationship_table.relationship_type,
 356                  $t_mantis_bug_relationship_table.source_bug_id, $t_mantis_bug_relationship_table.destination_bug_id,
 357                  $t_mantis_bug_table.project_id
 358                  FROM $t_mantis_bug_relationship_table
 359                  INNER JOIN $t_mantis_bug_table ON $t_mantis_bug_relationship_table.destination_bug_id = $t_mantis_bug_table.id
 360                  WHERE source_bug_id=" . db_param() . "
 361                  ORDER BY relationship_type, $t_mantis_bug_relationship_table.id";
 362      $result = db_query_bound( $query, array( $c_src_bug_id ) );
 363  
 364      $t_src_project_id = bug_get_field( $p_src_bug_id, 'project_id' );
 365  
 366      $t_bug_relationship_data = array();
 367      $t_relationship_count = db_num_rows( $result );
 368      $t_bug_array = Array();
 369      for( $i = 0;$i < $t_relationship_count;$i++ ) {
 370          $row = db_fetch_array( $result );
 371          $t_bug_relationship_data[$i] = new BugRelationshipData;
 372          $t_bug_relationship_data[$i]->id = $row['id'];
 373          $t_bug_relationship_data[$i]->src_bug_id = $row['source_bug_id'];
 374          $t_bug_relationship_data[$i]->src_project_id = $t_src_project_id;
 375          $t_bug_relationship_data[$i]->dest_bug_id = $row['destination_bug_id'];
 376          $t_bug_relationship_data[$i]->dest_project_id = $row['project_id'];
 377          $t_bug_relationship_data[$i]->type = $row['relationship_type'];
 378          $t_bug_array[] = $row['destination_bug_id'];
 379      }
 380      unset( $t_bug_relationship_data[$t_relationship_count] );
 381      if( !empty( $t_bug_array ) ) {
 382          bug_cache_array_rows( $t_bug_array );
 383      }
 384  
 385      return $t_bug_relationship_data;
 386  }
 387  
 388  /**
 389   * get all relationships with the given bug as destination
 390   * @param int $p_dest_bug_id Destination Bug id
 391   * @return array Array of BugRelationshipData objects
 392   */
 393  function relationship_get_all_dest( $p_dest_bug_id ) {
 394      $c_dest_bug_id = db_prepare_int( $p_dest_bug_id );
 395  
 396      $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
 397      $t_mantis_bug_table = db_get_table( 'bug' );
 398  
 399      $query = "SELECT $t_mantis_bug_relationship_table.id, $t_mantis_bug_relationship_table.relationship_type,
 400                  $t_mantis_bug_relationship_table.source_bug_id, $t_mantis_bug_relationship_table.destination_bug_id,
 401                  $t_mantis_bug_table.project_id
 402                  FROM $t_mantis_bug_relationship_table
 403                  INNER JOIN $t_mantis_bug_table ON $t_mantis_bug_relationship_table.source_bug_id = $t_mantis_bug_table.id
 404                  WHERE destination_bug_id=" . db_param() . "
 405                  ORDER BY relationship_type, $t_mantis_bug_relationship_table.id";
 406      $result = db_query_bound( $query, Array( $c_dest_bug_id ) );
 407  
 408      $t_dest_project_id = bug_get_field( $p_dest_bug_id, 'project_id' );
 409  
 410      $t_bug_relationship_data = array();
 411      $t_relationship_count = db_num_rows( $result );
 412      $t_bug_array = Array();
 413      for( $i = 0;$i < $t_relationship_count;$i++ ) {
 414          $row = db_fetch_array( $result );
 415          $t_bug_relationship_data[$i] = new BugRelationshipData;
 416          $t_bug_relationship_data[$i]->id = $row['id'];
 417          $t_bug_relationship_data[$i]->src_bug_id = $row['source_bug_id'];
 418          $t_bug_relationship_data[$i]->src_project_id = $row['project_id'];
 419          $t_bug_relationship_data[$i]->dest_bug_id = $row['destination_bug_id'];
 420          $t_bug_relationship_data[$i]->dest_project_id = $t_dest_project_id;
 421          $t_bug_relationship_data[$i]->type = $row['relationship_type'];
 422          $t_bug_array[] = $row['source_bug_id'];
 423      }
 424      unset( $t_bug_relationship_data[$t_relationship_count] );
 425  
 426      if( !empty( $t_bug_array ) ) {
 427          bug_cache_array_rows( $t_bug_array );
 428      }
 429      return $t_bug_relationship_data;
 430  }
 431  
 432  /**
 433   * get all relationships associated with the given bug
 434   * @param int $p_bug_id  Bug id
 435   * @param bool &$p_is_different_projects Returned Boolean value indicating if some relationships cross project boundaries
 436   * @return array Array of BugRelationshipData objects
 437   */
 438  function relationship_get_all( $p_bug_id, &$p_is_different_projects ) {
 439      $t_src = relationship_get_all_src( $p_bug_id );
 440      $t_dest = relationship_get_all_dest( $p_bug_id );
 441      $t_all = array_merge( $t_src, $t_dest );
 442  
 443      $p_is_different_projects = false;
 444      $t_count = count( $t_all );
 445      for( $i = 0;$i < $t_count;$i++ ) {
 446          $p_is_different_projects |= ( $t_all[$i]->src_project_id != $t_all[$i]->dest_project_id );
 447      }
 448      return $t_all;
 449  }
 450  
 451  /**
 452   * check if there is a relationship between two bugs
 453   * return id if found 0 otherwise
 454   * @param int $p_src_bug_id Source Bug Id
 455   * @param int $p_dest_bug_id Destination Bug Id
 456   * @return int Relationship ID
 457   */
 458  function relationship_exists( $p_src_bug_id, $p_dest_bug_id ) {
 459      $c_src_bug_id = db_prepare_int( $p_src_bug_id );
 460      $c_dest_bug_id = db_prepare_int( $p_dest_bug_id );
 461  
 462      $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
 463  
 464      $t_query = "SELECT *
 465                  FROM $t_mantis_bug_relationship_table
 466                  WHERE
 467                  (source_bug_id=" . db_param() . "
 468                  AND destination_bug_id=" . db_param() . ")
 469                  OR
 470                  (source_bug_id=" . db_param() . "
 471                  AND destination_bug_id=" . db_param() . ')';
 472      $result = db_query_bound( $t_query, array( $c_src_bug_id, $c_dest_bug_id, $c_dest_bug_id, $c_src_bug_id ), 1 );
 473  
 474      $t_relationship_count = db_num_rows( $result );
 475  
 476      if( $t_relationship_count == 1 ) {
 477  
 478          # return the first id
 479          $row = db_fetch_array( $result );
 480          return $row['id'];
 481      } else {
 482  
 483          # no relationship found
 484          return 0;
 485      }
 486  }
 487  
 488  /**
 489   * check if there is a relationship between two bugs
 490   * return:
 491   *  0 if the relationship is not found
 492   *  -1 if the relationship is found and it's of the same type $p_rel_type
 493   *  id if the relationship is found and it's of a different time (this means it can be replaced with the new type $p_rel_type
 494   * @param int $p_src_bug_id Source Bug Id
 495   * @param int $p_dest_bug_id Destination Bug Id
 496   * @param int $p_rel_type Relationship Type
 497   * @return int 0, -1 or id
 498   */
 499  function relationship_same_type_exists( $p_src_bug_id, $p_dest_bug_id, $p_rel_type ) {
 500  
 501      # Check if there is already a relationship set between them
 502      $t_id_relationship = relationship_exists( $p_src_bug_id, $p_dest_bug_id );
 503  
 504      if( $t_id_relationship > 0 ) {
 505  
 506          # if there is...
 507          # get all the relationship info
 508          $t_relationship = relationship_get( $t_id_relationship );
 509  
 510          if( $t_relationship->src_bug_id == $p_src_bug_id && $t_relationship->dest_bug_id == $p_dest_bug_id ) {
 511              if( $t_relationship->type == $p_rel_type ) {
 512                  $t_id_relationship = -1;
 513              }
 514          } else {
 515              if( $t_relationship->type == relationship_get_complementary_type( $p_rel_type ) ) {
 516                  $t_id_relationship = -1;
 517              }
 518          }
 519      }
 520      return $t_id_relationship;
 521  }
 522  
 523  /**
 524   * retrieve the linked bug id of the relationship: provide src -> return dest; provide dest -> return src
 525   * @param int $p_relationship_id Relationship id
 526   * @param int $p_bug_id Bug Id
 527   * @return int Complementary bug id
 528   */
 529  function relationship_get_linked_bug_id( $p_relationship_id, $p_bug_id ) {
 530  
 531      $t_bug_relationship_data = relationship_get( $p_relationship_id );
 532  
 533      if( $t_bug_relationship_data->src_bug_id == $p_bug_id ) {
 534          return $t_bug_relationship_data->dest_bug_id;
 535      }
 536  
 537      if( $t_bug_relationship_data->dest_bug_id == $p_bug_id ) {
 538          return $t_bug_relationship_data->src_bug_id;
 539      }
 540  
 541      trigger_error( ERROR_RELATIONSHIP_NOT_FOUND, ERROR );
 542  }
 543  
 544  /**
 545   * get class description of a relationship (source side)
 546   * @param int $p_relationship_type Relationship type
 547   * @return string Relationship description
 548   */
 549  function relationship_get_description_src_side( $p_relationship_type ) {
 550      global $g_relationships;
 551      if( !isset( $g_relationships[$p_relationship_type] ) ) {
 552          trigger_error( ERROR_RELATIONSHIP_NOT_FOUND, ERROR );
 553      }
 554      return lang_get( $g_relationships[$p_relationship_type]['#description'] );
 555  }
 556  
 557  /**
 558   * get class description of a relationship (destination side)
 559   * @param int $p_relationship_type Relationship type
 560   * @return string Relationship description
 561   */
 562  function relationship_get_description_dest_side( $p_relationship_type ) {
 563      global $g_relationships;
 564      if( !isset( $g_relationships[$p_relationship_type] ) || !isset( $g_relationships[$g_relationships[$p_relationship_type]['#complementary']] ) ) {
 565          trigger_error( ERROR_RELATIONSHIP_NOT_FOUND, ERROR );
 566      }
 567      return lang_get( $g_relationships[$g_relationships[$p_relationship_type]['#complementary']]['#description'] );
 568  }
 569  
 570  /**
 571   * get class description of a relationship as it's stored in the history
 572   * @param int $p_relationship_code Relationship Type
 573   * @return string Relationship description
 574   */
 575  function relationship_get_description_for_history( $p_relationship_code ) {
 576      return relationship_get_description_src_side( $p_relationship_code );
 577  }
 578  
 579  /**
 580   * return false if there are child bugs not resolved/closed
 581   * N.B. we don't check if the parent bug is read-only. This is because the answer of this function is indepedent from
 582   * the state of the parent bug itself.
 583   * @param int $p_bug_id Bug id
 584   * @return bool
 585   */
 586  function relationship_can_resolve_bug( $p_bug_id ) {
 587  
 588      # retrieve all the relationships in which the bug is the source bug
 589      $t_relationship = relationship_get_all_src( $p_bug_id );
 590      $t_relationship_count = count( $t_relationship );
 591      if( $t_relationship_count == 0 ) {
 592          return true;
 593      }
 594  
 595      for( $i = 0;$i < $t_relationship_count;$i++ ) {
 596  
 597          # verify if each bug in relation BUG_DEPENDANT is already marked as resolved
 598          if( $t_relationship[$i]->type == BUG_DEPENDANT ) {
 599              $t_dest_bug_id = $t_relationship[$i]->dest_bug_id;
 600              $t_status = bug_get_field( $t_dest_bug_id, 'status' );
 601              if( $t_status < config_get( 'bug_resolved_status_threshold' ) ) {
 602  
 603                  # the bug is NOT marked as resolved/closed
 604                  return false;
 605              }
 606          }
 607      }
 608  
 609      return true;
 610  }
 611  
 612  /**
 613   * return formatted string with all the details on the requested relationship
 614   * @param int $p_bug_id Bug id
 615   * @param BugRelationshipData $p_relationship Relationsip object
 616   * @param bool $p_html Generate html
 617   * @param bool $p_html_preview ???? generate printable version???
 618   * @param bool $p_show_project Show Project details
 619   * @return string
 620   */
 621  function relationship_get_details( $p_bug_id, $p_relationship, $p_html = false, $p_html_preview = false, $p_show_project = false ) {
 622      $t_summary_wrap_at = utf8_strlen( config_get( 'email_separator2' ) ) - 28;
 623      $t_icon_path = config_get( 'icon_path' );
 624  
 625      if( $p_bug_id == $p_relationship->src_bug_id ) {
 626  
 627          # root bug is in the src side, related bug in the dest side
 628          $t_related_bug_id = $p_relationship->dest_bug_id;
 629          $t_related_project_name = project_get_name( $p_relationship->dest_project_id );
 630          $t_relationship_descr = relationship_get_description_src_side( $p_relationship->type );
 631      } else {
 632  
 633          # root bug is in the dest side, related bug in the src side
 634          $t_related_bug_id = $p_relationship->src_bug_id;
 635          $t_related_project_name = project_get_name( $p_relationship->src_project_id );
 636          $t_relationship_descr = relationship_get_description_dest_side( $p_relationship->type );
 637      }
 638  
 639      # related bug not existing...
 640      if( !bug_exists( $t_related_bug_id ) ) {
 641          return '';
 642      }
 643  
 644      # user can access to the related bug at least as a viewer
 645      if( !access_has_bug_level( VIEWER, $t_related_bug_id ) ) {
 646          return '';
 647      }
 648  
 649      if( $p_html_preview == false ) {
 650          $t_td = '<td>';
 651      } else {
 652          $t_td = '<td class="print">';
 653      }
 654  
 655      # get the information from the related bug and prepare the link
 656      $t_bug = bug_get( $t_related_bug_id, false );
 657      $t_status_string = get_enum_element( 'status', $t_bug->status );
 658      $t_resolution_string = get_enum_element( 'resolution', $t_bug->resolution );
 659  
 660      $t_relationship_info_html = $t_td . string_no_break( $t_relationship_descr ) . '&#160;</td>';
 661      if( $p_html_preview == false ) {
 662          $t_relationship_info_html .= '<td><a href="' . string_get_bug_view_url( $t_related_bug_id ) . '">' . string_display_line( bug_format_id( $t_related_bug_id ) ) . '</a></td>';
 663          $t_relationship_info_html .= '<td><span class="issue-status" title="' . string_attribute( $t_resolution_string ) . '">' . string_display_line( $t_status_string ) . '</span></td>';
 664      } else {
 665          $t_relationship_info_html .= $t_td . string_display_line( bug_format_id( $t_related_bug_id ) ) . '</td>';
 666          $t_relationship_info_html .= $t_td . string_display_line( $t_status_string ) . '&#160;</td>';
 667      }
 668  
 669      $t_relationship_info_text = utf8_str_pad( $t_relationship_descr, 20 );
 670      $t_relationship_info_text .= utf8_str_pad( bug_format_id( $t_related_bug_id ), 8 );
 671  
 672      # get the handler name of the related bug
 673      $t_relationship_info_html .= $t_td;
 674      if( $t_bug->handler_id > 0 ) {
 675          $t_relationship_info_html .= string_no_break( prepare_user_name( $t_bug->handler_id ) );
 676      }
 677      $t_relationship_info_html .= '&#160;</td>';
 678  
 679      # add project name
 680      if( $p_show_project ) {
 681          $t_relationship_info_html .= $t_td . string_display_line( $t_related_project_name ) . '&#160;</td>';
 682      }
 683  
 684      # add summary
 685       if( $p_html == true ) {
 686           $t_relationship_info_html .= $t_td . string_display_line_links( $t_bug->summary );
 687           if( VS_PRIVATE == $t_bug->view_state ) {
 688               $t_relationship_info_html .= sprintf( ' <img src="%s" alt="(%s)" title="%s" />', $t_icon_path . 'protected.gif', lang_get( 'private' ), lang_get( 'private' ) );
 689           }
 690        } else {
 691           if( utf8_strlen( $t_bug->summary ) <= $t_summary_wrap_at ) {
 692               $t_relationship_info_text .= string_email_links( $t_bug->summary );
 693           } else {
 694               $t_relationship_info_text .= utf8_substr( string_email_links( $t_bug->summary ), 0, $t_summary_wrap_at - 3 ) . '...';
 695           }
 696      }
 697  
 698      # add delete link if bug not read only and user has access level
 699       if( !bug_is_readonly( $p_bug_id ) && !current_user_is_anonymous() && ( $p_html_preview == false ) ) {
 700           if( access_has_bug_level( config_get( 'update_bug_threshold' ), $p_bug_id ) ) {
 701              $t_relationship_info_html .= ' [<a class="small" href="bug_relationship_delete.php?bug_id=' . $p_bug_id . '&amp;rel_id=' . $p_relationship->id . htmlspecialchars( form_security_param( 'bug_relationship_delete' ) ) . '">' . lang_get( 'delete_link' ) . '</a>]';
 702          }
 703      }
 704  
 705      $t_relationship_info_html .= '&#160;</td>';
 706      $t_relationship_info_text .= "\n";
 707  
 708      if( $p_html_preview == false ) {
 709          # choose color based on status
 710          $status_label = html_get_status_css_class( $t_bug->status );
 711  
 712          $t_relationship_info_html = '<tr class="' . $status_label . '">' . $t_relationship_info_html . '</tr>' . "\n";
 713      } else {
 714          $t_relationship_info_html = '<tr>' . $t_relationship_info_html . '</tr>';
 715      }
 716  
 717      if( $p_html == true ) {
 718          return $t_relationship_info_html;
 719      } else {
 720          return $t_relationship_info_text;
 721      }
 722  }
 723  
 724  /**
 725   * print ALL the RELATIONSHIPS OF A SPECIFIC BUG
 726   * @param int $p_bug_id Bug id
 727   * @return string
 728   */
 729  function relationship_get_summary_html( $p_bug_id ) {
 730      $t_summary = '';
 731      $t_show_project = false;
 732  
 733      $t_relationship_all = relationship_get_all( $p_bug_id, $t_show_project );
 734      $t_relationship_all_count = count( $t_relationship_all );
 735  
 736      # prepare the relationships table
 737      for( $i = 0;$i < $t_relationship_all_count;$i++ ) {
 738          $t_summary .= relationship_get_details( $p_bug_id, $t_relationship_all[$i], true, false, $t_show_project );
 739      }
 740  
 741      if( !is_blank( $t_summary ) ) {
 742          if( relationship_can_resolve_bug( $p_bug_id ) == false ) {
 743              $t_summary .= '<tr class="row-2"><td colspan="' . ( 5 + $t_show_project ) . '"><strong>' . lang_get( 'relationship_warning_blocking_bugs_not_resolved' ) . '</strong></td></tr>';
 744          }
 745          $t_summary = '<table width="100%" cellpadding="0" cellspacing="1">' . $t_summary . '</table>';
 746      }
 747  
 748      return $t_summary;
 749  }
 750  
 751  /**
 752   * print ALL the RELATIONSHIPS OF A SPECIFIC BUG
 753   * @param int $p_bug_id Bug id
 754   * @return string
 755   */
 756  function relationship_get_summary_html_preview( $p_bug_id ) {
 757      $t_summary = '';
 758      $t_show_project = false;
 759  
 760      $t_relationship_all = relationship_get_all( $p_bug_id, $t_show_project );
 761      $t_relationship_all_count = count( $t_relationship_all );
 762  
 763      # prepare the relationships table
 764      for( $i = 0;$i < $t_relationship_all_count;$i++ ) {
 765          $t_summary .= relationship_get_details( $p_bug_id, $t_relationship_all[$i], true, true, $t_show_project );
 766      }
 767  
 768      if( !is_blank( $t_summary ) ) {
 769          if( relationship_can_resolve_bug( $p_bug_id ) == false ) {
 770              $t_summary .= '<tr class="print"><td class="print" colspan=' . ( 5 + $t_show_project ) . '><strong>' . lang_get( 'relationship_warning_blocking_bugs_not_resolved' ) . '</strong></td></tr>';
 771          }
 772          $t_summary = '<table width="100%" cellpadding="0" cellspacing="1">' . $t_summary . '</table>';
 773      }
 774  
 775      return $t_summary;
 776  }
 777  
 778  /**
 779   * print ALL the RELATIONSHIPS OF A SPECIFIC BUG in text format (used by email_api.php
 780   * @param int $p_bug_id Bug id
 781   * @return string
 782   */
 783  function relationship_get_summary_text( $p_bug_id ) {
 784      $t_summary = '';
 785      $t_show_project = false;
 786  
 787      $t_relationship_all = relationship_get_all( $p_bug_id, $t_show_project );
 788      $t_relationship_all_count = count( $t_relationship_all );
 789  
 790      # prepare the relationships table
 791      for( $i = 0;$i < $t_relationship_all_count;$i++ ) {
 792          $t_summary .= relationship_get_details( $p_bug_id, $t_relationship_all[$i], false );
 793      }
 794  
 795      return $t_summary;
 796  }
 797  
 798  /**
 799   * print HTML relationship listbox
 800   * @param int $p_default_rel_type Relationship Type (default -1)
 801   * @param string $p_select_name List box name (default "rel_type")
 802   * @param bool $p_include_any Include an ANY option in list box (default false)
 803   * @param bool $p_include_none Include a NONE option in list box (default false)
 804   * @param int $p_bug_id Bug id
 805   * @return null
 806   */
 807  function relationship_list_box( $p_default_rel_type = -1, $p_select_name = "rel_type", $p_include_any = false, $p_include_none = false ) {
 808      global $g_relationships;
 809      ?>
 810  <select name="<?php echo $p_select_name?>">
 811  <?php if( $p_include_any ) {?>
 812  <option value="-1" <?php echo( $p_default_rel_type == -1 ? ' selected="selected"' : '' )?>>[<?php echo lang_get( 'any' )?>]</option>
 813  <?php
 814      }
 815  
 816      if( $p_include_none ) {?>
 817  <option value="-2" <?php echo( $p_default_rel_type == -2 ? ' selected="selected"' : '' )?>>[<?php echo lang_get( 'none' )?>]</option>
 818  <?php
 819      }
 820  
 821      foreach( $g_relationships as $type => $relationship ) {
 822          ?>
 823  <option value="<?php echo $type?>"<?php echo( $p_default_rel_type == $type ? ' selected="selected"' : '' )?>><?php echo lang_get( $relationship['#description'] )?></option>
 824  <?php
 825      }?>
 826  </select>
 827  <?php
 828  }
 829  
 830  /**
 831   * print HTML relationship form
 832   * @param int $p_bug_id Bug id
 833   * @return null
 834   */
 835  function relationship_view_box( $p_bug_id ) {
 836      ?>
 837  <br/>
 838  
 839  <?php collapse_open( 'relationships' );?>
 840  <table class="width100" cellspacing="1">
 841  <tr class="row-2">
 842      <td width="15%" class="form-title" colspan="2">
 843          <?php
 844              collapse_icon( 'relationships' );
 845      echo lang_get( 'bug_relationships' );
 846      if( ON == config_get( 'relationship_graph_enable' ) ) {
 847          ?>
 848          <span class="small"><?php print_bracket_link( "bug_relationship_graph.php?bug_id=$p_bug_id&graph=relation", lang_get( 'relation_graph' ) )?></span>
 849          <span class="small"><?php print_bracket_link( "bug_relationship_graph.php?bug_id=$p_bug_id&graph=dependency", lang_get( 'dependency_graph' ) )?></span>
 850          <?php
 851      }
 852      ?>
 853      </td>
 854  </tr>
 855  <?php
 856      # bug not read-only and user authenticated
 857      if( !bug_is_readonly( $p_bug_id ) ) {
 858  
 859          # user access level at least updater
 860          if( access_has_bug_level( config_get( 'update_bug_threshold' ), $p_bug_id ) ) {
 861              ?>
 862  <tr class="row-1">
 863      <th class="category"><?php echo lang_get( 'add_new_relationship' )?></th>
 864      <td><?php echo lang_get( 'this_bug' )?>
 865          <form method="post" action="bug_relationship_add.php">
 866          <?php echo form_security_field( 'bug_relationship_add' ) ?>
 867          <input type="hidden" name="src_bug_id" value="<?php echo $p_bug_id?>" size="4" />
 868          <?php relationship_list_box( -1 )?>
 869          <input type="text" name="dest_bug_id" value="" />
 870          <input type="submit" name="add_relationship" class="button" value="<?php echo lang_get( 'add_new_relationship_button' )?>" />
 871          </form>
 872      </td></tr>
 873  <?php
 874          }
 875      }
 876      ?>
 877  <tr>
 878      <td colspan="2"><?php echo relationship_get_summary_html( $p_bug_id )?></td>
 879  </tr>
 880  </table>
 881  
 882  <?php collapse_closed( 'relationships' );?>
 883  <table class="width100" cellspacing="1">
 884  <tr>
 885      <td class="form-title">
 886          <?php
 887              collapse_icon( 'relationships' );
 888      echo lang_get( 'bug_relationships' );
 889      ?>
 890      </td>
 891  </tr>
 892  </table>
 893  
 894  <?php
 895      collapse_end( 'relationships' );
 896  }


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