[ Index ]

PHP Cross Reference of phpBB-3.1.12-deutsch

title

Body

[close]

/phpbb/db/migration/tool/ -> module.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\db\migration\tool;
  15  
  16  /**
  17  * Migration module management tool
  18  */
  19  class module implements \phpbb\db\migration\tool\tool_interface
  20  {
  21      /** @var \phpbb\cache\service */
  22      protected $cache;
  23  
  24      /** @var \phpbb\db\driver\driver_interface */
  25      protected $db;
  26  
  27      /** @var \phpbb\user */
  28      protected $user;
  29  
  30      /** @var string */
  31      protected $phpbb_root_path;
  32  
  33      /** @var string */
  34      protected $php_ext;
  35  
  36      /** @var string */
  37      protected $modules_table;
  38  
  39      /** @var array */
  40      protected $module_categories = array();
  41  
  42      /**
  43      * Constructor
  44      *
  45      * @param \phpbb\db\driver\driver_interface $db
  46      * @param \phpbb\cache\service $cache
  47      * @param \phpbb\user $user
  48      * @param string $phpbb_root_path
  49      * @param string $php_ext
  50      * @param string $modules_table
  51      */
  52  	public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\user $user, $phpbb_root_path, $php_ext, $modules_table)
  53      {
  54          $this->db = $db;
  55          $this->cache = $cache;
  56          $this->user = $user;
  57          $this->phpbb_root_path = $phpbb_root_path;
  58          $this->php_ext = $php_ext;
  59          $this->modules_table = $modules_table;
  60      }
  61  
  62      /**
  63      * {@inheritdoc}
  64      */
  65  	public function get_name()
  66      {
  67          return 'module';
  68      }
  69  
  70      /**
  71      * Module Exists
  72      *
  73      * Check if a module exists
  74      *
  75      * @param string $class The module class(acp|mcp|ucp)
  76      * @param int|string|bool $parent The parent module_id|module_langname (0 for no parent).
  77      *        Use false to ignore the parent check and check class wide.
  78      * @param int|string $module The module_id|module_langname you would like to
  79      *         check for to see if it exists
  80      * @return bool true/false if module exists
  81      */
  82  	public function exists($class, $parent, $module)
  83      {
  84          // the main root directory should return true
  85          if (!$module)
  86          {
  87              return true;
  88          }
  89  
  90          $parent_sql = '';
  91          if ($parent !== false)
  92          {
  93              $parent = $this->get_parent_module_id($parent, $module, false);
  94              if ($parent === false)
  95              {
  96                  return false;
  97              }
  98  
  99              $parent_sql = 'AND parent_id = ' . (int) $parent;
 100          }
 101  
 102          $sql = 'SELECT module_id
 103              FROM ' . $this->modules_table . "
 104              WHERE module_class = '" . $this->db->sql_escape($class) . "'
 105                  $parent_sql
 106                  AND " . ((is_numeric($module)) ? 'module_id = ' . (int) $module : "module_langname = '" . $this->db->sql_escape($module) . "'");
 107          $result = $this->db->sql_query($sql);
 108          $module_id = $this->db->sql_fetchfield('module_id');
 109          $this->db->sql_freeresult($result);
 110  
 111          if ($module_id)
 112          {
 113              return true;
 114          }
 115  
 116          return false;
 117      }
 118  
 119      /**
 120      * Module Add
 121      *
 122      * Add a new module
 123      *
 124      * @param string $class The module class(acp|mcp|ucp)
 125      * @param int|string $parent The parent module_id|module_langname (0 for no parent)
 126      * @param array $data an array of the data on the new \module.
 127      *     This can be setup in two different ways.
 128      *    1. The "manual" way.  For inserting a category or one at a time.
 129      *        It will be merged with the base array shown a bit below,
 130      *            but at the least requires 'module_langname' to be sent, and,
 131      *            if you want to create a module (instead of just a category) you must
 132      *            send module_basename and module_mode.
 133      *        array(
 134      *            'module_enabled'    => 1,
 135      *            'module_display'    => 1,
 136      *               'module_basename'    => '',
 137      *            'module_class'        => $class,
 138      *               'parent_id'            => (int) $parent,
 139      *            'module_langname'    => '',
 140      *               'module_mode'        => '',
 141      *               'module_auth'        => '',
 142      *        )
 143      *    2. The "automatic" way.  For inserting multiple at a time based on the
 144      *            specs in the info file for the module(s).  For this to work the
 145      *            modules must be correctly setup in the info file.
 146      *        An example follows (this would insert the settings, log, and flag
 147      *            modes from the includes/acp/info/acp_asacp.php file):
 148      *         array(
 149      *             'module_basename'    => 'asacp',
 150      *             'modes'                => array('settings', 'log', 'flag'),
 151      *         )
 152      *         Optionally you may not send 'modes' and it will insert all of the
 153      *             modules in that info file.
 154      *     path, specify that here
 155      * @return null
 156      * @throws \phpbb\db\migration\exception
 157      */
 158  	public function add($class, $parent = 0, $data = array())
 159      {
 160          // allow sending the name as a string in $data to create a category
 161          if (!is_array($data))
 162          {
 163              $data = array('module_langname' => $data);
 164          }
 165  
 166          $parent = $data['parent_id'] = $this->get_parent_module_id($parent, $data);
 167  
 168          if (!isset($data['module_langname']))
 169          {
 170              // The "automatic" way
 171              $basename = (isset($data['module_basename'])) ? $data['module_basename'] : '';
 172              $module = $this->get_module_info($class, $basename);
 173  
 174              $result = '';
 175              foreach ($module['modes'] as $mode => $module_info)
 176              {
 177                  if (!isset($data['modes']) || in_array($mode, $data['modes']))
 178                  {
 179                      $new_module = array(
 180                          'module_basename'    => $basename,
 181                          'module_langname'    => $module_info['title'],
 182                          'module_mode'        => $mode,
 183                          'module_auth'        => $module_info['auth'],
 184                          'module_display'    => (isset($module_info['display'])) ? $module_info['display'] : true,
 185                          'before'            => (isset($module_info['before'])) ? $module_info['before'] : false,
 186                          'after'                => (isset($module_info['after'])) ? $module_info['after'] : false,
 187                      );
 188  
 189                      // Run the "manual" way with the data we've collected.
 190                      $this->add($class, $parent, $new_module);
 191                  }
 192              }
 193  
 194              return;
 195          }
 196  
 197          // The "manual" way
 198          if (!$this->exists($class, false, $parent))
 199          {
 200              throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent);
 201          }
 202  
 203          if ($this->exists($class, $parent, $data['module_langname']))
 204          {
 205              throw new \phpbb\db\migration\exception('MODULE_EXISTS', $data['module_langname']);
 206          }
 207  
 208          if (!class_exists('acp_modules'))
 209          {
 210              include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext);
 211              $this->user->add_lang('acp/modules');
 212          }
 213          $acp_modules = new \acp_modules();
 214  
 215          $module_data = array(
 216              'module_enabled'    => (isset($data['module_enabled'])) ? $data['module_enabled'] : 1,
 217              'module_display'    => (isset($data['module_display'])) ? $data['module_display'] : 1,
 218              'module_basename'    => (isset($data['module_basename'])) ? $data['module_basename'] : '',
 219              'module_class'        => $class,
 220              'parent_id'            => (int) $parent,
 221              'module_langname'    => (isset($data['module_langname'])) ? $data['module_langname'] : '',
 222              'module_mode'        => (isset($data['module_mode'])) ? $data['module_mode'] : '',
 223              'module_auth'        => (isset($data['module_auth'])) ? $data['module_auth'] : '',
 224          );
 225          $result = $acp_modules->update_module_data($module_data, true);
 226  
 227          // update_module_data can either return a string or an empty array...
 228          if (is_string($result))
 229          {
 230              // Error
 231              throw new \phpbb\db\migration\exception('MODULE_ERROR', $result);
 232          }
 233          else
 234          {
 235              // Success
 236              $module_log_name = ((isset($this->user->lang[$data['module_langname']])) ? $this->user->lang[$data['module_langname']] : $data['module_langname']);
 237              add_log('admin', 'LOG_MODULE_ADD', $module_log_name);
 238  
 239              // Move the module if requested above/below an existing one
 240              if (isset($data['before']) && $data['before'])
 241              {
 242                  $sql = 'SELECT left_id
 243                      FROM ' . $this->modules_table . "
 244                      WHERE module_class = '" . $this->db->sql_escape($class) . "'
 245                          AND parent_id = " . (int) $parent . "
 246                          AND module_langname = '" . $this->db->sql_escape($data['before']) . "'";
 247                  $this->db->sql_query($sql);
 248                  $to_left = (int) $this->db->sql_fetchfield('left_id');
 249  
 250                  $sql = 'UPDATE ' . $this->modules_table . "
 251                      SET left_id = left_id + 2, right_id = right_id + 2
 252                      WHERE module_class = '" . $this->db->sql_escape($class) . "'
 253                          AND left_id >= $to_left
 254                          AND left_id < {$module_data['left_id']}";
 255                  $this->db->sql_query($sql);
 256  
 257                  $sql = 'UPDATE ' . $this->modules_table . "
 258                      SET left_id = $to_left, right_id = " . ($to_left + 1) . "
 259                      WHERE module_class = '" . $this->db->sql_escape($class) . "'
 260                          AND module_id = {$module_data['module_id']}";
 261                  $this->db->sql_query($sql);
 262              }
 263              else if (isset($data['after']) && $data['after'])
 264              {
 265                  $sql = 'SELECT right_id
 266                      FROM ' . $this->modules_table . "
 267                      WHERE module_class = '" . $this->db->sql_escape($class) . "'
 268                          AND parent_id = " . (int) $parent . "
 269                          AND module_langname = '" . $this->db->sql_escape($data['after']) . "'";
 270                  $this->db->sql_query($sql);
 271                  $to_right = (int) $this->db->sql_fetchfield('right_id');
 272  
 273                  $sql = 'UPDATE ' . $this->modules_table . "
 274                      SET left_id = left_id + 2, right_id = right_id + 2
 275                      WHERE module_class = '" . $this->db->sql_escape($class) . "'
 276                          AND left_id >= $to_right
 277                          AND left_id < {$module_data['left_id']}";
 278                  $this->db->sql_query($sql);
 279  
 280                  $sql = 'UPDATE ' . $this->modules_table . '
 281                      SET left_id = ' . ($to_right + 1) . ', right_id = ' . ($to_right + 2) . "
 282                      WHERE module_class = '" . $this->db->sql_escape($class) . "'
 283                          AND module_id = {$module_data['module_id']}";
 284                  $this->db->sql_query($sql);
 285              }
 286          }
 287  
 288          // Clear the Modules Cache
 289          $this->cache->destroy("_modules_$class");
 290      }
 291  
 292      /**
 293      * Module Remove
 294      *
 295      * Remove a module
 296      *
 297      * @param string $class The module class(acp|mcp|ucp)
 298      * @param int|string|bool $parent The parent module_id|module_langname(0 for no parent).
 299      *     Use false to ignore the parent check and check class wide.
 300      * @param int|string $module The module id|module_langname
 301      *     specify that here
 302      * @return null
 303      * @throws \phpbb\db\migration\exception
 304      */
 305  	public function remove($class, $parent = 0, $module = '')
 306      {
 307          // Imitation of module_add's "automatic" and "manual" method so the uninstaller works from the same set of instructions for umil_auto
 308          if (is_array($module))
 309          {
 310              if (isset($module['module_langname']))
 311              {
 312                  // Manual Method
 313                  return $this->remove($class, $parent, $module['module_langname']);
 314              }
 315  
 316              // Failed.
 317              if (!isset($module['module_basename']))
 318              {
 319                  throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST');
 320              }
 321  
 322              // Automatic method
 323              $basename = $module['module_basename'];
 324              $module_info = $this->get_module_info($class, $basename);
 325  
 326              foreach ($module_info['modes'] as $mode => $info)
 327              {
 328                  if (!isset($module['modes']) || in_array($mode, $module['modes']))
 329                  {
 330                      $this->remove($class, $parent, $info['title']);
 331                  }
 332              }
 333          }
 334          else
 335          {
 336              if (!$this->exists($class, $parent, $module))
 337              {
 338                  return;
 339              }
 340  
 341              $parent_sql = '';
 342              if ($parent !== false)
 343              {
 344                  $parent = $this->get_parent_module_id($parent, $module);
 345                  $parent_sql = 'AND parent_id = ' . (int) $parent;
 346              }
 347  
 348              $module_ids = array();
 349              if (!is_numeric($module))
 350              {
 351                  $sql = 'SELECT module_id
 352                      FROM ' . $this->modules_table . "
 353                      WHERE module_langname = '" . $this->db->sql_escape($module) . "'
 354                          AND module_class = '" . $this->db->sql_escape($class) . "'
 355                          $parent_sql";
 356                  $result = $this->db->sql_query($sql);
 357                  while ($module_id = $this->db->sql_fetchfield('module_id'))
 358                  {
 359                      $module_ids[] = (int) $module_id;
 360                  }
 361                  $this->db->sql_freeresult($result);
 362              }
 363              else
 364              {
 365                  $module_ids[] = (int) $module;
 366              }
 367  
 368              if (!class_exists('acp_modules'))
 369              {
 370                  include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext);
 371                  $this->user->add_lang('acp/modules');
 372              }
 373              $acp_modules = new \acp_modules();
 374              $acp_modules->module_class = $class;
 375  
 376              foreach ($module_ids as $module_id)
 377              {
 378                  $result = $acp_modules->delete_module($module_id);
 379                  if (!empty($result))
 380                  {
 381                      return;
 382                  }
 383              }
 384  
 385              $this->cache->destroy("_modules_$class");
 386          }
 387      }
 388  
 389      /**
 390      * {@inheritdoc}
 391      */
 392  	public function reverse()
 393      {
 394          $arguments = func_get_args();
 395          $original_call = array_shift($arguments);
 396  
 397          $call = false;
 398          switch ($original_call)
 399          {
 400              case 'add':
 401                  $call = 'remove';
 402              break;
 403  
 404              case 'remove':
 405                  $call = 'add';
 406              break;
 407  
 408              case 'reverse':
 409                  // Reversing a reverse is just the call itself
 410                  $call = array_shift($arguments);
 411              break;
 412          }
 413  
 414          if ($call)
 415          {
 416              return call_user_func_array(array(&$this, $call), $arguments);
 417          }
 418      }
 419  
 420      /**
 421      * Wrapper for \acp_modules::get_module_infos()
 422      *
 423      * @param string $class Module Class
 424      * @param string $basename Module Basename
 425      * @return array Module Information
 426      * @throws \phpbb\db\migration\exception
 427      */
 428  	protected function get_module_info($class, $basename)
 429      {
 430          if (!class_exists('acp_modules'))
 431          {
 432              include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext);
 433              $this->user->add_lang('acp/modules');
 434          }
 435          $acp_modules = new \acp_modules();
 436          $module = $acp_modules->get_module_infos($basename, $class, true);
 437  
 438          if (empty($module))
 439          {
 440              throw new \phpbb\db\migration\exception('MODULE_INFO_FILE_NOT_EXIST', $class, $basename);
 441          }
 442  
 443          return array_pop($module);
 444      }
 445  
 446      /**
 447      * Get the list of installed module categories
 448      *    key - module_id
 449      *    value - module_langname
 450      *
 451      * @return null
 452      */
 453  	protected function get_categories_list()
 454      {
 455          // Select the top level categories
 456          // and 2nd level [sub]categories
 457          $sql = 'SELECT m2.module_id, m2.module_langname
 458              FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2
 459              WHERE m1.parent_id = 0
 460                  AND (m1.module_id = m2.module_id OR m2.parent_id = m1.module_id)
 461              ORDER BY m1.module_id, m2.module_id ASC";
 462  
 463          $result = $this->db->sql_query($sql);
 464          while ($row = $this->db->sql_fetchrow($result))
 465          {
 466              $this->module_categories[(int) $row['module_id']] = $row['module_langname'];
 467          }
 468          $this->db->sql_freeresult($result);
 469      }
 470  
 471      /**
 472      * Get parent module id
 473      *
 474      * @param string|int $parent_id The parent module_id|module_langname
 475      * @param int|string|array $data The module_id, module_langname for existance checking or module data array for adding
 476      * @param bool $throw_exception The flag indicating if exception should be thrown on error
 477      * @return mixed The int parent module_id or false
 478      * @throws \phpbb\db\migration\exception
 479      */
 480  	public function get_parent_module_id($parent_id, $data = '', $throw_exception = true)
 481      {
 482          // Initialize exception object placeholder
 483          $exception = false;
 484  
 485          // Allow '' to be sent as 0
 486          $parent_id = $parent_id ?: 0;
 487  
 488          // If automatic adding is in action, convert array back to string to simplify things
 489          if (is_array($data) && sizeof($data) == 1)
 490          {
 491              $data = $data['module_langname'];
 492          }
 493  
 494          if (!is_numeric($parent_id))
 495          {
 496              // Refresh the $module_categories array
 497              $this->get_categories_list();
 498  
 499              // Search for the parent module_langname
 500              $ids = array_keys($this->module_categories, $parent_id);
 501  
 502              switch (sizeof($ids))
 503              {
 504                  // No parent with the given module_langname exist
 505                  case 0:
 506                      $exception = new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent_id);
 507                  break;
 508  
 509                  // Return the module id
 510                  case 1:
 511                      $parent_id = (int) $ids[0];
 512                  break;
 513  
 514                  // Several modules with the given module_langname were found
 515                  // Try to determine the parent_id by the neighbour module parent
 516                  default:
 517                      if (is_array($data) && (isset($data['before']) || isset($data['after'])))
 518                      {
 519                          $neighbour_module_langname = isset($data['before']) ? $data['before'] : $data['after'];
 520                          $sql = 'SELECT parent_id
 521                              FROM ' . $this->modules_table . "
 522                              WHERE module_langname = '" . $this->db->sql_escape($neighbour_module_langname) . "'
 523                                  AND " . $this->db->sql_in_set('parent_id', $ids);
 524                          $result = $this->db->sql_query($sql);
 525                          $parent_id = (int) $this->db->sql_fetchfield('parent_id');
 526                          if (!$parent_id)
 527                          {
 528                              $exception = new \phpbb\db\migration\exception('PARENT_MODULE_FIND_ERROR', $data['parent_id']);
 529                          }
 530                      }
 531                      else if (!empty($data) && !is_array($data))
 532                      {
 533                          // The module_langname is set, checking for the module existance
 534                          // As more than 1 parents were found already, there's no way for null parent_id here
 535                          $sql = 'SELECT m2.module_id as module_parent_id
 536                              FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2
 537                              WHERE " . ((is_numeric($data)) ? 'm1.module_id = ' . (int) $data : "m1.module_langname = '" . $this->db->sql_escape($data)) . "'
 538                                  AND m2.module_id = m1.parent_id
 539                                  AND " . $this->db->sql_in_set('m2.module_id', $ids);
 540                          $result = $this->db->sql_query($sql);
 541                          $parent_id = (int) $this->db->sql_fetchfield('module_parent_id');
 542                      }
 543                      else
 544                      {
 545                          //Unable to get the parent module id, throwing an exception
 546                          $exception = new \phpbb\db\migration\exception('MODULE_EXIST_MULTIPLE', $parent_id);
 547                      }
 548                  break;
 549              }
 550          }
 551  
 552          if ($exception !== false)
 553          {
 554              if ($throw_exception)
 555              {
 556                  throw $exception;
 557              }
 558              return false;
 559          }
 560  
 561          return $parent_id;
 562      }
 563  }


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1