Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 214
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
add_modules
0.00% covered (danger)
0.00%
0 / 214
0.00% covered (danger)
0.00%
0 / 6
1560
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 run
0.00% covered (danger)
0.00%
0 / 103
0.00% covered (danger)
0.00%
0 / 1
812
 order_modules
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 1
20
 add_module_extras
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
20
 get_step_count
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_task_lang_name
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
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
14namespace phpbb\install\module\install_data\task;
15
16use phpbb\install\exception\resource_limit_reached_exception;
17use phpbb\install\helper\config;
18use phpbb\install\helper\container_factory;
19use phpbb\install\helper\iohandler\iohandler_interface;
20
21class add_modules extends \phpbb\install\task_base
22{
23    /**
24     * @var config
25     */
26    protected $config;
27
28    /**
29     * @var \phpbb\db\driver\driver_interface
30     */
31    protected $db;
32
33    /**
34     * @var iohandler_interface
35     */
36    protected $iohandler;
37
38    /**
39     * @var \phpbb\module\module_manager
40     */
41    protected $module_manager;
42
43    /**
44     * Define the module structure so that we can populate the database without
45     * needing to hard-code module_id values
46     *
47     * @var array
48     */
49    protected $module_categories = array(
50        'acp' => array(
51            'ACP_CAT_GENERAL' => array(
52                'ACP_QUICK_ACCESS',
53                'ACP_BOARD_CONFIGURATION',
54                'ACP_CLIENT_COMMUNICATION',
55                'ACP_SERVER_CONFIGURATION',
56            ),
57            'ACP_CAT_FORUMS' => array(
58                'ACP_MANAGE_FORUMS',
59                'ACP_FORUM_BASED_PERMISSIONS',
60            ),
61            'ACP_CAT_POSTING' => array(
62                'ACP_MESSAGES',
63                'ACP_ATTACHMENTS',
64            ),
65            'ACP_CAT_USERGROUP' => array(
66                'ACP_CAT_USERS',
67                'ACP_GROUPS',
68                'ACP_USER_SECURITY',
69            ),
70            'ACP_CAT_PERMISSIONS' => array(
71                'ACP_GLOBAL_PERMISSIONS',
72                'ACP_FORUM_BASED_PERMISSIONS',
73                'ACP_PERMISSION_ROLES',
74                'ACP_PERMISSION_MASKS',
75            ),
76            'ACP_CAT_CUSTOMISE' => array(
77                'ACP_STYLE_MANAGEMENT',
78                'ACP_EXTENSION_MANAGEMENT',
79                'ACP_LANGUAGE',
80            ),
81            'ACP_CAT_MAINTENANCE' => array(
82                'ACP_FORUM_LOGS',
83                'ACP_CAT_DATABASE',
84            ),
85            'ACP_CAT_SYSTEM' => array(
86                'ACP_AUTOMATION',
87                'ACP_GENERAL_TASKS',
88                'ACP_MODULE_MANAGEMENT',
89            ),
90            'ACP_CAT_DOT_MODS' => null,
91        ),
92        'mcp' => array(
93            'MCP_MAIN'        => null,
94            'MCP_QUEUE'        => null,
95            'MCP_REPORTS'    => null,
96            'MCP_NOTES'        => null,
97            'MCP_WARN'        => null,
98            'MCP_LOGS'        => null,
99            'MCP_BAN'        => null,
100        ),
101        'ucp' => array(
102            'UCP_MAIN'            => null,
103            'UCP_PROFILE'        => null,
104            'UCP_PREFS'            => null,
105            'UCP_PM'            => null,
106            'UCP_USERGROUPS'    => null,
107            'UCP_ZEBRA'            => null,
108        ),
109    );
110
111    /**
112     * @var array
113     */
114    protected $module_categories_basenames = array(
115        'UCP_PM' => 'ucp_pm',
116    );
117
118    /**
119     * @var array
120     */
121    protected $module_extras = array(
122        'acp'    => array(
123            'ACP_QUICK_ACCESS' => array(
124                'ACP_MANAGE_USERS',
125                'ACP_GROUPS_MANAGE',
126                'ACP_MANAGE_FORUMS',
127                'ACP_MOD_LOGS',
128                'ACP_BOTS',
129                'ACP_PHP_INFO',
130            ),
131            'ACP_FORUM_BASED_PERMISSIONS' => array(
132                'ACP_FORUM_PERMISSIONS',
133                'ACP_FORUM_PERMISSIONS_COPY',
134                'ACP_FORUM_MODERATORS',
135                'ACP_USERS_FORUM_PERMISSIONS',
136                'ACP_GROUPS_FORUM_PERMISSIONS',
137            ),
138        ),
139    );
140
141    /**
142     * Constructor
143     *
144     * @param config                $config        Installer's config
145     * @param iohandler_interface    $iohandler    Installer's input-output handler
146     * @param container_factory        $container    Installer's DI container
147     */
148    public function __construct(config $config, iohandler_interface $iohandler, container_factory $container)
149    {
150        $this->config                = $config;
151        $this->db                    = $container->get('dbal.conn');
152        $this->iohandler            = $iohandler;
153        $this->module_manager        = $container->get('module.manager');
154
155        parent::__construct(true);
156    }
157
158    /**
159     * {@inheritdoc}
160     */
161    public function run()
162    {
163        $this->db->sql_return_on_error(true);
164
165        $module_classes = array('acp', 'mcp', 'ucp');
166        $total = count($module_classes);
167        $i = $this->config->get('module_class_index', 0);
168        $module_classes = array_slice($module_classes, $i);
169
170        foreach ($module_classes as $module_class)
171        {
172            $categories = $this->config->get('module_categories_array', array());
173
174            $k = $this->config->get('module_categories_index', 0);
175            $module_categories = array_slice($this->module_categories[$module_class], $k);
176            $timed_out = false;
177
178            foreach ($module_categories as $cat_name => $subs)
179            {
180                // Check if this sub-category has a basename. If it has, use it.
181                $basename = (isset($this->module_categories_basenames[$cat_name])) ? $this->module_categories_basenames[$cat_name] : '';
182
183                $module_data = array(
184                    'module_basename'    => $basename,
185                    'module_enabled'    => 1,
186                    'module_display'    => 1,
187                    'parent_id'            => 0,
188                    'module_class'        => $module_class,
189                    'module_langname'    => $cat_name,
190                    'module_mode'        => '',
191                    'module_auth'        => '',
192                );
193
194                $this->module_manager->update_module_data($module_data);
195
196                // Check for last sql error happened
197                if ($this->db->get_sql_error_triggered())
198                {
199                    $error = $this->db->sql_error($this->db->get_sql_error_sql());
200                    $this->iohandler->add_error_message('INST_ERR_DB', $error['message']);
201                }
202
203                $categories[$cat_name]['id'] = (int) $module_data['module_id'];
204                $categories[$cat_name]['parent_id'] = 0;
205
206                if (is_array($subs))
207                {
208                    foreach ($subs as $level2_name)
209                    {
210                        // Check if this sub-category has a basename. If it has, use it.
211                        $basename = (isset($this->module_categories_basenames[$level2_name])) ? $this->module_categories_basenames[$level2_name] : '';
212
213                        $module_data = array(
214                            'module_basename'    => $basename,
215                            'module_enabled'    => 1,
216                            'module_display'    => 1,
217                            'parent_id'            => (int) $categories[$cat_name]['id'],
218                            'module_class'        => $module_class,
219                            'module_langname'    => $level2_name,
220                            'module_mode'        => '',
221                            'module_auth'        => '',
222                        );
223
224                        $this->module_manager->update_module_data($module_data);
225
226                        // Check for last sql error happened
227                        if ($this->db->get_sql_error_triggered())
228                        {
229                            $error = $this->db->sql_error($this->db->get_sql_error_sql());
230                            $this->iohandler->add_error_message('INST_ERR_DB', $error['message']);
231                        }
232
233                        $categories[$level2_name]['id'] = (int) $module_data['module_id'];
234                        $categories[$level2_name]['parent_id'] = (int) $categories[$cat_name]['id'];
235                    }
236                }
237
238                $k++;
239
240                // Stop execution if resource limit is reached
241                if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0)
242                {
243                    $timed_out = true;
244                    break;
245                }
246            }
247
248            $this->config->set('module_categories_array', $categories);
249            $this->config->set('module_categories_index', $k);
250
251            if ($timed_out)
252            {
253                throw new resource_limit_reached_exception();
254            }
255
256            // Get the modules we want to add... returned sorted by name
257            $module_info = $this->module_manager->get_module_infos($module_class);
258
259            $k = $this->config->get('module_info_index', 0);
260            $module_info = array_slice($module_info, $k);
261
262            foreach ($module_info as $module_basename => $fileinfo)
263            {
264                foreach ($fileinfo['modes'] as $module_mode => $row)
265                {
266                    foreach ($row['cat'] as $cat_name)
267                    {
268                        if (!isset($categories[$cat_name]))
269                        {
270                            continue;
271                        }
272
273                        $module_data = array(
274                            'module_basename'    => $module_basename,
275                            'module_enabled'    => 1,
276                            'module_display'    => (isset($row['display'])) ? (int) $row['display'] : 1,
277                            'parent_id'            => (int) $categories[$cat_name]['id'],
278                            'module_class'        => $module_class,
279                            'module_langname'    => $row['title'],
280                            'module_mode'        => $module_mode,
281                            'module_auth'        => $row['auth'],
282                        );
283
284                        $this->module_manager->update_module_data($module_data);
285
286                        // Check for last sql error happened
287                        if ($this->db->get_sql_error_triggered())
288                        {
289                            $error = $this->db->sql_error($this->db->get_sql_error_sql());
290                            $this->iohandler->add_error_message('INST_ERR_DB', $error['message']);
291                        }
292                    }
293                }
294
295                $k++;
296
297                // Stop execution if resource limit is reached
298                if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0)
299                {
300                    $timed_out = true;
301                    break;
302                }
303            }
304
305            $this->config->set('module_info_index', $k);
306
307            // Stop execution if resource limit is reached
308            if ($timed_out)
309            {
310                throw new resource_limit_reached_exception();
311            }
312
313            // Move some of the modules around since the code above will put them in the wrong place
314            if (!$this->config->get('modules_ordered', false))
315            {
316                $this->order_modules($module_class);
317                $this->config->set('modules_ordered', true);
318
319                // Stop execution if resource limit is reached
320                if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0)
321                {
322                    throw new resource_limit_reached_exception();
323                }
324            }
325
326            // And now for the special ones
327            // (these are modules which appear in multiple categories and thus get added manually
328            // to some for more control)
329            if (isset($this->module_extras[$module_class]))
330            {
331                $this->add_module_extras($module_class);
332            }
333
334            $this->module_manager->remove_cache_file($module_class);
335
336            $i++;
337
338            $this->config->set('module_class_index', $i);
339            $this->config->set('module_categories_index', 0);
340            $this->config->set('module_info_index', 0);
341            $this->config->set('added_extra_modules', false);
342            $this->config->set('modules_ordered', false);
343            $this->config->set('module_categories_array', array());
344
345            // Stop execution if resource limit is reached
346            if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0)
347            {
348                break;
349            }
350        }
351
352        if ($i < $total)
353        {
354            throw new resource_limit_reached_exception();
355        }
356    }
357
358    /**
359     * Move modules to their correct place
360     *
361     * @param string    $module_class
362     */
363    protected function order_modules($module_class)
364    {
365        if ($module_class == 'acp')
366        {
367            // Move main module 4 up...
368            $sql = 'SELECT *
369                FROM ' . MODULES_TABLE . "
370                WHERE module_basename = 'acp_main'
371                    AND module_class = 'acp'
372                    AND module_mode = 'main'";
373            $result = $this->db->sql_query($sql);
374            $row = $this->db->sql_fetchrow($result);
375            $this->db->sql_freeresult($result);
376
377            $this->module_manager->move_module_by($row, 'acp', 'move_up', 4);
378
379            // Move permissions intro screen module 4 up...
380            $sql = 'SELECT *
381                FROM ' . MODULES_TABLE . "
382                WHERE module_basename = 'acp_permissions'
383                    AND module_class = 'acp'
384                    AND module_mode = 'intro'";
385            $result = $this->db->sql_query($sql);
386            $row = $this->db->sql_fetchrow($result);
387            $this->db->sql_freeresult($result);
388
389            $this->module_manager->move_module_by($row, 'acp', 'move_up', 4);
390
391            // Move manage users screen module 5 up...
392            $sql = 'SELECT *
393                FROM ' . MODULES_TABLE . "
394                WHERE module_basename = 'acp_users'
395                    AND module_class = 'acp'
396                    AND module_mode = 'overview'";
397            $result = $this->db->sql_query($sql);
398            $row = $this->db->sql_fetchrow($result);
399            $this->db->sql_freeresult($result);
400
401            $this->module_manager->move_module_by($row, 'acp', 'move_up', 5);
402
403            // Move extension management module 1 up...
404            $sql = 'SELECT *
405                FROM ' . MODULES_TABLE . "
406                WHERE module_langname = 'ACP_EXTENSION_MANAGEMENT'
407                    AND module_class = 'acp'
408                    AND module_mode = ''
409                    AND module_basename = ''";
410            $result = $this->db->sql_query($sql);
411            $row = $this->db->sql_fetchrow($result);
412            $this->db->sql_freeresult($result);
413
414            $this->module_manager->move_module_by($row, 'acp', 'move_up', 1);
415        }
416
417        if ($module_class == 'mcp')
418        {
419            // Move pm report details module 3 down...
420            $sql = 'SELECT *
421                FROM ' . MODULES_TABLE . "
422                WHERE module_basename = 'mcp_pm_reports'
423                    AND module_class = 'mcp'
424                    AND module_mode = 'pm_report_details'";
425            $result = $this->db->sql_query($sql);
426            $row = $this->db->sql_fetchrow($result);
427            $this->db->sql_freeresult($result);
428
429            $this->module_manager->move_module_by($row, 'mcp', 'move_down', 3);
430
431            // Move closed pm reports module 3 down...
432            $sql = 'SELECT *
433                FROM ' . MODULES_TABLE . "
434                WHERE module_basename = 'mcp_pm_reports'
435                    AND module_class = 'mcp'
436                    AND module_mode = 'pm_reports_closed'";
437            $result = $this->db->sql_query($sql);
438            $row = $this->db->sql_fetchrow($result);
439            $this->db->sql_freeresult($result);
440
441            $this->module_manager->move_module_by($row, 'mcp', 'move_down', 3);
442
443            // Move open pm reports module 3 down...
444            $sql = 'SELECT *
445                FROM ' . MODULES_TABLE . "
446                WHERE module_basename = 'mcp_pm_reports'
447                    AND module_class = 'mcp'
448                    AND module_mode = 'pm_reports'";
449            $result = $this->db->sql_query($sql);
450            $row = $this->db->sql_fetchrow($result);
451            $this->db->sql_freeresult($result);
452
453            $this->module_manager->move_module_by($row, 'mcp', 'move_down', 3);
454        }
455
456        if ($module_class == 'ucp')
457        {
458            // Move attachment module 4 down...
459            $sql = 'SELECT *
460                FROM ' . MODULES_TABLE . "
461                WHERE module_basename = 'ucp_attachments'
462                    AND module_class = 'ucp'
463                    AND module_mode = 'attachments'";
464            $result = $this->db->sql_query($sql);
465            $row = $this->db->sql_fetchrow($result);
466            $this->db->sql_freeresult($result);
467
468            $this->module_manager->move_module_by($row, 'ucp', 'move_down', 4);
469
470            // Move notification options module 4 down...
471            $sql = 'SELECT *
472                FROM ' . MODULES_TABLE . "
473                WHERE module_basename = 'ucp_notifications'
474                    AND module_class = 'ucp'
475                    AND module_mode = 'notification_options'";
476            $result = $this->db->sql_query($sql);
477            $row = $this->db->sql_fetchrow($result);
478            $this->db->sql_freeresult($result);
479
480            $this->module_manager->move_module_by($row, 'ucp', 'move_down', 4);
481
482            // Move OAuth module 5 down...
483            $sql = 'SELECT *
484                FROM ' . MODULES_TABLE . "
485                WHERE module_basename = 'ucp_auth_link'
486                    AND module_class = 'ucp'
487                    AND module_mode = 'auth_link'";
488            $result = $this->db->sql_query($sql);
489            $row = $this->db->sql_fetchrow($result);
490            $this->db->sql_freeresult($result);
491
492            $this->module_manager->move_module_by($row, 'ucp', 'move_down', 5);
493        }
494    }
495
496    /**
497     * Add extra modules
498     *
499     * @param string    $module_class
500     */
501    protected function add_module_extras($module_class)
502    {
503        foreach ($this->module_extras[$module_class] as $cat_name => $mods)
504        {
505            $sql = 'SELECT module_id, left_id, right_id
506                FROM ' . MODULES_TABLE . "
507                WHERE module_langname = '" . $this->db->sql_escape($cat_name) . "'
508                    AND module_class = '" . $this->db->sql_escape($module_class) . "'";
509            $result = $this->db->sql_query_limit($sql, 1);
510            $row2 = $this->db->sql_fetchrow($result);
511            $this->db->sql_freeresult($result);
512
513            foreach ($mods as $mod_name)
514            {
515                $sql = 'SELECT *
516                    FROM ' . MODULES_TABLE . "
517                    WHERE module_langname = '" . $this->db->sql_escape($mod_name) . "'
518                        AND module_class = '" . $this->db->sql_escape($module_class) . "'
519                        AND module_basename <> ''";
520                $result = $this->db->sql_query_limit($sql, 1);
521                $row = $this->db->sql_fetchrow($result);
522                $this->db->sql_freeresult($result);
523
524                $module_data = array(
525                    'module_basename'    => $row['module_basename'],
526                    'module_enabled'    => (int) $row['module_enabled'],
527                    'module_display'    => (int) $row['module_display'],
528                    'parent_id'            => (int) $row2['module_id'],
529                    'module_class'        => $row['module_class'],
530                    'module_langname'    => $row['module_langname'],
531                    'module_mode'        => $row['module_mode'],
532                    'module_auth'        => $row['module_auth'],
533                );
534
535                $this->module_manager->update_module_data($module_data);
536
537                // Check for last sql error happened
538                if ($this->db->get_sql_error_triggered())
539                {
540                    $error = $this->db->sql_error($this->db->get_sql_error_sql());
541                    $this->iohandler->add_error_message('INST_ERR_DB', $error['message']);
542                }
543            }
544        }
545    }
546
547    /**
548     * {@inheritdoc}
549     */
550    public static function get_step_count()
551    {
552        return 1;
553    }
554
555    /**
556     * {@inheritdoc}
557     */
558    public function get_task_lang_name()
559    {
560        return 'TASK_ADD_MODULES';
561    }
562}