diff --git a/CHANGELOG.md b/CHANGELOG.md index 34c2813..9cc34ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] +### Fixed +- **Honest install success** — the installer no longer claims success or shows the license message when the install partially failed. The package postflight verifies every child extension declared in the manifest registered in `#__extensions`; the `com_mokoog` component script verifies its declared tables exist before echoing the success message. Both checks fail open, so a transient DB/IO glitch never fakes a failure. + ### Added - OG coverage **dashboard** as the default admin view — SVG donut gauge, coverage by content type, and a list of articles missing OG tags with a batch-generate shortcut (#94) - Single OG tag **create/edit screen** in the admin (the tag manager was previously read-only) (#98) diff --git a/source/packages/com_mokoog/script.php b/source/packages/com_mokoog/script.php index ace5636..9990285 100644 --- a/source/packages/com_mokoog/script.php +++ b/source/packages/com_mokoog/script.php @@ -10,7 +10,9 @@ defined('_JEXEC') or die; +use Joomla\CMS\Factory; use Joomla\CMS\Installer\InstallerAdapter; +use Joomla\Database\DatabaseInterface; class Com_MokoOGInstallerScript { @@ -23,6 +25,20 @@ class Com_MokoOGInstallerScript */ public function install(InstallerAdapter $parent): void { + // Be honest about success: don't claim a clean install if the component's + // own tables never landed. Fails open (see missingTables) so a query/IO + // glitch never fakes a failure. + $missing = $this->missingTables(); + + if (!empty($missing)) + { + echo '
MokoSuiteOpenGraph component did not install correctly. ' + . 'Missing database table(s): ' + . htmlspecialchars(implode(', ', $missing), ENT_QUOTES) . '.
'; + + return; + } + echo 'MokoSuiteOpenGraph component installed successfully.
'; } @@ -35,6 +51,69 @@ class Com_MokoOGInstallerScript */ public function update(InstallerAdapter $parent): void { + $missing = $this->missingTables(); + + if (!empty($missing)) + { + echo 'MokoSuiteOpenGraph component did not update correctly. ' + . 'Missing database table(s): ' + . htmlspecialchars(implode(', ', $missing), ENT_QUOTES) . '.
'; + + return; + } + echo 'MokoSuiteOpenGraph component updated successfully.
'; } + + /** + * Verify the component's declared tables actually exist. Reads the shipped + * install SQL, extracts every CREATE TABLE #__name, resolves the live prefix, + * and checks each against the database's table list (case-insensitive). + * + * FAILS OPEN: any error (unreadable SQL, query failure) returns [] so a + * transient glitch never turns a good install into a false failure. + * + * @return string[] Prefixed names of any missing tables. + */ + private function missingTables(): array + { + try + { + $sqlFile = JPATH_ADMINISTRATOR . '/components/com_mokoog/sql/install.mysql.sql'; + + if (!is_file($sqlFile)) + { + return []; + } + + $sql = (string) file_get_contents($sqlFile); + + if ($sql === '' || !preg_match_all('/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?[`"\']?(#__[A-Za-z0-9_]+)/i', $sql, $m)) + { + return []; + } + + $db = Factory::getContainer()->get(DatabaseInterface::class); + $prefix = $db->getPrefix(); + $existing = array_map('strtolower', (array) $db->getTableList()); + $missing = []; + + foreach (array_unique($m[1]) as $table) + { + $real = str_replace('#__', $prefix, $table); + + if (!in_array(strtolower($real), $existing, true)) + { + $missing[] = $real; + } + } + + return $missing; + } + catch (\Throwable $e) + { + // Fail open — never fake a failure on a glitch. + return []; + } + } } diff --git a/source/script.php b/source/script.php index c90d65e..08b806d 100644 --- a/source/script.php +++ b/source/script.php @@ -51,8 +51,8 @@ class Pkg_MokoOGInstallerScript public function postflight(string $type, InstallerAdapter $parent): void { $this->restoreDownloadKey(); - $this->warnMissingLicenseKey(); + // Enable plugins after first install (unconditional module/plugin setup) if ($type === 'install') { $db = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class); @@ -69,6 +69,101 @@ class Pkg_MokoOGInstallerScript )->execute(); } } + + // Be honest about success. Joomla's package installer only LOGS a failed child + // sub-install but still runs this postflight, so don't show the license / + // next-steps message if a bundled extension is actually missing. Fails open + // (see missingChildExtensions) so a query/IO glitch never fakes a failure. + $missing = $this->missingChildExtensions($parent); + + if (!empty($missing)) + { + Factory::getApplication()->enqueueMessage( + 'The following bundled extensions are missing: ' + . htmlspecialchars(implode(', ', $missing), ENT_QUOTES) . '
' + . 'Please uninstall MokoSuiteOpenGraph and reinstall the full package.
', + 'error' + ); + + return; + } + + $this->warnMissingLicenseKey(); + } + + /** + * Verify every child extension declared in the package manifest actually landed + * in #__extensions. Returns readable labels of any that are missing. + * + * element =