diff --git a/source/packages/plg_system_mokosuiteclient_backup/src/Extension/Backup.php b/source/packages/plg_system_mokosuiteclient_backup/src/Extension/Backup.php index 6eee0741..b921da44 100644 --- a/source/packages/plg_system_mokosuiteclient_backup/src/Extension/Backup.php +++ b/source/packages/plg_system_mokosuiteclient_backup/src/Extension/Backup.php @@ -22,6 +22,10 @@ use Joomla\Event\SubscriberInterface; * Detects whether MokoSuiteBackup is installed and collects backup * status data for inclusion in heartbeat payloads to MokoSuiteHQ. * + * Prefers MokoSuiteBackup's own BackupStatusHelper when available, + * falling back to a direct table query if the helper class is missing + * (e.g. older versions of MokoSuiteBackup). + * * @since 02.34.84 */ class Backup extends CMSPlugin implements SubscriberInterface @@ -90,6 +94,9 @@ class Backup extends CMSPlugin implements SubscriberInterface /** * Get backup status summary from MokoSuiteBackup. * + * Prefers the BackupStatusHelper API when available. Falls back + * to a direct database query for compatibility with older versions. + * * @return array Backup status data for heartbeat inclusion. */ public function getBackupStatus(): array @@ -101,12 +108,22 @@ class Backup extends CMSPlugin implements SubscriberInterface ]; } - $db = Factory::getContainer()->get(DatabaseInterface::class); - $tables = $db->getTableList(); - $prefix = $db->getPrefix(); - $statsTable = $prefix . 'mokosuitebackup_records'; + // Prefer MokoSuiteBackup's own helper (clean public API) + $helperClass = 'Joomla\\Component\\MokoSuiteBackup\\Administrator\\Utility\\BackupStatusHelper'; - if (!in_array($statsTable, $tables, true)) + if (class_exists($helperClass)) + { + $staleDays = (int) $this->params->get('stale_days', 7); + + return $helperClass::getStatus($staleDays); + } + + // Fallback: direct table query for older MokoSuiteBackup versions + $db = Factory::getContainer()->get(DatabaseInterface::class); + $tables = $db->getTableList(); + $prefix = $db->getPrefix(); + + if (!in_array($prefix . 'mokosuitebackup_records', $tables, true)) { return [ 'installed' => true, @@ -115,32 +132,17 @@ class Backup extends CMSPlugin implements SubscriberInterface ]; } - // TODO: Query MokoSuiteBackup records table for latest backup status. - // - // This is a placeholder — the actual column names and table structure - // depend on MokoSuiteBackup's schema. Once that component is available - // locally, update this query to match its database layout. - // - // Expected return shape: - // [ - // 'installed' => true, - // 'status' => 'ok' | 'degraded', - // 'last_backup' => '2026-06-18 10:30:45', - // 'last_status' => 'complete' | 'failed' | 'partial', - // 'last_size_mb' => 512, - // 'days_since' => 2, - // 'total_backups'=> 42, - // 'recent_7d' => 5, - // 'destination' => 'local' | 's3' | 'remote', - // 'description' => 'Full site backup', - // ] - return $this->queryBackupRecords($db); } /** * Query MokoSuiteBackup records for the latest backup summary. * + * Column names match the MokoSuiteBackup schema: + * - backupstart/backupend (not created/modified) + * - status: pending, running, complete, fail + * - total_size in bytes + * * @param DatabaseInterface $db Database driver. * * @return array Backup status array. @@ -149,9 +151,19 @@ class Backup extends CMSPlugin implements SubscriberInterface { $staleDays = (int) $this->params->get('stale_days', 7); - // Get the most recent backup record + // Most recent backup record $query = $db->getQuery(true) - ->select('*') + ->select([ + $db->quoteName('id'), + $db->quoteName('description'), + $db->quoteName('status'), + $db->quoteName('backup_type'), + $db->quoteName('total_size'), + $db->quoteName('backupstart'), + $db->quoteName('backupend'), + $db->quoteName('origin'), + $db->quoteName('filesexist'), + ]) ->from($db->quoteName('#__mokosuitebackup_records')) ->order($db->quoteName('id') . ' DESC'); @@ -167,53 +179,77 @@ class Backup extends CMSPlugin implements SubscriberInterface ]; } - // Count total and recent backups + // Count completed backups $db->setQuery( $db->getQuery(true) ->select('COUNT(*)') ->from($db->quoteName('#__mokosuitebackup_records')) + ->where($db->quoteName('status') . ' = ' . $db->quote('complete')) ); $totalBackups = (int) $db->loadResult(); + // Recent completed backups (last 7 days) + $cutoff = date('Y-m-d H:i:s', strtotime('-7 days')); $db->setQuery( $db->getQuery(true) ->select('COUNT(*)') ->from($db->quoteName('#__mokosuitebackup_records')) - ->where($db->quoteName('created') . ' >= DATE_SUB(NOW(), INTERVAL 7 DAY)') + ->where($db->quoteName('status') . ' = ' . $db->quote('complete')) + ->where($db->quoteName('backupstart') . ' >= ' . $db->quote($cutoff)) ); $recentBackups = (int) $db->loadResult(); + // Failures in last 7 days + $db->setQuery( + $db->getQuery(true) + ->select('COUNT(*)') + ->from($db->quoteName('#__mokosuitebackup_records')) + ->where($db->quoteName('status') . ' = ' . $db->quote('fail')) + ->where($db->quoteName('backupstart') . ' >= ' . $db->quote($cutoff)) + ); + $failCount7d = (int) $db->loadResult(); + // Determine status - $lastDate = $latest->created ?? ''; - $daysSince = $lastDate ? (int) ((time() - strtotime($lastDate)) / 86400) : 999; - $lastStatus = $latest->status ?? 'unknown'; + $daysSince = 999; + + if (!empty($latest->backupstart) && $latest->backupstart !== '0000-00-00 00:00:00') + { + $daysSince = (int) ((time() - strtotime($latest->backupstart)) / 86400); + } $status = 'ok'; - if ($lastStatus !== 'complete') + if ($latest->status === 'fail') { $status = 'degraded'; } + elseif ($latest->status !== 'complete') + { + $status = ($latest->status === 'running') ? 'ok' : 'degraded'; + } elseif ($daysSince > $staleDays) { $status = 'degraded'; } - $sizeMb = !empty($latest->total_size) + $sizeMb = $latest->total_size ? round($latest->total_size / 1048576) : null; return [ - 'installed' => true, - 'status' => $status, - 'last_backup' => $lastDate, - 'last_status' => $lastStatus, - 'last_size_mb' => $sizeMb, - 'days_since' => $daysSince, - 'total_backups' => $totalBackups, - 'recent_7d' => $recentBackups, - 'destination' => $latest->destination ?? null, - 'description' => $latest->description ?? null, + 'installed' => true, + 'status' => $status, + 'last_backup' => $latest->backupstart, + 'last_status' => $latest->status, + 'last_size_mb' => $sizeMb, + 'days_since' => $daysSince, + 'backup_type' => $latest->backup_type, + 'origin' => $latest->origin, + 'total_backups' => $totalBackups, + 'recent_7d' => $recentBackups, + 'fail_count_7d' => $failCount7d, + 'files_exist' => (bool) $latest->filesexist, + 'description' => $latest->description, ]; } }