diff --git a/source/script.php b/source/script.php index 9170c64b..98c5b85c 100644 --- a/source/script.php +++ b/source/script.php @@ -526,84 +526,51 @@ class Pkg_MokosuiteclientInstallerScript try { $db = Factory::getDbo(); - $systemDir = JPATH_PLUGINS . '/system'; - // 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() ?: []; + // Delete orphaned extension rows with empty element — they'll be + // recreated correctly on the next package update + $db->setQuery("DELETE FROM " . $db->quoteName('#__extensions') + . " WHERE " . $db->quoteName('element') . " = ''" + . " AND " . $db->quoteName('type') . " = 'plugin'"); + $db->execute(); + $deleted = $db->getAffectedRows(); - foreach ($orphans as $orphan) + if ($deleted > 0) { - // 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'); + Log::add("Deleted {$deleted} orphaned plugin row(s) with empty element", Log::INFO, 'mokosuiteclient'); } - // Clean up any remaining stale dirs that couldn't be matched - foreach (['services', 'src', 'language'] as $dir) - { - $path = $systemDir . '/' . $dir; + // Clean up stale plugin files that leaked to plugin group roots + $groupDirs = [JPATH_PLUGINS . '/system', JPATH_PLUGINS . '/task', JPATH_PLUGINS . '/webservices']; - if (is_dir($path)) + foreach ($groupDirs as $groupDir) + { + foreach (['services', 'src', 'language'] as $dir) { - $this->rmdirRecursive($path); - } - } + $path = $groupDir . '/' . $dir; - // Clean up stale XML manifests at group root - foreach (glob($systemDir . '/mokosuiteclient_*.xml') ?: [] as $staleXml) - { - @unlink($staleXml); + if (is_dir($path)) + { + $this->rmdirRecursive($path); + Log::add("Removed stale: {$path}", Log::INFO, 'mokosuiteclient'); + } + } + + // Remove stale manifest XMLs at group root + foreach (glob($groupDir . '/mokosuiteclient*.xml') ?: [] as $staleXml) + { + @unlink($staleXml); + } + + // Remove dirs with spaces (Joomla uses display name as dir when element is empty) + foreach (glob($groupDir . '/*mokosuiteclient*', GLOB_ONLYDIR) ?: [] as $badDir) + { + if (strpos(basename($badDir), ' ') !== false) + { + $this->rmdirRecursive($badDir); + Log::add("Removed bad dir: " . basename($badDir), Log::INFO, 'mokosuiteclient'); + } + } } } catch (\Throwable $e)