diff --git a/source/script.php b/source/script.php index 045022c..f05e331 100644 --- a/source/script.php +++ b/source/script.php @@ -1,9 +1,10 @@ warnMissingLicenseKey(); + if ($type === 'update') + { + $this->savedDlid = $this->getExistingDlid(); + } + + return true; } - private function warnMissingLicenseKey(): void + public function postflight(string $type, InstallerAdapter $adapter): void { - try + if ($this->savedDlid) + { + $this->restoreDlid($this->savedDlid); + } + + if ($type === 'install') + { + $missing = $this->verifyChildren($adapter); + + if (!empty($missing)) + { + Factory::getApplication()->enqueueMessage( + 'MokoSuite NPO — Incomplete Installation
' + . 'The following extensions failed to install: ' + . implode(', ', $missing) + . '.
Please check file permissions and server logs, then reinstall the package.', + 'error' + ); + + return; + } + + $this->enablePlugin('system', 'mokosuitenpo'); + $this->enablePlugin('webservices', 'mokosuitenpo'); + $this->enablePlugin('task', 'mokosuitenpo_task'); + } + + $dlid = $this->getExistingDlid(); + + if (empty($dlid)) { - $db = Factory::getDbo(); $app = Factory::getApplication(); - $query = $db->getQuery(true) - ->select([$db->quoteName('update_site_id'), $db->quoteName('extra_query')]) - ->from($db->quoteName('#__update_sites')) - ->where('(' . $db->quoteName('name') . ' LIKE ' . $db->quote('%MokoSuiteNPO%') - . ' OR ' . $db->quoteName('location') . ' LIKE ' . $db->quote('%MokoSuiteNPO%') . ')') - ->setLimit(1); - $db->setQuery($query); - $site = $db->loadObject(); - - if ($site) + try { - $extraQuery = (string) ($site->extra_query ?? ''); - - if (!empty($extraQuery) && strpos($extraQuery, 'dlid=') !== false) - { - parse_str($extraQuery, $parsed); - - if (!empty($parsed['dlid'])) - { - return; - } - } - - $editUrl = 'index.php?option=com_installer&task=updatesite.edit&update_site_id=' . (int) $site->update_site_id; + $db = Factory::getContainer()->get(DatabaseInterface::class); + $db->setQuery( + $db->getQuery(true) + ->select($db->quoteName('update_site_id')) + ->from($db->quoteName('#__update_sites')) + ->where($db->quoteName('name') . ' LIKE ' . $db->quote('%MokoSuiteNPO%')) + ->setLimit(1) + ); + $siteId = (int) $db->loadResult(); + $editUrl = $siteId + ? 'index.php?option=com_installer&task=updatesite.edit&update_site_id=' . $siteId + : 'index.php?option=com_installer&view=updatesites'; } - else + catch (\Throwable $e) { $editUrl = 'index.php?option=com_installer&view=updatesites'; } @@ -66,9 +90,130 @@ class Pkg_MokoSuiteNPOInstallerScript 'warning' ); } + } + + private function verifyChildren(InstallerAdapter $adapter): array + { + try + { + $manifest = $adapter->getParent()->getManifest(); + $files = $manifest->files->file ?? []; + + if (!$files) + { + return []; + } + + $db = Factory::getContainer()->get(DatabaseInterface::class); + $missing = []; + + foreach ($files as $file) + { + $type = (string) ($file['type'] ?? ''); + $id = (string) ($file['id'] ?? ''); + $group = (string) ($file['group'] ?? ''); + + if ($type === '' || $id === '') + { + continue; + } + + $element = ($type === 'plugin' && $group !== '') + ? preg_replace('/^plg_' . preg_quote($group, '/') . '_/', '', $id) + : $id; + + $query = $db->getQuery(true) + ->select('COUNT(*)') + ->from($db->quoteName('#__extensions')) + ->where($db->quoteName('element') . ' = ' . $db->quote($element)) + ->where($db->quoteName('type') . ' = ' . $db->quote($type)); + + if ($type === 'plugin' && $group !== '') + { + $query->where($db->quoteName('folder') . ' = ' . $db->quote($group)); + } + + $db->setQuery($query); + + if ((int) $db->loadResult() === 0) + { + $missing[] = htmlspecialchars($type . ': ' . $id, ENT_QUOTES, 'UTF-8'); + } + } + + return $missing; + } catch (\Throwable $e) { - // Silent — avoid breaking install if update_sites query fails + return []; + } + } + + private function getExistingDlid(): string + { + try + { + $db = Factory::getContainer()->get(DatabaseInterface::class); + $db->setQuery( + $db->getQuery(true) + ->select($db->quoteName('extra_query')) + ->from($db->quoteName('#__update_sites')) + ->where($db->quoteName('name') . ' LIKE ' . $db->quote('%MokoSuiteNPO%')) + ->setLimit(1) + ); + + $extraQuery = $db->loadResult() ?? ''; + + if (preg_match('/dlid=([a-zA-Z0-9]+)/', $extraQuery, $matches)) + { + return $matches[1]; + } + } + catch (\Throwable $e) + { + Log::add('NPO install: failed to read DLID — ' . $e->getMessage(), Log::WARNING, 'mokosuite.npo'); + } + + return ''; + } + + private function restoreDlid(string $dlid): void + { + try + { + $db = Factory::getContainer()->get(DatabaseInterface::class); + $db->setQuery( + $db->getQuery(true) + ->update($db->quoteName('#__update_sites')) + ->set($db->quoteName('extra_query') . ' = ' . $db->quote('dlid=' . $dlid)) + ->where($db->quoteName('name') . ' LIKE ' . $db->quote('%MokoSuiteNPO%')) + ); + $db->execute(); + } + catch (\Throwable $e) + { + Log::add('NPO install: failed to restore DLID — ' . $e->getMessage(), Log::WARNING, 'mokosuite.npo'); + } + } + + private function enablePlugin(string $group, string $element): void + { + try + { + $db = Factory::getContainer()->get(DatabaseInterface::class); + $db->setQuery( + $db->getQuery(true) + ->update($db->quoteName('#__extensions')) + ->set($db->quoteName('enabled') . ' = 1') + ->where($db->quoteName('type') . ' = ' . $db->quote('plugin')) + ->where($db->quoteName('folder') . ' = ' . $db->quote($group)) + ->where($db->quoteName('element') . ' = ' . $db->quote($element)) + ); + $db->execute(); + } + catch (\Throwable $e) + { + Log::add('NPO install: failed to enable ' . $group . '/' . $element . ' — ' . $e->getMessage(), Log::WARNING, 'mokosuite.npo'); } } }