diff --git a/src/script.php b/src/script.php index c48027e..35f6641 100644 --- a/src/script.php +++ b/src/script.php @@ -94,6 +94,7 @@ class Tpl_MokoonyxInstallerScript implements InstallerScriptInterface $this->clearFaviconStamp(); $this->cleanMediaFolder(); $this->removeDeletedFiles(); + $this->removeDuplicateExtensions(); $this->lockExtension(); } @@ -484,6 +485,96 @@ class Tpl_MokoonyxInstallerScript implements InstallerScriptInterface } } + /** + * Remove duplicate MokoOnyx extension entries from #__extensions. + * + * Re-installs or migrations can leave ghost rows. We keep the one + * that is locked (the active template) and delete any extras. + * Also removes stale MokoCassiopeia entries if present. + */ + private function removeDuplicateExtensions(): void + { + $db = Factory::getDbo(); + + // Find all MokoOnyx template entries + $rows = $db->setQuery( + $db->getQuery(true) + ->select(['extension_id', 'locked']) + ->from('#__extensions') + ->where($db->quoteName('element') . ' = ' . $db->quote(self::NEW_NAME)) + ->where($db->quoteName('type') . ' = ' . $db->quote('template')) + ->order('locked DESC, extension_id ASC') + )->loadObjectList(); + + if (count($rows) > 1) { + $keep = (int) $rows[0]->extension_id; + $removed = 0; + + for ($i = 1; $i < count($rows); $i++) { + $staleId = (int) $rows[$i]->extension_id; + + $db->setQuery( + $db->getQuery(true) + ->delete('#__update_sites_extensions') + ->where('extension_id = ' . $staleId) + )->execute(); + + $db->setQuery( + $db->getQuery(true) + ->delete('#__extensions') + ->where('extension_id = ' . $staleId) + )->execute(); + + $removed++; + } + + if ($removed > 0) { + $this->logMessage("Removed {$removed} duplicate MokoOnyx extension(s). Kept ID {$keep}."); + } + } + + // Remove stale MokoCassiopeia if not set as default + $oldExt = (int) $db->setQuery( + $db->getQuery(true) + ->select('extension_id') + ->from('#__extensions') + ->where($db->quoteName('element') . ' = ' . $db->quote(self::OLD_NAME)) + ->where($db->quoteName('type') . ' = ' . $db->quote('template')) + )->loadResult(); + + if ($oldExt) { + $isDefault = (int) $db->setQuery( + $db->getQuery(true) + ->select('COUNT(*)') + ->from('#__template_styles') + ->where($db->quoteName('template') . ' = ' . $db->quote(self::OLD_NAME)) + ->where($db->quoteName('home') . ' = 1') + )->loadResult(); + + if ($isDefault === 0) { + $db->setQuery( + $db->getQuery(true) + ->delete('#__update_sites_extensions') + ->where('extension_id = ' . $oldExt) + )->execute(); + + $db->setQuery( + $db->getQuery(true) + ->delete('#__extensions') + ->where('extension_id = ' . $oldExt) + )->execute(); + + $db->setQuery( + $db->getQuery(true) + ->delete('#__template_styles') + ->where($db->quoteName('template') . ' = ' . $db->quote(self::OLD_NAME)) + )->execute(); + + $this->logMessage('Removed stale MokoCassiopeia extension and styles.'); + } + } + } + /** * Remove files and directories that were shipped in previous versions * but have since been deleted from the package.