Skip to content

Commit 6362c41

Browse files
authored
fix(system-menus): create and seed menu tables during fresh install (#8)
Create `menuscategory` and `menusitems` during fresh install and seed the default protected menu categories, items, and permissions from shared definitions. Keep the System module update path as the idempotent upgrade path, align menu table signedness between install and upgrade flows, and fail fast when install menu seeding cannot complete successfully. Fresh installs intentionally omit the menu foreign key from installer SQL because `SqlUtility::prefixQuery()` does not rewrite `REFERENCES ...` targets inside `CREATE TABLE` bodies. The runtime System module update path adds and restores that FK with properly prefixed table names. Install-time FK parity is tracked separately in #9.
1 parent e1bd16b commit 6362c41

8 files changed

Lines changed: 709 additions & 142 deletions

File tree

htdocs/install/include/makedata.php

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
// TODO: Shouldn't we insert specific field names?? That way we can use
3131
// the defaults specified in the database...!!!! (and don't have problem
3232
// of missing fields in install file, when add new fields to database)
33+
34+
require_once XOOPS_ROOT_PATH . '/modules/system/include/menu_seed.php';
35+
3336
function make_groups($dbm)
3437
{
3538
$groups['XOOPS_GROUP_ADMIN'] = $dbm->insert('groups', " VALUES (1, '" . addslashes(_INSTALL_WEBMASTER) . "', '" . addslashes(_INSTALL_WEBMASTERD) . "', 'Admin')");
@@ -42,6 +45,103 @@ function make_groups($dbm)
4245
return $groups;
4346
}
4447

48+
/**
49+
* Seed protected front-end menus for a fresh install.
50+
*
51+
* @param Db_manager $dbm
52+
* @param array<string, int> $groups
53+
* @param int $moduleId
54+
*
55+
* @return bool
56+
*/
57+
function system_menu_install_seed_defaults($dbm, array $groups, int $moduleId): bool
58+
{
59+
$seed = system_menu_get_seed_definitions();
60+
$groupMap = [
61+
'admin' => (int) $groups['XOOPS_GROUP_ADMIN'],
62+
'users' => (int) $groups['XOOPS_GROUP_USERS'],
63+
'anonymous' => (int) $groups['XOOPS_GROUP_ANONYMOUS'],
64+
];
65+
$categoryIds = [];
66+
67+
foreach ($seed['categories'] as $key => $definition) {
68+
$categoryId = $dbm->insert(
69+
'menuscategory',
70+
" (`category_title`, `category_prefix`, `category_suffix`, `category_url`, `category_target`, `category_position`, `category_protected`, `category_active`) VALUES ("
71+
. "'" . addslashes($definition['title']) . "', "
72+
. "'" . addslashes($definition['prefix']) . "', "
73+
. "'" . addslashes($definition['suffix']) . "', "
74+
. "'" . addslashes($definition['url']) . "', "
75+
. (int) $definition['target'] . ', '
76+
. (int) $definition['position'] . ', '
77+
. (int) $definition['protected'] . ', '
78+
. (int) $definition['active']
79+
. ')'
80+
);
81+
if (!$categoryId) {
82+
trigger_error(
83+
sprintf('Failed to seed menu category "%s" during install.', $definition['title']),
84+
E_USER_WARNING
85+
);
86+
return false;
87+
}
88+
$categoryIds[$key] = (int) $categoryId;
89+
90+
foreach (system_menu_map_group_keys($definition['group_keys'], $groupMap) as $groupId) {
91+
if (!$dbm->insert(
92+
'group_permission',
93+
' VALUES (0, ' . $groupId . ', ' . (int) $categoryId . ', ' . $moduleId . ", 'menus_category_view')"
94+
)) {
95+
trigger_error(
96+
sprintf('Failed to seed menu category permissions for "%s" during install.', $definition['title']),
97+
E_USER_WARNING
98+
);
99+
return false;
100+
}
101+
}
102+
}
103+
104+
foreach ($seed['items'] as $definition) {
105+
$itemId = $dbm->insert(
106+
'menusitems',
107+
" (`items_pid`, `items_cid`, `items_title`, `items_prefix`, `items_suffix`, `items_url`, `items_target`, `items_position`, `items_protected`, `items_active`) VALUES ("
108+
. (int) $definition['pid'] . ', '
109+
. $categoryIds['account'] . ', '
110+
. "'" . addslashes($definition['title']) . "', "
111+
. "'" . addslashes($definition['prefix']) . "', "
112+
. "'" . addslashes($definition['suffix']) . "', "
113+
. "'" . addslashes($definition['url']) . "', "
114+
. (int) $definition['target'] . ', '
115+
. (int) $definition['position'] . ', '
116+
. (int) $definition['protected'] . ', '
117+
. (int) $definition['active']
118+
. ')'
119+
);
120+
if (!$itemId) {
121+
trigger_error(
122+
sprintf('Failed to seed menu item "%s" during install.', $definition['title']),
123+
E_USER_WARNING
124+
);
125+
return false;
126+
}
127+
128+
foreach (system_menu_map_group_keys($definition['group_keys'], $groupMap) as $groupId) {
129+
if (!$dbm->insert(
130+
'group_permission',
131+
' VALUES (0, ' . $groupId . ', ' . (int) $itemId . ', ' . $moduleId . ", 'menus_items_view')"
132+
)) {
133+
trigger_error(
134+
sprintf('Failed to seed menu item permissions for "%s" during install.', $definition['title']),
135+
E_USER_WARNING
136+
);
137+
return false;
138+
}
139+
}
140+
}
141+
142+
return true;
143+
}
144+
45145
/**
46146
* @param $dbm
47147
* @param $adminname
@@ -104,6 +204,9 @@ function make_data($dbm, $adminname, $hashedAdminPass, $adminmail, $language, $g
104204
$time = time();
105205
// RMV-NOTIFY (updated for extra column in table)
106206
$dbm->insert('modules', " VALUES (1, '" . _MI_SYSTEM_NAME . "', '" . $modversion['version'] . "', " . $time . ", 0, 1, 'system', 0, 1, 0, 0, 0, 0)");
207+
if (!system_menu_install_seed_defaults($dbm, $groups, 1)) {
208+
return false;
209+
}
107210

108211
foreach ($modversion['templates'] as $tplfile) {
109212
$templateType = isset($tplfile['type']) && 'admin' === $tplfile['type'] ? 'admin' : 'module';

htdocs/install/sql/mysql.structure.sql

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,46 @@ CREATE TABLE group_permission (
231231
) ENGINE=MyISAM;
232232
# --------------------------------------------------------
233233

234+
#
235+
# Table structure for table `menuscategory`
236+
#
237+
238+
CREATE TABLE menuscategory (
239+
category_id int unsigned NOT NULL auto_increment,
240+
category_title varchar(100) NOT NULL default '',
241+
category_prefix text NOT NULL,
242+
category_suffix text NOT NULL,
243+
category_url varchar(255) NOT NULL default '',
244+
category_target tinyint(1) unsigned NOT NULL default '0',
245+
category_position int NOT NULL default '0',
246+
category_protected int NOT NULL default '0',
247+
category_active tinyint(1) unsigned NOT NULL default '1',
248+
PRIMARY KEY (category_id)
249+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
250+
# --------------------------------------------------------
251+
252+
#
253+
# Table structure for table `menusitems`
254+
#
255+
256+
CREATE TABLE menusitems (
257+
items_id int unsigned NOT NULL auto_increment,
258+
items_pid int NOT NULL default '0',
259+
items_cid int unsigned NOT NULL default '0',
260+
items_title varchar(100) NOT NULL default '',
261+
items_prefix text NOT NULL,
262+
items_suffix text NOT NULL,
263+
items_url varchar(255) NOT NULL default '',
264+
items_target tinyint(1) unsigned NOT NULL default '0',
265+
items_position int NOT NULL default '0',
266+
items_protected int NOT NULL default '0',
267+
items_active tinyint(1) unsigned NOT NULL default '1',
268+
PRIMARY KEY (items_id),
269+
KEY idx_items_cid (items_cid),
270+
KEY idx_items_pid (items_pid)
271+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
272+
# --------------------------------------------------------
273+
234274

235275
#
236276
# Table structure for table `groups_users_link`
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<?php
2+
/*
3+
* You may not change or alter any portion of this comment or credits
4+
* of supporting developers from this source code or any supporting source code
5+
* which is considered copyrighted (c) material of the original comment or credit authors.
6+
*
7+
* This program is distributed in the hope that it will be useful,
8+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10+
*/
11+
12+
/**
13+
* Shared protected menu seed data for install and upgrade flows.
14+
*
15+
* Titles are stored as language constant identifiers and resolved at render time.
16+
*
17+
* @return array{categories: array<string, array<string, mixed>>, items: array<int, array<string, mixed>>}
18+
*/
19+
function system_menu_get_seed_definitions(): array
20+
{
21+
return [
22+
'categories' => [
23+
'home' => [
24+
'title' => 'MENUS_HOME',
25+
'prefix' => '<span class="fa fa-home"></span>',
26+
'suffix' => '',
27+
'url' => 'index.php',
28+
'target' => 0,
29+
'position' => 1,
30+
'protected' => 1,
31+
'active' => 1,
32+
'group_keys' => ['admin', 'users', 'anonymous'],
33+
],
34+
'account' => [
35+
'title' => 'MENUS_ACCOUNT',
36+
'prefix' => '<span class="fa fa-user fa-fw"></span>',
37+
'suffix' => '',
38+
'url' => '',
39+
'target' => 0,
40+
'position' => 2,
41+
'protected' => 1,
42+
'active' => 1,
43+
'group_keys' => ['admin', 'users', 'anonymous'],
44+
],
45+
'admin' => [
46+
'title' => 'MENUS_ADMIN',
47+
'prefix' => '<span class="fa fa-wrench fa-fw"></span>',
48+
'suffix' => '',
49+
'url' => 'admin.php',
50+
'target' => 0,
51+
'position' => 3,
52+
'protected' => 1,
53+
'active' => 1,
54+
'group_keys' => ['admin'],
55+
],
56+
],
57+
'items' => [
58+
[
59+
'title' => 'MENUS_ACCOUNT_EDIT',
60+
'prefix' => '<span class="fa fa-edit fa-fw"></span>',
61+
'suffix' => '',
62+
'url' => 'user.php',
63+
'target' => 0,
64+
'position' => 1,
65+
'pid' => 0,
66+
'protected' => 1,
67+
'active' => 1,
68+
'group_keys' => ['admin', 'users'],
69+
],
70+
[
71+
'title' => 'MENUS_ACCOUNT_LOGIN',
72+
'prefix' => '<span class="fa fa-sign-in fa-fw"></span>',
73+
'suffix' => '',
74+
'url' => 'user.php',
75+
'target' => 0,
76+
'position' => 2,
77+
'pid' => 0,
78+
'protected' => 1,
79+
'active' => 1,
80+
'group_keys' => ['anonymous'],
81+
],
82+
[
83+
'title' => 'MENUS_ACCOUNT_REGISTER',
84+
'prefix' => '<span class="fa fa-sign-in fa-fw"></span>',
85+
'suffix' => '',
86+
'url' => 'register.php',
87+
'target' => 0,
88+
'position' => 3,
89+
'pid' => 0,
90+
'protected' => 1,
91+
'active' => 1,
92+
'group_keys' => ['anonymous'],
93+
],
94+
[
95+
'title' => 'MENUS_ACCOUNT_MESSAGES',
96+
'prefix' => '<span class="fa fa-envelope fa-fw"></span>',
97+
'suffix' => '<span class="badge bg-primary rounded-pill"><{xoInboxCount}></span>',
98+
'url' => 'viewpmsg.php',
99+
'target' => 0,
100+
'position' => 4,
101+
'pid' => 0,
102+
'protected' => 1,
103+
'active' => 1,
104+
'group_keys' => ['admin', 'users'],
105+
],
106+
[
107+
'title' => 'MENUS_ACCOUNT_NOTIFICATIONS',
108+
'prefix' => '<span class="fa fa-info-circle fa-fw"></span>',
109+
'suffix' => '',
110+
'url' => 'notifications.php',
111+
'target' => 0,
112+
'position' => 5,
113+
'pid' => 0,
114+
'protected' => 1,
115+
'active' => 1,
116+
'group_keys' => ['admin', 'users'],
117+
],
118+
[
119+
'title' => 'MENUS_ACCOUNT_TOOLBAR',
120+
'prefix' => '<span class="fa fa-wrench fa-fw"></span>',
121+
'suffix' => '<span id="xswatch-toolbar-ind"></span>',
122+
'url' => '#xswatch-toolbar-toggle',
123+
'target' => 0,
124+
'position' => 6,
125+
'pid' => 0,
126+
'protected' => 1,
127+
'active' => 1,
128+
'group_keys' => ['admin', 'users'],
129+
],
130+
[
131+
'title' => 'MENUS_ACCOUNT_LOGOUT',
132+
'prefix' => '<span class="fa fa-sign-out fa-fw"></span>',
133+
'suffix' => '',
134+
'url' => 'user.php?op=logout',
135+
'target' => 0,
136+
'position' => 7,
137+
'pid' => 0,
138+
'protected' => 1,
139+
'active' => 1,
140+
'group_keys' => ['admin', 'users'],
141+
],
142+
],
143+
];
144+
}
145+
146+
/**
147+
* Resolve symbolic group keys to concrete group ids.
148+
*
149+
* @param string[] $groupKeys
150+
* @param array<string, int> $groupMap
151+
*
152+
* @return int[]
153+
*/
154+
function system_menu_map_group_keys(array $groupKeys, array $groupMap): array
155+
{
156+
$groupIds = [];
157+
foreach ($groupKeys as $groupKey) {
158+
if (isset($groupMap[$groupKey])) {
159+
$groupIds[] = $groupMap[$groupKey];
160+
}
161+
}
162+
163+
return $groupIds;
164+
}

0 commit comments

Comments
 (0)