Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
module.php
001 <?php
002 /**
003 *
004 * This file is part of the phpBB Forum Software package.
005 *
006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
007 * @license GNU General Public License, version 2 (GPL-2.0)
008 *
009 * For full copyright and license information, please see
010 * the docs/CREDITS.txt file.
011 *
012 */
013
014 namespace phpbb\db\migration\tool;
015
016 use phpbb\module\exception\module_exception;
017
018 /**
019 * Migration module management tool
020 */
021 class module implements \phpbb\db\migration\tool\tool_interface
022 {
023 /** @var \phpbb\cache\service */
024 protected $cache;
025
026 /** @var \phpbb\db\driver\driver_interface */
027 protected $db;
028
029 /** @var \phpbb\user */
030 protected $user;
031
032 /** @var \phpbb\module\module_manager */
033 protected $module_manager;
034
035 /** @var string */
036 protected $phpbb_root_path;
037
038 /** @var string */
039 protected $php_ext;
040
041 /** @var string */
042 protected $modules_table;
043
044 /** @var array */
045 protected $module_categories = array();
046
047 /**
048 * Constructor
049 *
050 * @param \phpbb\db\driver\driver_interface $db
051 * @param \phpbb\cache\service $cache
052 * @param \phpbb\user $user
053 * @param \phpbb\module\module_manager $module_manager
054 * @param string $phpbb_root_path
055 * @param string $php_ext
056 * @param string $modules_table
057 */
058 public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\user $user, \phpbb\module\module_manager $module_manager, $phpbb_root_path, $php_ext, $modules_table)
059 {
060 $this->db = $db;
061 $this->cache = $cache;
062 $this->user = $user;
063 $this->module_manager = $module_manager;
064 $this->phpbb_root_path = $phpbb_root_path;
065 $this->php_ext = $php_ext;
066 $this->modules_table = $modules_table;
067 }
068
069 /**
070 * {@inheritdoc}
071 */
072 public function get_name()
073 {
074 return 'module';
075 }
076
077 /**
078 * Module Exists
079 *
080 * Check if a module exists
081 *
082 * @param string $class The module class(acp|mcp|ucp)
083 * @param int|string|bool $parent The parent module_id|module_langname (0 for no parent).
084 * Use false to ignore the parent check and check class wide.
085 * @param int|string $module The module_id|module_langname you would like to
086 * check for to see if it exists
087 * @return bool true/false if module exists
088 */
089 public function exists($class, $parent, $module)
090 {
091 // the main root directory should return true
092 if (!$module)
093 {
094 return true;
095 }
096
097 $parent_sql = '';
098 if ($parent !== false)
099 {
100 $parent = $this->get_parent_module_id($parent, $module, false);
101 if ($parent === false)
102 {
103 return false;
104 }
105
106 $parent_sql = 'AND parent_id = ' . (int) $parent;
107 }
108
109 $sql = 'SELECT module_id
110 FROM ' . $this->modules_table . "
111 WHERE module_class = '" . $this->db->sql_escape($class) . "'
112 $parent_sql
113 AND " . ((is_numeric($module)) ? 'module_id = ' . (int) $module : "module_langname = '" . $this->db->sql_escape($module) . "'");
114 $result = $this->db->sql_query($sql);
115 $module_id = $this->db->sql_fetchfield('module_id');
116 $this->db->sql_freeresult($result);
117
118 if ($module_id)
119 {
120 return true;
121 }
122
123 return false;
124 }
125
126 /**
127 * Module Add
128 *
129 * Add a new module
130 *
131 * @param string $class The module class(acp|mcp|ucp)
132 * @param int|string $parent The parent module_id|module_langname (0 for no parent)
133 * @param array $data an array of the data on the new \module.
134 * This can be setup in two different ways.
135 * 1. The "manual" way. For inserting a category or one at a time.
136 * It will be merged with the base array shown a bit below,
137 * but at the least requires 'module_langname' to be sent, and,
138 * if you want to create a module (instead of just a category) you must
139 * send module_basename and module_mode.
140 * array(
141 * 'module_enabled' => 1,
142 * 'module_display' => 1,
143 * 'module_basename' => '',
144 * 'module_class' => $class,
145 * 'parent_id' => (int) $parent,
146 * 'module_langname' => '',
147 * 'module_mode' => '',
148 * 'module_auth' => '',
149 * )
150 * 2. The "automatic" way. For inserting multiple at a time based on the
151 * specs in the info file for the module(s). For this to work the
152 * modules must be correctly setup in the info file.
153 * An example follows (this would insert the settings, log, and flag
154 * modes from the includes/acp/info/acp_asacp.php file):
155 * array(
156 * 'module_basename' => 'asacp',
157 * 'modes' => array('settings', 'log', 'flag'),
158 * )
159 * Optionally you may not send 'modes' and it will insert all of the
160 * modules in that info file.
161 * path, specify that here
162 * @return null
163 * @throws \phpbb\db\migration\exception
164 */
165 public function add($class, $parent = 0, $data = array())
166 {
167 global $user, $phpbb_log;
168
169 // allow sending the name as a string in $data to create a category
170 if (!is_array($data))
171 {
172 $data = array('module_langname' => $data);
173 }
174
175 $parent = $data['parent_id'] = $this->get_parent_module_id($parent, $data);
176
177 if (!isset($data['module_langname']))
178 {
179 // The "automatic" way
180 $basename = (isset($data['module_basename'])) ? $data['module_basename'] : '';
181 $module = $this->get_module_info($class, $basename);
182
183 foreach ($module['modes'] as $mode => $module_info)
184 {
185 if (!isset($data['modes']) || in_array($mode, $data['modes']))
186 {
187 $new_module = array(
188 'module_basename' => $basename,
189 'module_langname' => $module_info['title'],
190 'module_mode' => $mode,
191 'module_auth' => $module_info['auth'],
192 'module_display' => (isset($module_info['display'])) ? $module_info['display'] : true,
193 'before' => (isset($module_info['before'])) ? $module_info['before'] : false,
194 'after' => (isset($module_info['after'])) ? $module_info['after'] : false,
195 );
196
197 // Run the "manual" way with the data we've collected.
198 $this->add($class, $parent, $new_module);
199 }
200 }
201
202 return;
203 }
204
205 // The "manual" way
206 if (!$this->exists($class, false, $parent))
207 {
208 throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent);
209 }
210
211 if ($this->exists($class, $parent, $data['module_langname']))
212 {
213 throw new \phpbb\db\migration\exception('MODULE_EXISTS', $data['module_langname']);
214 }
215
216 $module_data = array(
217 'module_enabled' => (isset($data['module_enabled'])) ? $data['module_enabled'] : 1,
218 'module_display' => (isset($data['module_display'])) ? $data['module_display'] : 1,
219 'module_basename' => (isset($data['module_basename'])) ? $data['module_basename'] : '',
220 'module_class' => $class,
221 'parent_id' => (int) $parent,
222 'module_langname' => (isset($data['module_langname'])) ? $data['module_langname'] : '',
223 'module_mode' => (isset($data['module_mode'])) ? $data['module_mode'] : '',
224 'module_auth' => (isset($data['module_auth'])) ? $data['module_auth'] : '',
225 );
226
227 try
228 {
229 $this->module_manager->update_module_data($module_data);
230
231 // Success
232 $module_log_name = ((isset($this->user->lang[$data['module_langname']])) ? $this->user->lang[$data['module_langname']] : $data['module_langname']);
233 $phpbb_log->add('admin', (isset($user->data['user_id'])) ? $user->data['user_id'] : ANONYMOUS, $user->ip, 'LOG_MODULE_ADD', false, array($module_log_name));
234
235 // Move the module if requested above/below an existing one
236 if (isset($data['before']) && $data['before'])
237 {
238 $sql = 'SELECT left_id
239 FROM ' . $this->modules_table . "
240 WHERE module_class = '" . $this->db->sql_escape($class) . "'
241 AND parent_id = " . (int) $parent . "
242 AND module_langname = '" . $this->db->sql_escape($data['before']) . "'";
243 $this->db->sql_query($sql);
244 $to_left = (int) $this->db->sql_fetchfield('left_id');
245
246 $sql = 'UPDATE ' . $this->modules_table . "
247 SET left_id = left_id + 2, right_id = right_id + 2
248 WHERE module_class = '" . $this->db->sql_escape($class) . "'
249 AND left_id >= $to_left
250 AND left_id < {$module_data['left_id']}";
251 $this->db->sql_query($sql);
252
253 $sql = 'UPDATE ' . $this->modules_table . "
254 SET left_id = $to_left, right_id = " . ($to_left + 1) . "
255 WHERE module_class = '" . $this->db->sql_escape($class) . "'
256 AND module_id = {$module_data['module_id']}";
257 $this->db->sql_query($sql);
258 }
259 else if (isset($data['after']) && $data['after'])
260 {
261 $sql = 'SELECT right_id
262 FROM ' . $this->modules_table . "
263 WHERE module_class = '" . $this->db->sql_escape($class) . "'
264 AND parent_id = " . (int) $parent . "
265 AND module_langname = '" . $this->db->sql_escape($data['after']) . "'";
266 $this->db->sql_query($sql);
267 $to_right = (int) $this->db->sql_fetchfield('right_id');
268
269 $sql = 'UPDATE ' . $this->modules_table . "
270 SET left_id = left_id + 2, right_id = right_id + 2
271 WHERE module_class = '" . $this->db->sql_escape($class) . "'
272 AND left_id >= $to_right
273 AND left_id < {$module_data['left_id']}";
274 $this->db->sql_query($sql);
275
276 $sql = 'UPDATE ' . $this->modules_table . '
277 SET left_id = ' . ($to_right + 1) . ', right_id = ' . ($to_right + 2) . "
278 WHERE module_class = '" . $this->db->sql_escape($class) . "'
279 AND module_id = {$module_data['module_id']}";
280 $this->db->sql_query($sql);
281 }
282 }
283 catch (module_exception $e)
284 {
285 // Error
286 throw new \phpbb\db\migration\exception('MODULE_ERROR', $e->getMessage());
287 }
288
289 // Clear the Modules Cache
290 $this->cache->destroy("_modules_$class");
291 }
292
293 /**
294 * Module Remove
295 *
296 * Remove a module
297 *
298 * @param string $class The module class(acp|mcp|ucp)
299 * @param int|string|bool $parent The parent module_id|module_langname(0 for no parent).
300 * Use false to ignore the parent check and check class wide.
301 * @param int|string $module The module id|module_langname
302 * specify that here
303 * @return null
304 * @throws \phpbb\db\migration\exception
305 */
306 public function remove($class, $parent = 0, $module = '')
307 {
308 // Imitation of module_add's "automatic" and "manual" method so the uninstaller works from the same set of instructions for umil_auto
309 if (is_array($module))
310 {
311 if (isset($module['module_langname']))
312 {
313 // Manual Method
314 return $this->remove($class, $parent, $module['module_langname']);
315 }
316
317 // Failed.
318 if (!isset($module['module_basename']))
319 {
320 throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST');
321 }
322
323 // Automatic method
324 $basename = $module['module_basename'];
325 $module_info = $this->get_module_info($class, $basename);
326
327 foreach ($module_info['modes'] as $mode => $info)
328 {
329 if (!isset($module['modes']) || in_array($mode, $module['modes']))
330 {
331 $this->remove($class, $parent, $info['title']);
332 }
333 }
334 }
335 else
336 {
337 if (!$this->exists($class, $parent, $module))
338 {
339 return;
340 }
341
342 $parent_sql = '';
343 if ($parent !== false)
344 {
345 $parent = $this->get_parent_module_id($parent, $module);
346 $parent_sql = 'AND parent_id = ' . (int) $parent;
347 }
348
349 $module_ids = array();
350 if (!is_numeric($module))
351 {
352 $sql = 'SELECT module_id
353 FROM ' . $this->modules_table . "
354 WHERE module_langname = '" . $this->db->sql_escape($module) . "'
355 AND module_class = '" . $this->db->sql_escape($class) . "'
356 $parent_sql";
357 $result = $this->db->sql_query($sql);
358 while ($module_id = $this->db->sql_fetchfield('module_id'))
359 {
360 $module_ids[] = (int) $module_id;
361 }
362 $this->db->sql_freeresult($result);
363 }
364 else
365 {
366 $module_ids[] = (int) $module;
367 }
368
369 foreach ($module_ids as $module_id)
370 {
371 $this->module_manager->delete_module($module_id, $class);
372 }
373
374 $this->cache->destroy("_modules_$class");
375 }
376 }
377
378 /**
379 * {@inheritdoc}
380 */
381 public function reverse()
382 {
383 $arguments = func_get_args();
384 $original_call = array_shift($arguments);
385
386 $call = false;
387 switch ($original_call)
388 {
389 case 'add':
390 $call = 'remove';
391 break;
392
393 case 'remove':
394 $call = 'add';
395 break;
396
397 case 'reverse':
398 // Reversing a reverse is just the call itself
399 $call = array_shift($arguments);
400 break;
401 }
402
403 if ($call)
404 {
405 return call_user_func_array(array(&$this, $call), $arguments);
406 }
407 }
408
409 /**
410 * Wrapper for \acp_modules::get_module_infos()
411 *
412 * @param string $class Module Class
413 * @param string $basename Module Basename
414 * @return array Module Information
415 * @throws \phpbb\db\migration\exception
416 */
417 protected function get_module_info($class, $basename)
418 {
419 $module = $this->module_manager->get_module_infos($class, $basename, true);
420
421 if (empty($module))
422 {
423 throw new \phpbb\db\migration\exception('MODULE_INFO_FILE_NOT_EXIST', $class, $basename);
424 }
425
426 return array_pop($module);
427 }
428
429 /**
430 * Get the list of installed module categories
431 * key - module_id
432 * value - module_langname
433 *
434 * @return null
435 */
436 protected function get_categories_list()
437 {
438 // Select the top level categories
439 // and 2nd level [sub]categories
440 $sql = 'SELECT m2.module_id, m2.module_langname
441 FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2
442 WHERE m1.parent_id = 0
443 AND (m1.module_id = m2.module_id OR m2.parent_id = m1.module_id)
444 ORDER BY m1.module_id, m2.module_id ASC";
445
446 $result = $this->db->sql_query($sql);
447 while ($row = $this->db->sql_fetchrow($result))
448 {
449 $this->module_categories[(int) $row['module_id']] = $row['module_langname'];
450 }
451 $this->db->sql_freeresult($result);
452 }
453
454 /**
455 * Get parent module id
456 *
457 * @param string|int $parent_id The parent module_id|module_langname
458 * @param int|string|array $data The module_id, module_langname for existance checking or module data array for adding
459 * @param bool $throw_exception The flag indicating if exception should be thrown on error
460 * @return mixed The int parent module_id or false
461 * @throws \phpbb\db\migration\exception
462 */
463 public function get_parent_module_id($parent_id, $data = '', $throw_exception = true)
464 {
465 // Initialize exception object placeholder
466 $exception = false;
467
468 // Allow '' to be sent as 0
469 $parent_id = $parent_id ?: 0;
470
471 // If automatic adding is in action, convert array back to string to simplify things
472 if (is_array($data) && sizeof($data) == 1)
473 {
474 $data = $data['module_langname'];
475 }
476
477 if (!is_numeric($parent_id))
478 {
479 // Refresh the $module_categories array
480 $this->get_categories_list();
481
482 // Search for the parent module_langname
483 $ids = array_keys($this->module_categories, $parent_id);
484
485 switch (sizeof($ids))
486 {
487 // No parent with the given module_langname exist
488 case 0:
489 $exception = new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent_id);
490 break;
491
492 // Return the module id
493 case 1:
494 $parent_id = (int) $ids[0];
495 break;
496
497 // Several modules with the given module_langname were found
498 // Try to determine the parent_id by the neighbour module parent
499 default:
500 if (is_array($data) && (isset($data['before']) || isset($data['after'])))
501 {
502 $neighbour_module_langname = isset($data['before']) ? $data['before'] : $data['after'];
503 $sql = 'SELECT parent_id
504 FROM ' . $this->modules_table . "
505 WHERE module_langname = '" . $this->db->sql_escape($neighbour_module_langname) . "'
506 AND " . $this->db->sql_in_set('parent_id', $ids);
507 $result = $this->db->sql_query($sql);
508 $parent_id = (int) $this->db->sql_fetchfield('parent_id');
509 if (!$parent_id)
510 {
511 $exception = new \phpbb\db\migration\exception('PARENT_MODULE_FIND_ERROR', $data['parent_id']);
512 }
513 }
514 else if (!empty($data) && !is_array($data))
515 {
516 // The module_langname is set, checking for the module existance
517 // As more than 1 parents were found already, there's no way for null parent_id here
518 $sql = 'SELECT m2.module_id as module_parent_id
519 FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2
520 WHERE " . ((is_numeric($data)) ? 'm1.module_id = ' . (int) $data : "m1.module_langname = '" . $this->db->sql_escape($data)) . "'
521 AND m2.module_id = m1.parent_id
522 AND " . $this->db->sql_in_set('m2.module_id', $ids);
523 $result = $this->db->sql_query($sql);
524 $parent_id = (int) $this->db->sql_fetchfield('module_parent_id');
525 }
526 else
527 {
528 //Unable to get the parent module id, throwing an exception
529 $exception = new \phpbb\db\migration\exception('MODULE_EXIST_MULTIPLE', $parent_id);
530 }
531 break;
532 }
533 }
534
535 if ($exception !== false)
536 {
537 if ($throw_exception)
538 {
539 throw $exception;
540 }
541 return false;
542 }
543
544 return $parent_id;
545 }
546 }
547