fix(installer): self-heal admin menu; fix alias collision; short-constant label
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 22s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 22s
Fallout of the duplicate-component element bug:
- Preflight now runs removeOrphanedComponent() BEFORE the component install
recreates its menu, so the orphan's "Backup" menu (alias "backup") no longer
collides ("The alias backup is already being used by the Backup menu item").
- ensureSubmenuItems() recreates the top-level "Backup" menu when it is missing
(via new createTopMenu()) instead of bailing out — so a failed install that
deleted the parent menu no longer leaves Backup gone from the admin menu (which
also broke the cPanel module and MokoSuiteClient component detection).
- The top-level menu label now uses the short constant COM_MOKOJOOMBACKUP_SHORT
(manifest <menu> + enforced/normalized in the script).
Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
This commit is contained in:
+96
-17
@@ -77,6 +77,13 @@ class Pkg_MokoSuiteBackupInstallerScript
|
||||
$this->backupDownloadKey();
|
||||
}
|
||||
|
||||
/* Remove any orphaned mis-registered component BEFORE the component install
|
||||
recreates its admin menu. The orphan (element com_component-mokosuitebackup)
|
||||
owns a "Backup" menu with alias "backup"; if it survives, the real
|
||||
component's menu creation collides ("The alias backup is already being used")
|
||||
and the whole install aborts. */
|
||||
$this->removeOrphanedComponent();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -622,23 +629,7 @@ class Pkg_MokoSuiteBackupInstallerScript
|
||||
try {
|
||||
$db = Factory::getDbo();
|
||||
|
||||
/* Find the parent menu item for our component */
|
||||
$query = $db->getQuery(true)
|
||||
->select([$db->quoteName('id'), $db->quoteName('menutype')])
|
||||
->from($db->quoteName('#__menu'))
|
||||
->where($db->quoteName('client_id') . ' = 1')
|
||||
->where($db->quoteName('level') . ' = 1')
|
||||
->where($db->quoteName('link') . ' LIKE ' . $db->quote('index.php?option=com_mokosuitebackup%'))
|
||||
->setLimit(1);
|
||||
$db->setQuery($query);
|
||||
$parent = $db->loadObject();
|
||||
|
||||
if (!$parent) {
|
||||
error_log('MokoSuiteBackup: ensureSubmenuItems() — parent menu item not found');
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the component extension_id */
|
||||
/* Component extension_id first — needed to (re)create the parent menu. */
|
||||
$query = $db->getQuery(true)
|
||||
->select($db->quoteName('extension_id'))
|
||||
->from($db->quoteName('#__extensions'))
|
||||
@@ -653,6 +644,41 @@ class Pkg_MokoSuiteBackupInstallerScript
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find the top-level "Backup" parent menu item for our component */
|
||||
$query = $db->getQuery(true)
|
||||
->select([$db->quoteName('id'), $db->quoteName('menutype')])
|
||||
->from($db->quoteName('#__menu'))
|
||||
->where($db->quoteName('client_id') . ' = 1')
|
||||
->where($db->quoteName('level') . ' = 1')
|
||||
->where($db->quoteName('link') . ' LIKE ' . $db->quote('index.php?option=com_mokosuitebackup%'))
|
||||
->setLimit(1);
|
||||
$db->setQuery($query);
|
||||
$parent = $db->loadObject();
|
||||
|
||||
/* Self-heal: if the top-level menu was deleted (e.g. by a failed install
|
||||
after the duplicate-component mess), recreate it — otherwise the whole
|
||||
Backup menu stays gone and dependents (cPanel module, MokoSuiteClient)
|
||||
can't locate the component. */
|
||||
if (!$parent) {
|
||||
$parent = $this->createTopMenu($componentId);
|
||||
|
||||
if (!$parent) {
|
||||
error_log('MokoSuiteBackup: ensureSubmenuItems() — parent menu missing and could not be created');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep the top-level menu label on the short constant and owned by the
|
||||
real component. */
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->update($db->quoteName('#__menu'))
|
||||
->set($db->quoteName('title') . ' = ' . $db->quote('COM_MOKOJOOMBACKUP_SHORT'))
|
||||
->set($db->quoteName('component_id') . ' = ' . (int) $componentId)
|
||||
->where($db->quoteName('id') . ' = ' . (int) $parent->id)
|
||||
);
|
||||
$db->execute();
|
||||
|
||||
foreach ($submenus as $submenu) {
|
||||
/* Check if this submenu item already exists */
|
||||
$query = $db->getQuery(true)
|
||||
@@ -718,6 +744,59 @@ class Pkg_MokoSuiteBackupInstallerScript
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the top-level "Backup" admin menu item for the component when it is
|
||||
* missing (deleted by a failed install / the duplicate-component fallout).
|
||||
* Label uses the short constant. Returns a lightweight {id, menutype} object,
|
||||
* or null on failure.
|
||||
*
|
||||
* @param int $componentId Extension id of com_mokosuitebackup
|
||||
*
|
||||
* @return object|null
|
||||
*/
|
||||
private function createTopMenu(int $componentId): ?object
|
||||
{
|
||||
try {
|
||||
$table = Factory::getApplication()
|
||||
->bootComponent('com_menus')
|
||||
->getMVCFactory()
|
||||
->createTable('Menu', 'Administrator');
|
||||
|
||||
$table->menutype = 'main';
|
||||
$table->title = 'COM_MOKOJOOMBACKUP_SHORT';
|
||||
$table->alias = 'backup';
|
||||
$table->link = 'index.php?option=com_mokosuitebackup';
|
||||
$table->type = 'component';
|
||||
$table->published = 1;
|
||||
$table->parent_id = 1;
|
||||
$table->level = 1;
|
||||
$table->component_id = $componentId;
|
||||
$table->client_id = 1;
|
||||
$table->img = 'class:archive';
|
||||
$table->params = '{}';
|
||||
$table->language = '*';
|
||||
$table->access = 1;
|
||||
|
||||
$table->setLocation(1, 'last-child');
|
||||
|
||||
if (!$table->check() || !$table->store()) {
|
||||
error_log('MokoSuiteBackup: createTopMenu() failed: ' . $table->getError());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$obj = new \stdClass();
|
||||
$obj->id = (int) $table->id;
|
||||
$obj->menutype = 'main';
|
||||
|
||||
return $obj;
|
||||
} catch (\Throwable $e) {
|
||||
error_log('MokoSuiteBackup: createTopMenu() exception: ' . $e->getMessage());
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private function fixPackageClientId(): void
|
||||
{
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user