[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/core/ -> plugin_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  /**
  19   * Plugin API
  20   *
  21   * Handles the initialisation, management, and execution of plugins.
  22   *
  23   * @package CoreAPI
  24   * @subpackage PluginAPI
  25   * @copyright Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
  26   * @copyright Copyright (C) 2002 - 2011  MantisBT Team - mantisbt-dev@lists.sourceforge.net
  27   * @link http://www.mantisbt.org
  28   *
  29   * @uses access_api.php
  30   * @uses config_api.php
  31   * @uses constant_inc.php
  32   * @uses database_api.php
  33   * @uses error_api.php
  34   * @uses event_api.php
  35   * @uses helper_api.php
  36   * @uses history_api.php
  37   * @uses lang_api.php
  38   */
  39  
  40  require_api( 'access_api.php' );
  41  require_api( 'config_api.php' );
  42  require_api( 'constant_inc.php' );
  43  require_api( 'database_api.php' );
  44  require_api( 'error_api.php' );
  45  require_api( 'event_api.php' );
  46  require_api( 'helper_api.php' );
  47  require_api( 'history_api.php' );
  48  require_api( 'lang_api.php' );
  49  
  50  # Cache variables #####
  51  
  52  $g_plugin_cache = array();
  53  $g_plugin_cache_priority = array();
  54  $g_plugin_cache_protected = array();
  55  $g_plugin_current = array();
  56  
  57  # Public API #####
  58  /**
  59   * Get the currently executing plugin's basename.
  60   * @return string Plugin basename, or null if no current plugin
  61   */
  62  function plugin_get_current() {
  63      global $g_plugin_current;
  64      return( isset( $g_plugin_current[0] ) ? $g_plugin_current[0] : null );
  65  }
  66  
  67  /**
  68   * Add the current plugin to the stack
  69   * @param string Plugin basename
  70   */
  71  function plugin_push_current( $p_basename ) {
  72      global $g_plugin_current;
  73      array_unshift( $g_plugin_current, $p_basename );
  74  }
  75  
  76  /**
  77   * Remove the current plugin from the stack
  78   * @return string Plugin basename, or null if no current plugin
  79   */
  80  function plugin_pop_current() {
  81      global $g_plugin_current;
  82      return( isset( $g_plugin_current[0] ) ? array_shift( $g_plugin_current ) : null );
  83  }
  84  
  85  /**
  86   * Get the URL to the plugin wrapper page.
  87   * @param string Page name
  88   * @param string Plugin basename (defaults to current plugin)
  89   */
  90  function plugin_page( $p_page, $p_redirect = false, $p_basename = null ) {
  91      if( is_null( $p_basename ) ) {
  92          $t_current = plugin_get_current();
  93      } else {
  94          $t_current = $p_basename;
  95      }
  96      if( $p_redirect ) {
  97          return 'plugin.php?page=' . $t_current . '/' . $p_page;
  98      } else {
  99          return helper_mantis_url( 'plugin.php?page=' . $t_current . '/' . $p_page );
 100      }
 101  }
 102  
 103  /**
 104   * Return a path to a plugin file.
 105   * @param string File name
 106   * @param string Plugin basename
 107   * @return mixed File path or false if FNF
 108   */
 109  function plugin_file_path( $p_filename, $p_basename ) {
 110      $t_file_path = config_get( 'plugin_path' );
 111      $t_file_path .= $p_basename . DIRECTORY_SEPARATOR;
 112      $t_file_path .= 'files' . DIRECTORY_SEPARATOR . $p_filename;
 113  
 114      return( is_file( $t_file_path ) ? $t_file_path : false );
 115  }
 116  
 117  /**
 118   * Get the URL to the plugin wrapper page.
 119   * @param string Page name
 120   * @param string Plugin basename (defaults to current plugin)
 121   */
 122  function plugin_file( $p_file, $p_redirect = false, $p_basename = null ) {
 123      if( is_null( $p_basename ) ) {
 124          $t_current = plugin_get_current();
 125      } else {
 126          $t_current = $p_basename;
 127      }
 128      if( $p_redirect ) {
 129          return 'plugin_file.php?file=' . $t_current . '/' . $p_file;
 130      } else {
 131          return helper_mantis_url( 'plugin_file.php?file=' . $t_current . '/' . $p_file );
 132      }
 133  }
 134  
 135  /**
 136   * Include the contents of a file as output.
 137   * @param string File name
 138   * @param string Plugin basename
 139   */
 140  function plugin_file_include( $p_filename, $p_basename = null ) {
 141      if( is_null( $p_basename ) ) {
 142          $t_current = plugin_get_current();
 143      } else {
 144          $t_current = $p_basename;
 145      }
 146  
 147      $t_file_path = plugin_file_path( $p_filename, $t_current );
 148      if( false === $t_file_path ) {
 149          trigger_error( ERROR_GENERIC, ERROR );
 150      }
 151  
 152      readfile( $t_file_path );
 153  }
 154  
 155  /**
 156   * Given a base table name for a plugin, add appropriate prefix and suffix.
 157   * Convenience for plugin schema definitions.
 158   * @param string Table name
 159   * @param string Plugin basename (defaults to current plugin)
 160   * @return string Full table name
 161   */
 162  function plugin_table( $p_name, $p_basename = null ) {
 163      if( is_null( $p_basename ) ) {
 164          $t_current = plugin_get_current();
 165      } else {
 166          $t_current = $p_basename;
 167      }
 168      return db_get_table( 'plugin_' . $t_current . '_' . $p_name );
 169  }
 170  
 171  /**
 172   * Get a plugin configuration option.
 173   * @param string Configuration option name
 174   * @param multi Default option value
 175   */
 176  function plugin_config_get( $p_option, $p_default = null, $p_global = false ) {
 177      $t_basename = plugin_get_current();
 178      $t_full_option = 'plugin_' . $t_basename . '_' . $p_option;
 179  
 180      if( $p_global ) {
 181          return config_get_global( $t_full_option, $p_default );
 182      } else {
 183          return config_get( $t_full_option, $p_default );
 184      }
 185  }
 186  
 187  /**
 188   * Set a plugin configuration option in the database.
 189   * @param string Configuration option name
 190   * @param multi Option value
 191   * @param int User ID
 192   * @param int Project ID
 193   * @param int Access threshold
 194   */
 195  function plugin_config_set( $p_option, $p_value, $p_user = NO_USER, $p_project = ALL_PROJECTS, $p_access = DEFAULT_ACCESS_LEVEL ) {
 196      if( $p_access == DEFAULT_ACCESS_LEVEL ) {
 197          $p_access = config_get_global( 'admin_site_threshold' );
 198      }
 199  
 200      $t_basename = plugin_get_current();
 201      $t_full_option = 'plugin_' . $t_basename . '_' . $p_option;
 202  
 203      config_set( $t_full_option, $p_value, $p_user, $p_project, $p_access );
 204  }
 205  
 206  /**
 207   * Delete a plugin configuration option from the database.
 208   * @param string Configuration option name
 209   * @param int User ID
 210   * @param int Project ID
 211   */
 212  function plugin_config_delete( $p_option, $p_user = ALL_USERS, $p_project = ALL_PROJECTS ) {
 213      $t_basename = plugin_get_current();
 214      $t_full_option = 'plugin_' . $t_basename . '_' . $p_option;
 215  
 216      config_delete( $t_full_option, $p_user, $p_project );
 217  }
 218  
 219  /**
 220   * Set plugin default values to global values without overriding anything.
 221   * @param array Array of configuration option name/value pairs.
 222   */
 223  function plugin_config_defaults( $p_options ) {
 224      if( !is_array( $p_options ) ) {
 225          return;
 226      }
 227  
 228      $t_basename = plugin_get_current();
 229      $t_option_base = 'plugin_' . $t_basename . '_';
 230  
 231      foreach( $p_options as $t_option => $t_value ) {
 232          $t_full_option = $t_option_base . $t_option;
 233  
 234          config_set_global( $t_full_option, $t_value, false );
 235      }
 236  }
 237  
 238  /**
 239   * Get a language string for the plugin.
 240   * Automatically prepends plugin_<basename> to the string requested.
 241   * @param string Language string name
 242   * @param string Plugin basename
 243   * @return string Language string
 244   */
 245  function plugin_lang_get( $p_name, $p_basename = null ) {
 246      if( is_null( $p_basename ) ) {
 247          $t_basename = plugin_get_current();
 248      } else {
 249          $t_basename = $p_basename;
 250      }
 251  
 252      $t_name = 'plugin_' . $t_basename . '_' . $p_name;
 253  
 254      return lang_get( $t_name );
 255  }
 256  
 257  function plugin_history_log( $p_bug_id, $p_field_name, $p_old_value, $p_new_value = '', $p_user_id = null, $p_basename = null ) {
 258      if( is_null( $p_basename ) ) {
 259          $t_basename = plugin_get_current();
 260      } else {
 261          $t_basename = $p_basename;
 262      }
 263  
 264      $t_field_name = $t_basename . '_' . $p_field_name;
 265  
 266      history_log_event_direct( $p_bug_id, $t_field_name, $p_old_value, $p_new_value, $p_user_id, PLUGIN_HISTORY );
 267  }
 268  
 269  /**
 270   * Trigger a plugin-specific error with the given name and type.
 271   * @param string Error name
 272   * @param int Error type
 273   * @param string Plugin basename
 274   */
 275  function plugin_error( $p_error_name, $p_error_type = ERROR, $p_basename = null ) {
 276      if( is_null( $p_basename ) ) {
 277          $t_basename = plugin_get_current();
 278      } else {
 279          $t_basename = $p_basename;
 280      }
 281  
 282      $t_error_code = "plugin_$t_basename}_$p_error_name}";
 283  
 284      trigger_error( $t_error_code, $p_error_type );
 285  
 286      return null;
 287  }
 288  
 289  /**
 290   * Hook a plugin's callback function to an event.
 291   * @param string Event name
 292   * @param string Callback function
 293   */
 294  function plugin_event_hook( $p_name, $p_callback ) {
 295      $t_basename = plugin_get_current();
 296      event_hook( $p_name, $p_callback, $t_basename );
 297  }
 298  
 299  /**
 300   * Hook multiple plugin callbacks at once.
 301   * @param array Array of event name/callback key/value pairs
 302   */
 303  function plugin_event_hook_many( $p_hooks ) {
 304      if( !is_array( $p_hooks ) ) {
 305          return;
 306      }
 307  
 308      $t_basename = plugin_get_current();
 309  
 310      foreach( $p_hooks as $t_event => $t_callbacks ) {
 311          if( !is_array( $t_callbacks ) ) {
 312              event_hook( $t_event, $t_callbacks, $t_basename );
 313              continue;
 314          }
 315  
 316          foreach( $t_callbacks as $t_callback ) {
 317              event_hook( $t_event, $t_callback, $t_basename );
 318          }
 319      }
 320  }
 321  
 322  /**
 323   * Allows a plugin to declare a 'child plugin' that
 324   * can be loaded from the same parent directory.
 325   * @param string Child plugin basename.
 326   */
 327  function plugin_child( $p_child ) {
 328      $t_basename = plugin_get_current();
 329  
 330      $t_plugin = plugin_register( $t_basename, false, $p_child );
 331  
 332      if( !is_null( $t_plugin ) ) {
 333          plugin_init( $p_child );
 334      }
 335  
 336      return $t_plugin;
 337  }
 338  
 339  # ## Plugin Management Helpers
 340  
 341  /**
 342   * Checks if a given plugin has been registered and initialized,
 343   * and returns a boolean value representing the "loaded" state.
 344   * @param string Plugin basename
 345   * @return boolean Plugin loaded
 346   */
 347  function plugin_is_loaded( $p_basename ) {
 348      global $g_plugin_cache_init;
 349  
 350      return ( isset( $g_plugin_cache_init[ $p_basename ] ) && $g_plugin_cache_init[ $p_basename ] );
 351  }
 352  
 353  /**
 354   * Converts a version string to an array, using some punctuation and
 355   * number/lettor boundaries as splitting points.
 356   * @param string Version string
 357   * @return array Version array
 358   */
 359  function plugin_version_array( $p_version ) {
 360      $t_version = preg_replace( '/([a-zA-Z]+)([0-9]+)/', '\1.\2', $p_version );
 361      $t_version = preg_replace( '/([0-9]+)([a-zA-Z]+)/', '\1.\2', $t_version );
 362  
 363      $t_search = array(
 364          ',',
 365          '-',
 366          '_',
 367      );
 368  
 369      $t_replace = array(
 370          '.',
 371          '.',
 372          '.',
 373      );
 374  
 375      $t_version = explode( '.', str_replace( $t_search, $t_replace, $t_version ) );
 376  
 377      return $t_version;
 378  }
 379  
 380  /**
 381   * Checks two version arrays sequentially for minimum or maximum version dependencies.
 382   * @param array Version array to check
 383   * @param array Version array required
 384   * @param boolean Minimum (false) or maximum (true) version check
 385   * @return int 1 if the version dependency succeeds, -1 if it fails
 386   */
 387  function plugin_version_check( $p_version1, $p_version2, $p_maximum = false ) {
 388      while( count( $p_version1 ) > 0 && count( $p_version2 ) > 0 ) {
 389  
 390          # Grab the next version bits
 391          $t_version1 = array_shift( $p_version1 );
 392          $t_version2 = array_shift( $p_version2 );
 393  
 394          # Convert to integers if possible
 395          if( is_numeric( $t_version1 ) ) {
 396              $t_version1 = (int) $t_version1;
 397          }
 398          if( is_numeric( $t_version2 ) ) {
 399              $t_version2 = (int) $t_version2;
 400          }
 401  
 402          # Check for immediate version differences
 403          if( $p_maximum ) {
 404              if( $t_version1 < $t_version2 ) {
 405                  return 1;
 406              }
 407              else if( $t_version1 > $t_version2 ) {
 408                  return -1;
 409              }
 410          } else {
 411              if( $t_version1 > $t_version2 ) {
 412                  return 1;
 413              }
 414              else if( $t_version1 < $t_version2 ) {
 415                  return -1;
 416              }
 417          }
 418      }
 419  
 420      # Versions matched exactly
 421      if ( count( $p_version1 ) == 0 && count( $p_version2 ) == 0 ) {
 422          return 1;
 423      }
 424  
 425      # Handle unmatched version bits
 426      if( $p_maximum ) {
 427          if ( count( $p_version2 ) > 0 ) {
 428              return 1;
 429          }
 430      } else {
 431          if ( count( $p_version1 ) > 0 ) {
 432              return 1;
 433          }
 434      }
 435  
 436      # No more comparisons
 437      return -1;
 438  }
 439  
 440  /**
 441   * Check a plugin dependency given a basename and required version.
 442   * Versions are checked using PHP's library version_compare routine
 443   * and allows both minimum and maximum version requirements.
 444   * Returns 1 if plugin dependency is met, 0 if dependency not met,
 445   * or -1 if dependency is the wrong version.
 446   * @param string Plugin basename
 447   * @param string Required version
 448   * @return integer Plugin dependency status
 449   */
 450  function plugin_dependency( $p_basename, $p_required, $p_initialized = false ) {
 451      global $g_plugin_cache, $g_plugin_cache_init;
 452  
 453      # check for registered dependency
 454      if( isset( $g_plugin_cache[$p_basename] ) ) {
 455  
 456          # require dependency initialized?
 457          if( $p_initialized && !isset( $g_plugin_cache_init[$p_basename] ) ) {
 458              return 0;
 459          }
 460  
 461          $t_required_array = explode( ',', $p_required );
 462  
 463          foreach( $t_required_array as $t_required ) {
 464              $t_required = trim( $t_required );
 465              $t_maximum = false;
 466  
 467              # check for a less-than-or-equal version requirement
 468              $t_ltpos = strpos( $t_required, '<=' );
 469              if( $t_ltpos !== false ) {
 470                  $t_required = trim( utf8_substr( $t_required, $t_ltpos + 2 ) );
 471                  $t_maximum = true;
 472              } else {
 473                  $t_ltpos = strpos( $t_required, '<' );
 474                  if( $t_ltpos !== false ) {
 475                      $t_required = trim( utf8_substr( $t_required, $t_ltpos + 1 ) );
 476                      $t_maximum = true;
 477                  }
 478              }
 479  
 480              $t_version1 = plugin_version_array( $g_plugin_cache[$p_basename]->version );
 481              $t_version2 = plugin_version_array( $t_required );
 482  
 483              $t_check = plugin_version_check( $t_version1, $t_version2, $t_maximum );
 484  
 485              if ( $t_check < 1 ) {
 486                  return $t_check;
 487              }
 488          }
 489  
 490          return 1;
 491      } else {
 492          return 0;
 493      }
 494  }
 495  
 496  /**
 497   * Checks to see if a plugin is 'protected' from uninstall.
 498   * @param string Plugin basename
 499   * @return boolean True if plugin is protected
 500   */
 501  function plugin_protected( $p_basename ) {
 502      global $g_plugin_cache_protected;
 503  
 504      # For pseudo-plugin MantisCore, return protected as 1.
 505      if( $p_basename == 'MantisCore' ) {
 506          return 1;
 507      }
 508  
 509      return $g_plugin_cache_protected[$p_basename];
 510  }
 511  
 512  /**
 513   * Gets a plugin's priority.
 514   * @param string Plugin basename
 515   * @return int Plugin priority
 516   */
 517  function plugin_priority( $p_basename ) {
 518      global $g_plugin_cache_priority;
 519  
 520      # For pseudo-plugin MantisCore, return priority as 3.
 521      if( $p_basename == 'MantisCore' ) {
 522          return 3;
 523      }
 524  
 525      return $g_plugin_cache_priority[$p_basename];
 526  }
 527  
 528  # ## Plugin management functions
 529  /**
 530   * Determine if a given plugin is installed.
 531   * @param string Plugin basename
 532   * @return boolean True if plugin is installed
 533   */
 534  function plugin_is_installed( $p_basename ) {
 535      $t_plugin_table = db_get_table( 'plugin' );
 536  
 537      $t_forced_plugins = config_get_global( 'plugins_force_installed' );
 538      foreach( $t_forced_plugins as $t_basename => $t_priority ) {
 539          if ( $t_basename == $p_basename ) {
 540              return true;
 541          }
 542      }
 543  
 544      $t_query = "SELECT COUNT(*) FROM $t_plugin_table WHERE basename=" . db_param();
 545      $t_result = db_query_bound( $t_query, array( $p_basename ) );
 546      return( 0 < db_result( $t_result ) );
 547  }
 548  
 549  /**
 550   * Install a plugin to the database.
 551   * @param string Plugin basename
 552   */
 553  function plugin_install( $p_plugin ) {
 554      access_ensure_global_level( config_get_global( 'manage_plugin_threshold' ) );
 555  
 556      if( plugin_is_installed( $p_plugin->basename ) ) {
 557          trigger_error( ERROR_PLUGIN_ALREADY_INSTALLED, WARNING );
 558          return null;
 559      }
 560  
 561      plugin_push_current( $p_plugin->basename );
 562  
 563      if( !$p_plugin->install() ) {
 564          plugin_pop_current( $p_plugin->basename );
 565          return null;
 566      }
 567  
 568      $t_plugin_table = db_get_table( 'plugin' );
 569  
 570      $t_query = "INSERT INTO $t_plugin_table ( basename, enabled )
 571                  VALUES ( " . db_param() . ", '1' )";
 572      db_query_bound( $t_query, array( $p_plugin->basename ) );
 573  
 574      if( false === ( plugin_config_get( 'schema', false ) ) ) {
 575          plugin_config_set( 'schema', -1 );
 576      }
 577  
 578      plugin_upgrade( $p_plugin );
 579  
 580      plugin_pop_current();
 581  }
 582  
 583  /**
 584   * Determine if an installed plugin needs to upgrade its schema.
 585   * @param string Plugin basename
 586   * @return boolean True if plugin needs schema ugrades.
 587   */
 588  function plugin_needs_upgrade( $p_plugin ) {
 589      $t_plugin_schema = $p_plugin->schema();
 590      if( is_null( $t_plugin_schema ) ) {
 591          return false;
 592      }
 593  
 594      $t_config_option = 'plugin_' . $p_plugin->basename . '_schema';
 595      $t_plugin_schema_version = config_get( $t_config_option, -1, ALL_USERS, ALL_PROJECTS );
 596  
 597      return( $t_plugin_schema_version < count( $t_plugin_schema ) - 1 );
 598  }
 599  
 600  /**
 601   * Upgrade an installed plugin's schema.
 602   * @param string Plugin basename
 603   * @return multi True if upgrade completed, null if problem
 604   */
 605  function plugin_upgrade( $p_plugin ) {
 606      access_ensure_global_level( config_get_global( 'manage_plugin_threshold' ) );
 607  
 608      if( !plugin_is_installed( $p_plugin->basename ) ) {
 609          return;
 610      }
 611  
 612      require_api( 'install_helper_functions_api.php' );
 613  
 614      plugin_push_current( $p_plugin->basename );
 615  
 616      $t_schema_version = plugin_config_get( 'schema', -1 );
 617      $t_schema = $p_plugin->schema();
 618  
 619      global $g_db;
 620      $t_dict = NewDataDictionary( $g_db );
 621  
 622      $i = $t_schema_version + 1;
 623      while( $i < count( $t_schema ) ) {
 624          if( !$p_plugin->upgrade( $i ) ) {
 625              plugin_pop_current();
 626              return false;
 627          }
 628  
 629          $t_target = $t_schema[$i][1][0];
 630  
 631          if( $t_schema[$i][0] == 'InsertData' ) {
 632              $t_sqlarray = array(
 633                  'INSERT INTO ' . $t_schema[$i][1][0] . $t_schema[$i][1][1],
 634              );
 635          } else if( $t_schema[$i][0] == 'UpdateSQL' ) {
 636              $t_sqlarray = array(
 637                  'UPDATE ' . $t_schema[$i][1][0] . $t_schema[$i][1][1],
 638              );
 639              $t_target = $t_schema[$i][1];
 640          } else if( $t_schema[$i][0] == 'UpdateFunction' ) {
 641              $t_sqlarray = false;
 642              if( isset( $t_schema[$i][2] ) ) {
 643                  $t_status = call_user_func( 'install_' . $t_schema[$i][1], $t_schema[$i][2] );
 644              } else {
 645                  $t_status = call_user_func( 'install_' . $t_schema[$i][1] );
 646              }
 647          } else {
 648              $t_sqlarray = call_user_func_array( Array( $t_dict, $t_schema[$i][0] ), $t_schema[$i][1] );
 649          }
 650  
 651          if( $t_sqlarray ) {
 652              $t_status = $t_dict->ExecuteSQLArray( $t_sqlarray );
 653          }
 654  
 655          if( 2 == $t_status ) {
 656              plugin_config_set( 'schema', $i );
 657          } else {
 658              error_parameters( $i );
 659              trigger_error( ERROR_PLUGIN_UPGRADE_FAILED, ERROR );
 660              return null;
 661          }
 662  
 663          $i++;
 664      }
 665  
 666      plugin_pop_current();
 667  
 668      return true;
 669  }
 670  
 671  /**
 672   * Uninstall a plugin from the database.
 673   * @param string Plugin basename
 674   */
 675  function plugin_uninstall( $p_plugin ) {
 676      access_ensure_global_level( config_get_global( 'manage_plugin_threshold' ) );
 677  
 678      if( !plugin_is_installed( $p_plugin->basename ) || plugin_protected( $p_plugin->basename ) ) {
 679          return;
 680      }
 681  
 682      $t_plugin_table = db_get_table( 'plugin' );
 683  
 684      $t_query = "DELETE FROM $t_plugin_table WHERE basename=" . db_param();
 685      db_query_bound( $t_query, array( $p_plugin->basename ) );
 686  
 687      plugin_push_current( $p_plugin->basename );
 688  
 689      $p_plugin->uninstall();
 690  
 691      plugin_pop_current();
 692  }
 693  
 694  # ## Core usage only.
 695  /**
 696   * Search the plugins directory for plugins.
 697   * @return array Plugin basename/info key/value pairs.
 698   */
 699  function plugin_find_all() {
 700      $t_plugin_path = config_get_global( 'plugin_path' );
 701      $t_plugins = array(
 702          'MantisCore' => new MantisCorePlugin( 'MantisCore' ),
 703      );
 704  
 705      if( $t_dir = opendir( $t_plugin_path ) ) {
 706          while(( $t_file = readdir( $t_dir ) ) !== false ) {
 707              if( '.' == $t_file || '..' == $t_file ) {
 708                  continue;
 709              }
 710              if( is_dir( $t_plugin_path . $t_file ) ) {
 711                  $t_plugin = plugin_register( $t_file, true );
 712  
 713                  if( !is_null( $t_plugin ) ) {
 714                      $t_plugins[$t_file] = $t_plugin;
 715                  }
 716              }
 717          }
 718          closedir( $t_dir );
 719      }
 720      return $t_plugins;
 721  }
 722  
 723  /**
 724   * Load a plugin's core class file.
 725   * @param string Plugin basename
 726   */
 727  function plugin_include( $p_basename, $p_child = null ) {
 728      $t_path = config_get_global( 'plugin_path' ) . $p_basename . DIRECTORY_SEPARATOR;
 729  
 730      if( is_null( $p_child ) ) {
 731          $t_plugin_file = $t_path . $p_basename . '.php';
 732      } else {
 733          $t_plugin_file = $t_path . $p_child . '.php';
 734      }
 735      $t_included = false;
 736      if( is_file( $t_plugin_file ) ) {
 737          include_once( $t_plugin_file );
 738          $t_included = true;
 739      }
 740  
 741      return $t_included;
 742  }
 743  
 744  /**
 745   * Register a plugin with MantisBT.
 746   * The plugin class must already be loaded before calling.
 747   * @param string Plugin classname without 'Plugin' postfix
 748   */
 749  function plugin_register( $p_basename, $p_return = false, $p_child = null ) {
 750      global $g_plugin_cache;
 751  
 752      $t_basename = is_null( $p_child ) ? $p_basename : $p_child;
 753      if( !isset( $g_plugin_cache[$t_basename] ) ) {
 754          if( is_null( $p_child ) ) {
 755              $t_classname = $p_basename . 'Plugin';
 756          } else {
 757              $t_classname = $p_child . 'Plugin';
 758          }
 759  
 760          # Include the plugin script if the class is not already declared.
 761          if( !class_exists( $t_classname ) ) {
 762              if( !plugin_include( $p_basename, $p_child ) ) {
 763                  return null;
 764              }
 765          }
 766  
 767          # Make sure the class exists and that it's of the right type.
 768          if( class_exists( $t_classname ) && is_subclass_of( $t_classname, 'MantisPlugin' ) ) {
 769              plugin_push_current( is_null( $p_child ) ? $p_basename : $p_child );
 770  
 771              $t_plugin = new $t_classname( is_null( $p_child ) ? $p_basename : $p_child );
 772  
 773              plugin_pop_current();
 774  
 775              # Final check on the class
 776              if( is_null( $t_plugin->name ) || is_null( $t_plugin->version ) ) {
 777                  return null;
 778              }
 779  
 780              if( $p_return ) {
 781                  return $t_plugin;
 782              } else {
 783                  $g_plugin_cache[$t_basename] = $t_plugin;
 784              }
 785          }
 786      }
 787  
 788      return $g_plugin_cache[$t_basename];
 789  }
 790  
 791  /**
 792   * Find and register all installed plugins.
 793   */
 794  function plugin_register_installed() {
 795      global $g_plugin_cache_priority, $g_plugin_cache_protected;
 796  
 797      # register plugins specified in the site configuration
 798      $t_forced_plugins = config_get_global( 'plugins_force_installed' );
 799      foreach( $t_forced_plugins as $t_basename => $t_priority ) {
 800          plugin_register( $t_basename );
 801          $g_plugin_cache_priority[$t_basename] = $t_priority;
 802          $g_plugin_cache_protected[$t_basename] = true;
 803      }
 804  
 805      # register plugins installed via the interface/database
 806      $t_plugin_table = db_get_table( 'plugin' );
 807  
 808      $t_query = "SELECT basename, priority, protected FROM $t_plugin_table WHERE enabled=" . db_param() . ' ORDER BY priority DESC';
 809      $t_result = db_query_bound( $t_query, Array( 1 ) );
 810  
 811      while( $t_row = db_fetch_array( $t_result ) ) {
 812          $t_basename = $t_row['basename'];
 813          plugin_register( $t_basename );
 814          $g_plugin_cache_priority[$t_basename] = $t_row['priority'];
 815          $g_plugin_cache_protected[$t_basename] = $t_row['protected'];
 816      }
 817  }
 818  
 819  /**
 820   * Initialize all installed plugins.
 821   * Post-signals EVENT_PLUGIN_INIT.
 822   */
 823  function plugin_init_installed() {
 824      if( OFF == config_get_global( 'plugins_enabled' ) || !db_table_exists( db_get_table( 'plugin' ) ) ) {
 825          return;
 826      }
 827  
 828      global $g_plugin_cache, $g_plugin_current, $g_plugin_cache_priority, $g_plugin_cache_protected, $g_plugin_cache_init;
 829      $g_plugin_cache = array();
 830      $g_plugin_current = array();
 831      $g_plugin_cache_init = array();
 832      $g_plugin_cache_priority = array();
 833      $g_plugin_cache_protected = array();
 834  
 835      plugin_register( 'MantisCore' );
 836      plugin_register_installed();
 837  
 838      $t_plugins = array_keys( $g_plugin_cache );
 839  
 840      do {
 841          $t_continue = false;
 842          $t_plugins_retry = array();
 843  
 844          foreach( $t_plugins as $t_basename ) {
 845              if( plugin_init( $t_basename ) ) {
 846                  $t_continue = true;
 847  
 848              } else {
 849                  # Dependent plugin
 850                  $t_plugins_retry[] = $t_basename;
 851              }
 852          }
 853  
 854          $t_plugins = $t_plugins_retry;
 855      }
 856      while( $t_continue );
 857  
 858      event_signal( 'EVENT_PLUGIN_INIT' );
 859  }
 860  
 861  /**
 862   * Initialize a single plugin.
 863   * @param string Plugin basename
 864   * @return boolean True if plugin initialized, false otherwise.
 865   */
 866  function plugin_init( $p_basename ) {
 867      global $g_plugin_cache, $g_plugin_cache_init;
 868  
 869      # handle dependent plugins
 870      if( isset( $g_plugin_cache[$p_basename] ) ) {
 871          $t_plugin = $g_plugin_cache[$p_basename];
 872  
 873          # hard dependencies; return false if the dependency is not registered,
 874          # does not meet the version requirement, or is not yet initialized.
 875          if( is_array( $t_plugin->requires ) ) {
 876              foreach( $t_plugin->requires as $t_required => $t_version ) {
 877                  if( plugin_dependency( $t_required, $t_version, true ) !== 1 ) {
 878                      return false;
 879                  }
 880              }
 881          }
 882  
 883          # soft dependencies; only return false if the soft dependency is
 884          # registered, but not yet initialized.
 885          if( is_array( $t_plugin->uses ) ) {
 886              foreach( $t_plugin->uses as $t_used => $t_version ) {
 887                  if ( isset( $g_plugin_cache[ $t_used ] ) && !isset( $g_plugin_cache_init[ $t_used ] ) ) {
 888                      return false;
 889                  }
 890              }
 891          }
 892  
 893          # if plugin schema needs an upgrade, do not initialize
 894          if ( plugin_needs_upgrade( $t_plugin ) ) {
 895              return false;
 896          }
 897  
 898          plugin_push_current( $p_basename );
 899  
 900          # load plugin error strings
 901          global $g_lang_strings;
 902          $t_lang = lang_get_current();
 903          $t_plugin_errors = $t_plugin->errors();
 904  
 905          foreach( $t_plugin_errors as $t_error_name => $t_error_string ) {
 906              $t_error_code = "plugin_$p_basename}_$t_error_name}";
 907              $g_lang_strings[$t_lang]['MANTIS_ERROR'][$t_error_code] = $t_error_string;
 908          }
 909  
 910          # finish initializing the plugin
 911          $t_plugin->__init();
 912          $g_plugin_cache_init[$p_basename] = true;
 913  
 914          plugin_pop_current();
 915  
 916          return true;
 917      } else {
 918          return false;
 919      }
 920  }


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