[ Index ] |
PHP Cross Reference of phpBB-3.1.12-deutsch |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Jan 11 00:25:41 2018 | Cross-referenced by PHPXref 0.7.1 |