diff --git a/source/packages/mod_mokosuite_cpanel/tmpl/default.php b/source/packages/mod_mokosuite_cpanel/tmpl/default.php index 6233883c..7324f3f2 100644 --- a/source/packages/mod_mokosuite_cpanel/tmpl/default.php +++ b/source/packages/mod_mokosuite_cpanel/tmpl/default.php @@ -22,7 +22,7 @@ $healthOk = $healthOk ?? true; $counts = $counts ?? (object) ['articles' => 0, 'users' => 0, 'extensions' => 0, 'updates' => 0]; $disk = $disk ?? (object) ['free_mb' => null, 'total_mb' => null]; $currentIp = $currentIp ?? ''; -$collapsed = $params->get('collapsed', 1); +$collapsed = $params->get('collapsed', 0); $showHealth = $params->get('show_health', 1); $showStats = $params->get('show_stats', 1); $showDisk = $params->get('show_disk', 1); diff --git a/source/script.php b/source/script.php index 8ad33dcc..bc36b3b5 100644 --- a/source/script.php +++ b/source/script.php @@ -944,219 +944,87 @@ class Pkg_MokosuiteInstallerScript */ private function setupCpanelModule(): void { - try - { - $db = Factory::getDbo(); - - // Enable the module - $query = $db->getQuery(true) - ->update($db->quoteName('#__extensions')) - ->set($db->quoteName('enabled') . ' = 1') - ->where($db->quoteName('type') . ' = ' . $db->quote('module')) - ->where($db->quoteName('element') . ' = ' . $db->quote('mod_mokosuite_cpanel')); - $db->setQuery($query); - $db->execute(); - - // Check if a module instance already exists in #__modules - $query = $db->getQuery(true) - ->select('id') - ->from($db->quoteName('#__modules')) - ->where($db->quoteName('module') . ' = ' . $db->quote('mod_mokosuite_cpanel')); - $db->setQuery($query); - $existingId = (int) $db->loadResult(); - - if ($existingId > 0) - { - // Ensure it's published with correct position - $db->setQuery( - $db->getQuery(true) - ->update('#__modules') - ->set('published = 1') - ->set($db->quoteName('position') . ' = ' . $db->quote('top')) - ->where('id = ' . $existingId) - )->execute(); - return; - } - - // Create the module instance on the cpanel position - $module = (object) [ - 'title' => 'MokoSuite', - 'note' => '', - 'content' => '', - 'ordering' => 0, - 'position' => 'top', - 'checked_out' => null, - 'checked_out_time' => null, - 'publish_up' => null, - 'publish_down' => null, - 'published' => 1, - 'module' => 'mod_mokosuite_cpanel', - 'access' => 6, // Super Users only - 'showtitle' => 0, - 'params' => '{"show_health":"1","show_plugins":"1"}', - 'client_id' => 1, // Administrator - 'language' => '*', - ]; - - $db->insertObject('#__modules', $module, 'id'); - $moduleId = (int) $module->id; - - if ($moduleId) - { - // Assign to all admin pages - $map = (object) [ - 'moduleid' => $moduleId, - 'menuid' => 0, // 0 = all pages - ]; - $db->insertObject('#__modules_menu', $map); - } - } - catch (\Throwable $e) - { - Log::add('CPanel module setup error: ' . $e->getMessage(), Log::WARNING, 'mokosuite'); - } + $this->ensureAdminModule('mod_mokosuite_cpanel', 'MokoSuite', 'top', 6, 0, '{"show_health":"1","show_plugins":"1"}'); } - /** - * Set up the MokoSuite admin sidebar menu module at position 0. - */ private function setupAdminMenuModule(): void { - try - { - $db = Factory::getDbo(); + $this->ensureAdminModule('mod_mokosuite_menu', 'MokoSuite Menu', 'menu', 3, 0); + } - // Enable the module extension - $db->setQuery( - $db->getQuery(true) - ->update($db->quoteName('#__extensions')) - ->set($db->quoteName('enabled') . ' = 1') - ->where($db->quoteName('type') . ' = ' . $db->quote('module')) - ->where($db->quoteName('element') . ' = ' . $db->quote('mod_mokosuite_menu')) - )->execute(); - - // Check if module instance exists - $db->setQuery( - $db->getQuery(true) - ->select('id') - ->from($db->quoteName('#__modules')) - ->where($db->quoteName('module') . ' = ' . $db->quote('mod_mokosuite_menu')) - ); - $existingId = (int) $db->loadResult(); - - if ($existingId > 0) - { - $db->setQuery( - $db->getQuery(true) - ->update('#__modules') - ->set('published = 1') - ->set($db->quoteName('position') . ' = ' . $db->quote('menu')) - ->where('id = ' . $existingId) - )->execute(); - return; - } - - $module = (object) [ - 'title' => 'MokoSuite Menu', - 'note' => '', - 'content' => '', - 'ordering' => 0, - 'position' => 'menu', - 'checked_out' => null, - 'checked_out_time' => null, - 'publish_up' => null, - 'publish_down' => null, - 'published' => 1, - 'module' => 'mod_mokosuite_menu', - 'access' => 3, - 'showtitle' => 0, - 'params' => '{}', - 'client_id' => 1, - 'language' => '*', - ]; - - $db->insertObject('#__modules', $module, 'id'); - - if ((int) $module->id) - { - $db->insertObject('#__modules_menu', (object) ['moduleid' => (int) $module->id, 'menuid' => 0]); - } - } - catch (\Throwable $e) - { - Log::add('Admin menu module setup error: ' . $e->getMessage(), Log::WARNING, 'mokosuite'); - } + private function setupCacheModule(): void + { + $this->ensureAdminModule('mod_mokosuite_cache', 'MokoSuite Cache Cleaner', 'status', 3, 8); } /** - * Set up the cache cleaner module in the admin status bar position. + * Ensure an admin module is published at the correct position using Joomla's ModuleModel. + * + * Uses the Joomla MVC save pipeline so that #__modules_menu mappings, + * checked_out, and all internal bookkeeping are handled correctly. */ - private function setupCacheModule(): void + private function ensureAdminModule(string $element, string $title, string $position, int $access = 3, int $ordering = 0, string $params = '{}'): void { try { $db = Factory::getDbo(); - // Enable the module extension + // Enable the extension entry $db->setQuery( $db->getQuery(true) - ->update($db->quoteName('#__extensions')) - ->set($db->quoteName('enabled') . ' = 1') - ->where($db->quoteName('type') . ' = ' . $db->quote('module')) - ->where($db->quoteName('element') . ' = ' . $db->quote('mod_mokosuite_cache')) + ->update('#__extensions') + ->set('enabled = 1') + ->where('type = ' . $db->quote('module')) + ->where('element = ' . $db->quote($element)) )->execute(); - // Check if module instance exists + // Find existing module instance $db->setQuery( $db->getQuery(true) ->select('id') - ->from($db->quoteName('#__modules')) - ->where($db->quoteName('module') . ' = ' . $db->quote('mod_mokosuite_cache')) + ->from('#__modules') + ->where('module = ' . $db->quote($element)) + ->setLimit(1) ); - $existingId = (int) $db->loadResult(); + $moduleId = (int) $db->loadResult(); - if ($existingId > 0) - { - $db->setQuery( - $db->getQuery(true) - ->update('#__modules') - ->set('published = 1') - ->set($db->quoteName('position') . ' = ' . $db->quote('status')) - ->where('id = ' . $existingId) - )->execute(); - return; - } - - $module = (object) [ - 'title' => 'MokoSuite Cache Cleaner', - 'note' => '', - 'content' => '', - 'ordering' => 8, - 'position' => 'status', - 'checked_out' => null, - 'checked_out_time' => null, - 'publish_up' => null, - 'publish_down' => null, + // Build save data — Joomla's ModuleModel expects this format + $data = [ + 'title' => $title, + 'module' => $element, + 'position' => $position, 'published' => 1, - 'module' => 'mod_mokosuite_cache', - 'access' => 3, + 'access' => $access, + 'ordering' => $ordering, 'showtitle' => 0, - 'params' => '{}', 'client_id' => 1, 'language' => '*', + 'params' => $params, + 'assignment' => 0, // 0 = all pages ]; - $db->insertObject('#__modules', $module, 'id'); - - if ((int) $module->id) + if ($moduleId > 0) { - $mm = (object) ['moduleid' => (int) $module->id, 'menuid' => 0]; - $db->insertObject('#__modules_menu', $mm, 'moduleid'); + $data['id'] = $moduleId; + } + + // Use Joomla's ModuleModel to handle save + menu assignment + \Joomla\CMS\MVC\Factory\MVCFactory::class; + $app = Factory::getApplication(); + + /** @var \Joomla\Component\Modules\Administrator\Model\ModuleModel $model */ + $model = $app->bootComponent('com_modules') + ->getMVCFactory() + ->createModel('Module', 'Administrator', ['ignore_request' => true]); + + if (!$model->save($data)) + { + Log::add("Module setup ({$element}): " . $model->getError(), Log::WARNING, 'mokosuite'); } } catch (\Throwable $e) { - Log::add('Cache module setup error: ' . $e->getMessage(), Log::WARNING, 'mokosuite'); + Log::add("Module setup ({$element}): " . $e->getMessage(), Log::WARNING, 'mokosuite'); } }