diff --git a/source/script.php b/source/script.php index bfe0834b..9170c64b 100644 --- a/source/script.php +++ b/source/script.php @@ -526,36 +526,82 @@ class Pkg_MokosuiteclientInstallerScript try { $db = Factory::getDbo(); + $systemDir = JPATH_PLUGINS . '/system'; - // Delete orphaned extension rows with empty element - $db->setQuery("DELETE FROM " . $db->quoteName('#__extensions') - . " WHERE " . $db->quoteName('element') . " = ''"); - $db->execute(); - $deleted = $db->getAffectedRows(); + // Find empty-element rows and fix them using the manifest name + $db->setQuery( + $db->getQuery(true) + ->select([$db->quoteName('extension_id'), $db->quoteName('name'), $db->quoteName('folder')]) + ->from($db->quoteName('#__extensions')) + ->where($db->quoteName('element') . " = ''") + ->where($db->quoteName('type') . ' = ' . $db->quote('plugin')) + ); + $orphans = $db->loadObjectList() ?: []; - if ($deleted > 0) + foreach ($orphans as $orphan) { - Log::add("Deleted {$deleted} orphaned extension row(s) with empty element", Log::INFO, 'mokosuiteclient'); - Factory::getApplication()->enqueueMessage( - sprintf('Cleaned up %d orphaned extension record(s).', $deleted), - 'message' - ); + // Derive element from the manifest name (e.g. "plg_system_mokosuiteclient_offline" → "mokosuiteclient_offline") + $element = preg_replace('/^plg_[a-z]+_/', '', strtolower($orphan->name)); + + // Also try matching from stale XML manifests at group root + if (empty($element)) + { + continue; + } + + $pluginDir = $systemDir . '/' . $element; + + // If plugin dir doesn't exist but stale files do, relocate them + if (!is_dir($pluginDir) && $orphan->folder === 'system') + { + @mkdir($pluginDir, 0755, true); + + // Move stale dirs (services, src, language) into the plugin dir + foreach (['services', 'src', 'language'] as $subDir) + { + $stalePath = $systemDir . '/' . $subDir; + + if (is_dir($stalePath) && !is_dir($pluginDir . '/' . $subDir)) + { + @rename($stalePath, $pluginDir . '/' . $subDir); + } + } + + // Move stale manifest XML + $staleXml = $systemDir . '/' . $element . '.xml'; + + if (is_file($staleXml)) + { + @rename($staleXml, $pluginDir . '/' . $element . '.xml'); + } + + Log::add("Relocated stale files to plugins/system/{$element}/", Log::INFO, 'mokosuiteclient'); + } + + // Fix the element in the DB + $db->setQuery( + $db->getQuery(true) + ->update($db->quoteName('#__extensions')) + ->set($db->quoteName('element') . ' = ' . $db->quote($element)) + ->where($db->quoteName('extension_id') . ' = ' . (int) $orphan->extension_id) + )->execute(); + + Log::add("Fixed empty element → {$element} (ID {$orphan->extension_id})", Log::INFO, 'mokosuiteclient'); } - // Remove stale plugin files that leaked to group root + // Clean up any remaining stale dirs that couldn't be matched foreach (['services', 'src', 'language'] as $dir) { - $path = JPATH_PLUGINS . '/system/' . $dir; + $path = $systemDir . '/' . $dir; if (is_dir($path)) { $this->rmdirRecursive($path); - Log::add("Removed stale directory: plugins/system/{$dir}", Log::INFO, 'mokosuiteclient'); } } - // Remove stale XML manifests at group root - foreach (glob(JPATH_PLUGINS . '/system/mokosuiteclient_*.xml') ?: [] as $staleXml) + // Clean up stale XML manifests at group root + foreach (glob($systemDir . '/mokosuiteclient_*.xml') ?: [] as $staleXml) { @unlink($staleXml); }