[ Index ]

PHP Cross Reference of phpBB-3.2.11-deutsch

title

Body

[close]

/phpbb/module/ -> module_manager.php (source)

   1  <?php
   2  /**
   3   *
   4   * This file is part of the phpBB Forum Software package.
   5   *
   6   * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7   * @license GNU General Public License, version 2 (GPL-2.0)
   8   *
   9   * For full copyright and license information, please see
  10   * the docs/CREDITS.txt file.
  11   *
  12   */
  13  
  14  namespace phpbb\module;
  15  
  16  use phpbb\module\exception\module_exception;
  17  use phpbb\module\exception\module_not_found_exception;
  18  
  19  class module_manager
  20  {
  21      /**
  22       * @var \phpbb\cache\driver\driver_interface
  23       */
  24      protected $cache;
  25  
  26      /**
  27       * @var \phpbb\db\driver\driver_interface
  28       */
  29      protected $db;
  30  
  31      /**
  32       * @var \phpbb\extension\manager
  33       */
  34      protected $extension_manager;
  35  
  36      /**
  37       * @var string
  38       */
  39      protected $modules_table;
  40  
  41      /**
  42       * @var string
  43       */
  44      protected $phpbb_root_path;
  45  
  46      /**
  47       * @var string
  48       */
  49      protected $php_ext;
  50  
  51      /**
  52       * Constructor
  53       *
  54       * @param \phpbb\cache\driver\driver_interface    $cache                Cache driver
  55       * @param \phpbb\db\driver\driver_interface        $db                    Database driver
  56       * @param \phpbb\extension\manager                $ext_manager        Extension manager
  57       * @param string                                $modules_table        Module database table's name
  58       * @param string                                $phpbb_root_path    Path to phpBB's root
  59       * @param string                                $php_ext            Extension of PHP files
  60       */
  61  	public function __construct(\phpbb\cache\driver\driver_interface $cache, \phpbb\db\driver\driver_interface $db, \phpbb\extension\manager $ext_manager, $modules_table, $phpbb_root_path, $php_ext)
  62      {
  63          $this->cache                = $cache;
  64          $this->db                    = $db;
  65          $this->extension_manager    = $ext_manager;
  66          $this->modules_table        = $modules_table;
  67          $this->phpbb_root_path        = $phpbb_root_path;
  68          $this->php_ext                = $php_ext;
  69      }
  70  
  71      /**
  72       * Get row for specified module
  73       *
  74       * @param int        $module_id        ID of the module
  75       * @param string    $module_class    Class of the module (acp, ucp, mcp etc...)
  76       *
  77       * @return array    Array of data fetched from the database
  78       *
  79       * @throws \phpbb\module\exception\module_not_found_exception    When there is no module with $module_id
  80       */
  81  	public function get_module_row($module_id, $module_class)
  82      {
  83          $module_id = (int) $module_id;
  84  
  85          $sql = 'SELECT *
  86              FROM ' . $this->modules_table . "
  87              WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
  88                  AND module_id = $module_id";
  89          $result = $this->db->sql_query($sql);
  90          $row = $this->db->sql_fetchrow($result);
  91          $this->db->sql_freeresult($result);
  92  
  93          if (!$row)
  94          {
  95              throw new module_not_found_exception('NO_MODULE');
  96          }
  97  
  98          return $row;
  99      }
 100  
 101      /**
 102       * Get available module information from module files
 103       *
 104       * @param string    $module_class        Class of the module (acp, ucp, mcp etc...)
 105       * @param string    $module                ID of module
 106       * @param bool        $use_all_available    Use all available instead of just all
 107       *                                        enabled extensions
 108       *
 109       * @return array    Array with module information gathered from module info files.
 110       */
 111  	public function get_module_infos($module_class, $module = '', $use_all_available = false)
 112      {
 113          $directory = $this->phpbb_root_path . 'includes/' . $module_class . '/info/';
 114          $fileinfo = array();
 115  
 116          $finder = $this->extension_manager->get_finder($use_all_available);
 117  
 118          $modules = $finder
 119              ->extension_suffix('_module')
 120              ->extension_directory("/$module_class")
 121              ->core_path("includes/$module_class/info/")
 122              ->core_prefix($module_class . '_')
 123              ->get_classes(true);
 124  
 125          foreach ($modules as $cur_module)
 126          {
 127              // Skip entries we do not need if we know the module we are
 128              // looking for
 129              if ($module && strpos(str_replace('\\', '_', $cur_module), $module) === false && $module !== $cur_module)
 130              {
 131                  continue;
 132              }
 133  
 134              $info_class = preg_replace('/_module$/', '_info', $cur_module);
 135  
 136              // If the class does not exist it might be following the old
 137              // format. phpbb_acp_info_acp_foo needs to be turned into
 138              // acp_foo_info and the respective file has to be included
 139              // manually because it does not support auto loading
 140              $old_info_class_file = str_replace("phpbb_{$module_class}_info_", '', $cur_module);
 141              $old_info_class = $old_info_class_file . '_info';
 142  
 143              if (class_exists($old_info_class))
 144              {
 145                  $info_class = $old_info_class;
 146              }
 147              else if (!class_exists($info_class))
 148              {
 149                  $info_class = $old_info_class;
 150  
 151                  // need to check class exists again because previous checks triggered autoloading
 152                  if (!class_exists($info_class) && file_exists($directory . $old_info_class_file . '.' . $this->php_ext))
 153                  {
 154                      include($directory . $old_info_class_file . '.' . $this->php_ext);
 155                  }
 156              }
 157  
 158              if (class_exists($info_class))
 159              {
 160                  $info = new $info_class();
 161                  $module_info = $info->module();
 162  
 163                  $main_class = (isset($module_info['filename'])) ? $module_info['filename'] : $cur_module;
 164  
 165                  $fileinfo[$main_class] = $module_info;
 166              }
 167          }
 168  
 169          ksort($fileinfo);
 170  
 171          return $fileinfo;
 172      }
 173  
 174      /**
 175       * Get module branch
 176       *
 177       * @param int        $module_id        ID of the module
 178       * @param string    $module_class    Class of the module (acp, ucp, mcp etc...)
 179       * @param string    $type            Type of branch (Expected values: all, parents or children)
 180       * @param bool        $include_module    Whether or not to include the specified module with $module_id
 181       *
 182       * @return array    Returns an array containing the modules in the specified branch type.
 183       */
 184  	public function get_module_branch($module_id, $module_class, $type = 'all', $include_module = true)
 185      {
 186          $module_id = (int) $module_id;
 187  
 188          switch ($type)
 189          {
 190              case 'parents':
 191                  $condition = 'm1.left_id BETWEEN m2.left_id AND m2.right_id';
 192              break;
 193  
 194              case 'children':
 195                  $condition = 'm2.left_id BETWEEN m1.left_id AND m1.right_id';
 196              break;
 197  
 198              default:
 199                  $condition = 'm2.left_id BETWEEN m1.left_id AND m1.right_id OR m1.left_id BETWEEN m2.left_id AND m2.right_id';
 200              break;
 201          }
 202  
 203          $rows = array();
 204  
 205          $sql = 'SELECT m2.*
 206              FROM ' . $this->modules_table . ' m1
 207              LEFT JOIN ' . $this->modules_table . " m2 ON ($condition)
 208              WHERE m1.module_class = '" . $this->db->sql_escape($module_class) . "'
 209                  AND m2.module_class = '" . $this->db->sql_escape($module_class) . "'
 210                  AND m1.module_id = $module_id
 211              ORDER BY m2.left_id";
 212          $result = $this->db->sql_query($sql);
 213  
 214          while ($row = $this->db->sql_fetchrow($result))
 215          {
 216              if (!$include_module && $row['module_id'] == $module_id)
 217              {
 218                  continue;
 219              }
 220  
 221              $rows[] = $row;
 222          }
 223          $this->db->sql_freeresult($result);
 224  
 225          return $rows;
 226      }
 227  
 228      /**
 229       * Remove modules cache file
 230       *
 231       * @param string    $module_class    Class of the module (acp, ucp, mcp etc...)
 232       */
 233  	public function remove_cache_file($module_class)
 234      {
 235          // Sanitise for future path use, it's escaped as appropriate for queries
 236          $cache_class = str_replace(array('.', '/', '\\'), '', basename($module_class));
 237          $this->cache->destroy('_modules_' . $cache_class);
 238          $this->cache->destroy('sql', $this->modules_table);
 239      }
 240  
 241      /**
 242       * Update/Add module
 243       *
 244       * @param array    &$module_data    The module data
 245       *
 246       * @throws \phpbb\module\exception\module_not_found_exception    When parent module or the category is not exist
 247       */
 248  	public function update_module_data(&$module_data)
 249      {
 250          if (!isset($module_data['module_id']))
 251          {
 252              // no module_id means we're creating a new category/module
 253              if ($module_data['parent_id'])
 254              {
 255                  $sql = 'SELECT left_id, right_id
 256                      FROM ' . $this->modules_table . "
 257                      WHERE module_class = '" . $this->db->sql_escape($module_data['module_class']) . "'
 258                          AND module_id = " . (int) $module_data['parent_id'];
 259                  $result = $this->db->sql_query($sql);
 260                  $row = $this->db->sql_fetchrow($result);
 261                  $this->db->sql_freeresult($result);
 262  
 263                  if (!$row)
 264                  {
 265                      throw new module_not_found_exception('PARENT_NOT_EXIST');
 266                  }
 267  
 268                  // Workaround
 269                  $row['left_id'] = (int) $row['left_id'];
 270                  $row['right_id'] = (int) $row['right_id'];
 271  
 272                  $sql = 'UPDATE ' . $this->modules_table . "
 273                      SET left_id = left_id + 2, right_id = right_id + 2
 274                      WHERE module_class = '" . $this->db->sql_escape($module_data['module_class']) . "'
 275                          AND left_id > {$row['right_id']}";
 276                  $this->db->sql_query($sql);
 277  
 278                  $sql = 'UPDATE ' . $this->modules_table . "
 279                      SET right_id = right_id + 2
 280                      WHERE module_class = '" . $this->db->sql_escape($module_data['module_class']) . "'
 281                          AND {$row['left_id']} BETWEEN left_id AND right_id";
 282                  $this->db->sql_query($sql);
 283  
 284                  $module_data['left_id'] = (int) $row['right_id'];
 285                  $module_data['right_id'] = (int) $row['right_id'] + 1;
 286              }
 287              else
 288              {
 289                  $sql = 'SELECT MAX(right_id) AS right_id
 290                      FROM ' . $this->modules_table . "
 291                      WHERE module_class = '" . $this->db->sql_escape($module_data['module_class']) . "'";
 292                  $result = $this->db->sql_query($sql);
 293                  $row = $this->db->sql_fetchrow($result);
 294                  $this->db->sql_freeresult($result);
 295  
 296                  $module_data['left_id'] = (int) $row['right_id'] + 1;
 297                  $module_data['right_id'] = (int) $row['right_id'] + 2;
 298              }
 299  
 300              $sql = 'INSERT INTO ' . $this->modules_table . ' ' . $this->db->sql_build_array('INSERT', $module_data);
 301              $this->db->sql_query($sql);
 302  
 303              $module_data['module_id'] = $this->db->sql_nextid();
 304          }
 305          else
 306          {
 307              $row = $this->get_module_row($module_data['module_id'], $module_data['module_class']);
 308  
 309              if ($module_data['module_basename'] && !$row['module_basename'])
 310              {
 311                  // we're turning a category into a module
 312                  $branch = $this->get_module_branch($module_data['module_id'], $module_data['module_class'], 'children', false);
 313  
 314                  if (count($branch))
 315                  {
 316                      throw new module_not_found_exception('NO_CATEGORY_TO_MODULE');
 317                  }
 318              }
 319  
 320              if ($row['parent_id'] != $module_data['parent_id'])
 321              {
 322                  $this->move_module($module_data['module_id'], $module_data['parent_id'], $module_data['module_class']);
 323              }
 324  
 325              $update_ary = $module_data;
 326              unset($update_ary['module_id']);
 327  
 328              $sql = 'UPDATE ' . $this->modules_table . '
 329                  SET ' . $this->db->sql_build_array('UPDATE', $update_ary) . "
 330                  WHERE module_class = '" . $this->db->sql_escape($module_data['module_class']) . "'
 331                      AND module_id = " . (int) $module_data['module_id'];
 332              $this->db->sql_query($sql);
 333          }
 334      }
 335  
 336      /**
 337       * Move module around the tree
 338       *
 339       * @param int        $from_module_id    ID of the current parent module
 340       * @param int        $to_parent_id    ID of the target parent module
 341       * @param string    $module_class    Class of the module (acp, ucp, mcp etc...)
 342       *
 343       * @throws \phpbb\module\exception\module_not_found_exception    If the module specified to move modules from does not
 344       *                                                                 have any children.
 345       */
 346  	public function move_module($from_module_id, $to_parent_id, $module_class)
 347      {
 348          $moved_modules = $this->get_module_branch($from_module_id, $module_class, 'children');
 349  
 350          if (empty($moved_modules))
 351          {
 352              throw new module_not_found_exception();
 353          }
 354  
 355          $from_data = $moved_modules[0];
 356          $diff = count($moved_modules) * 2;
 357  
 358          $moved_ids = array();
 359          for ($i = 0, $size = count($moved_modules); $i < $size; ++$i)
 360          {
 361              $moved_ids[] = $moved_modules[$i]['module_id'];
 362          }
 363  
 364          // Resync parents
 365          $sql = 'UPDATE ' . $this->modules_table . "
 366              SET right_id = right_id - $diff
 367              WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
 368                  AND left_id < " . (int) $from_data['right_id'] . '
 369                  AND right_id > ' . (int) $from_data['right_id'];
 370          $this->db->sql_query($sql);
 371  
 372          // Resync righthand side of tree
 373          $sql = 'UPDATE ' . $this->modules_table . "
 374              SET left_id = left_id - $diff, right_id = right_id - $diff
 375              WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
 376                  AND left_id > " . (int) $from_data['right_id'];
 377          $this->db->sql_query($sql);
 378  
 379          if ($to_parent_id > 0)
 380          {
 381              $to_data = $this->get_module_row($to_parent_id, $module_class);
 382  
 383              // Resync new parents
 384              $sql = 'UPDATE ' . $this->modules_table . "
 385                  SET right_id = right_id + $diff
 386                  WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
 387                      AND " . (int) $to_data['right_id'] . ' BETWEEN left_id AND right_id
 388                      AND ' . $this->db->sql_in_set('module_id', $moved_ids, true);
 389              $this->db->sql_query($sql);
 390  
 391              // Resync the righthand side of the tree
 392              $sql = 'UPDATE ' . $this->modules_table . "
 393                  SET left_id = left_id + $diff, right_id = right_id + $diff
 394                  WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
 395                      AND left_id > " . (int) $to_data['right_id'] . '
 396                      AND ' . $this->db->sql_in_set('module_id', $moved_ids, true);
 397              $this->db->sql_query($sql);
 398  
 399              // Resync moved branch
 400              $to_data['right_id'] += $diff;
 401              if ($to_data['right_id'] > $from_data['right_id'])
 402              {
 403                  $diff = '+ ' . ($to_data['right_id'] - $from_data['right_id'] - 1);
 404              }
 405              else
 406              {
 407                  $diff = '- ' . abs($to_data['right_id'] - $from_data['right_id'] - 1);
 408              }
 409          }
 410          else
 411          {
 412              $sql = 'SELECT MAX(right_id) AS right_id
 413                  FROM ' . $this->modules_table . "
 414                  WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
 415                      AND " . $this->db->sql_in_set('module_id', $moved_ids, true);
 416              $result = $this->db->sql_query($sql);
 417              $row = $this->db->sql_fetchrow($result);
 418              $this->db->sql_freeresult($result);
 419  
 420              $diff = '+ ' . (int) ($row['right_id'] - $from_data['left_id'] + 1);
 421          }
 422  
 423          $sql = 'UPDATE ' . $this->modules_table . "
 424              SET left_id = left_id $diff, right_id = right_id $diff
 425              WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
 426                  AND " . $this->db->sql_in_set('module_id', $moved_ids);
 427          $this->db->sql_query($sql);
 428      }
 429  
 430      /**
 431       * Remove module from tree
 432       *
 433       * @param int        $module_id        ID of the module to delete
 434       * @param string    $module_class    Class of the module (acp, ucp, mcp etc...)
 435       *
 436       * @throws \phpbb\module\exception\module_exception    When the specified module cannot be removed
 437       */
 438  	public function delete_module($module_id, $module_class)
 439      {
 440          $module_id = (int) $module_id;
 441  
 442          $row = $this->get_module_row($module_id, $module_class);
 443  
 444          $branch = $this->get_module_branch($module_id, $module_class, 'children', false);
 445  
 446          if (count($branch))
 447          {
 448              throw new module_exception('CANNOT_REMOVE_MODULE');
 449          }
 450  
 451          // If not move
 452          $diff = 2;
 453          $sql = 'DELETE FROM ' . $this->modules_table . "
 454              WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
 455                  AND module_id = $module_id";
 456          $this->db->sql_query($sql);
 457  
 458          $row['right_id'] = (int) $row['right_id'];
 459          $row['left_id'] = (int) $row['left_id'];
 460  
 461          // Resync tree
 462          $sql = 'UPDATE ' . $this->modules_table . "
 463              SET right_id = right_id - $diff
 464              WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
 465                  AND left_id < {$row['right_id']} AND right_id > {$row['right_id']}";
 466          $this->db->sql_query($sql);
 467  
 468          $sql = 'UPDATE ' . $this->modules_table . "
 469              SET left_id = left_id - $diff, right_id = right_id - $diff
 470              WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
 471                  AND left_id > {$row['right_id']}";
 472          $this->db->sql_query($sql);
 473      }
 474  
 475      /**
 476       * Move module position by $steps up/down
 477       *
 478       * @param array        $module_row        Array of module data
 479       * @param string    $module_class    Class of the module (acp, ucp, mcp etc...)
 480       * @param string    $action            Direction of moving (valid values: move_up or move_down)
 481       * @param int        $steps            Number of steps to move module
 482       *
 483       * @return string    Returns the language name of the module
 484       *
 485       * @throws \phpbb\module\exception\module_not_found_exception    When the specified module does not exists
 486       */
 487  	public function move_module_by($module_row, $module_class, $action = 'move_up', $steps = 1)
 488      {
 489          /**
 490           * Fetch all the siblings between the module's current spot
 491           * and where we want to move it to. If there are less than $steps
 492           * siblings between the current spot and the target then the
 493           * module will move as far as possible
 494           */
 495          $sql = 'SELECT module_id, left_id, right_id, module_langname
 496              FROM ' . $this->modules_table . "
 497              WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
 498                  AND parent_id = " . (int) $module_row['parent_id'] . '
 499                  AND ' . (($action == 'move_up') ? 'right_id < ' . (int) $module_row['right_id'] . ' ORDER BY right_id DESC' : 'left_id > ' . (int) $module_row['left_id'] . ' ORDER BY left_id ASC');
 500          $result = $this->db->sql_query_limit($sql, $steps);
 501  
 502          $target = array();
 503          while ($row = $this->db->sql_fetchrow($result))
 504          {
 505              $target = $row;
 506          }
 507          $this->db->sql_freeresult($result);
 508  
 509          if (!count($target))
 510          {
 511              // The module is already on top or bottom
 512              throw new module_not_found_exception();
 513          }
 514  
 515          /**
 516           * $left_id and $right_id define the scope of the nodes that are affected by the move.
 517           * $diff_up and $diff_down are the values to substract or add to each node's left_id
 518           * and right_id in order to move them up or down.
 519           * $move_up_left and $move_up_right define the scope of the nodes that are moving
 520           * up. Other nodes in the scope of ($left_id, $right_id) are considered to move down.
 521           */
 522          if ($action == 'move_up')
 523          {
 524              $left_id = (int) $target['left_id'];
 525              $right_id = (int) $module_row['right_id'];
 526  
 527              $diff_up = (int) ($module_row['left_id'] - $target['left_id']);
 528              $diff_down = (int) ($module_row['right_id'] + 1 - $module_row['left_id']);
 529  
 530              $move_up_left = (int) $module_row['left_id'];
 531              $move_up_right = (int) $module_row['right_id'];
 532          }
 533          else
 534          {
 535              $left_id = (int) $module_row['left_id'];
 536              $right_id = (int) $target['right_id'];
 537  
 538              $diff_up = (int) ($module_row['right_id'] + 1 - $module_row['left_id']);
 539              $diff_down = (int) ($target['right_id'] - $module_row['right_id']);
 540  
 541              $move_up_left = (int) ($module_row['right_id'] + 1);
 542              $move_up_right = (int) $target['right_id'];
 543          }
 544  
 545          // Now do the dirty job
 546          $sql = 'UPDATE ' . $this->modules_table . "
 547              SET left_id = left_id + CASE
 548                  WHEN left_id BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up}
 549                  ELSE {$diff_down}
 550              END,
 551              right_id = right_id + CASE
 552                  WHEN right_id BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up}
 553                  ELSE {$diff_down}
 554              END
 555              WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
 556                  AND left_id BETWEEN {$left_id} AND {$right_id}
 557                  AND right_id BETWEEN {$left_id} AND {$right_id}";
 558          $this->db->sql_query($sql);
 559  
 560          $this->remove_cache_file($module_class);
 561  
 562          return $target['module_langname'];
 563      }
 564  }


Generated: Wed Nov 11 20:33:01 2020 Cross-referenced by PHPXref 0.7.1