Files
MokoSuiteBackup/source/packages/plg_task_mokosuitebackup/src/Extension/MokoSuiteBackupTask.php
T
jmiller 307067580c feat: BackupRunner helper — unify backup run/status/notification
Every non-interactive backup trigger used a slightly different path, so
final status and notification gating behaved inconsistently depending on
what started the backup (this is why pre-update backups did not gate
notifications the way "Backup Now" does).

Add src/Service/BackupRunner.php as the single synchronous entry point.
It delegates to BackupEngine (which already sends notifications gated by
the profile's notify_on_success/notify_on_failure and applies retention —
so there is exactly ONE notification layer), and normalises the result,
including the real complete/warning/fail status the engine records but did
not return. BackupRunner self-loads BackupEngine so callers require one file.

Routed through BackupRunner:
- plg_system  runPreActionBackup() (preaction) + web-cron handler (webcron)
- plg_content triggerAutoBackup() (pre-install)
- plg_task    scheduled task run
- plg_console RunCommand (cli)

The dashboard AJAX/stepped "Backup Now" flow is unchanged (it is the
interactive equivalent). The installer progress popup is deferred — the
installer request cannot drive the AJAX modal (TODO(#196) noted in code).

php -l clean on all changed files.

Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
2026-07-05 17:28:59 -05:00

149 lines
4.7 KiB
PHP

<?php
/**
* @package MokoSuiteBackup
* @subpackage plg_task_mokosuitebackup
* @author Moko Consulting <hello@mokoconsulting.tech>
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*
* Joomla Scheduled Task plugin for MokoSuiteBackup.
*
* Registers a "Run Backup Profile" task type with com_scheduler.
* Admins can create multiple scheduled tasks in System > Scheduled Tasks,
* each pointing to a different backup profile — just like Akeeba Backup Pro.
*/
namespace Joomla\Plugin\Task\MokoSuiteBackup\Extension;
defined('_JEXEC') or die;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Component\Scheduler\Administrator\Event\ExecuteTaskEvent;
use Joomla\Component\Scheduler\Administrator\Task\Status;
use Joomla\Component\Scheduler\Administrator\Traits\TaskPluginTrait;
use Joomla\Event\Event;
use Joomla\Event\SubscriberInterface;
final class MokoSuiteBackupTask extends CMSPlugin implements SubscriberInterface
{
use TaskPluginTrait;
protected $autoloadLanguage = true;
/**
* Task map — each entry registers a task type in System > Scheduled Tasks.
*
* The admin can create multiple task instances, each with its own profile_id,
* so different backup profiles run on different schedules.
*/
protected const TASKS_MAP = [
'mokosuitebackup.run_profile' => [
'langConstPrefix' => 'PLG_TASK_MOKOJOOMBACKUP_TASK_RUN_PROFILE',
'method' => 'runBackupProfile',
'form' => 'run_profile',
],
'mokosuitebackup.snapshot' => [
'langConstPrefix' => 'PLG_TASK_MOKOJOOMBACKUP_TASK_RUN_SNAPSHOT',
'method' => 'runContentSnapshot',
'form' => 'run_snapshot',
],
];
public static function getSubscribedEvents(): array
{
return [
'onTaskOptionsList' => 'advertiseRoutines',
'onExecuteTask' => 'standardRoutineHandler',
'onContentPrepareForm' => 'enhanceTaskItemForm',
];
}
/**
* Execute a backup using the profile selected in the scheduled task.
*
* @param ExecuteTaskEvent $event The task execution event
*
* @return int Status::OK on success, Status::KNOCKOUT on failure
*/
private function runBackupProfile(ExecuteTaskEvent $event): int
{
$params = $event->getArgument('params');
$profileId = (int) ($params->profile_id ?? 1);
// Load the backup engine from the component
$engineFile = JPATH_ADMINISTRATOR . '/components/com_mokosuitebackup/src/Service/BackupRunner.php';
if (!file_exists($engineFile)) {
$this->logTask('MokoSuiteBackup component not installed — cannot run backup.');
return Status::KNOCKOUT;
}
// The autoloader should handle this via namespace, but ensure class is available
if (!class_exists('\\Joomla\\Component\\MokoSuiteBackup\\Administrator\\Service\\BackupRunner')) {
require_once $engineFile;
}
$engine = new \Joomla\Component\MokoSuiteBackup\Administrator\Service\BackupRunner();
$result = $engine->run($profileId, 'Scheduled task backup', 'scheduled');
if ($result['success']) {
$this->logTask('Backup complete: ' . $result['message']);
return Status::OK;
}
$this->logTask('Backup failed: ' . $result['message']);
return Status::KNOCKOUT;
}
/**
* Create a content snapshot using the configured content types.
*
* @param ExecuteTaskEvent $event The task execution event
*
* @return int Status::OK on success, Status::KNOCKOUT on failure
*/
private function runContentSnapshot(ExecuteTaskEvent $event): int
{
$params = $event->getArgument('params');
$contentTypes = (array) ($params->content_types ?? ['articles', 'categories', 'modules']);
$descFormat = (string) ($params->description_format ?? '[date] Scheduled snapshot');
// Resolve placeholders in the description
$description = str_replace(
['[date]', '[datetime]'],
[date('Y-m-d'), date('Y-m-d H:i:s')],
$descFormat
);
// Load the snapshot engine from the component
$engineFile = JPATH_ADMINISTRATOR . '/components/com_mokosuitebackup/src/Engine/SnapshotEngine.php';
if (!file_exists($engineFile)) {
$this->logTask('MokoSuiteBackup component not installed — cannot create snapshot.');
return Status::KNOCKOUT;
}
if (!class_exists('\\Joomla\\Component\\MokoSuiteBackup\\Administrator\\Engine\\SnapshotEngine')) {
require_once $engineFile;
}
$engine = new \Joomla\Component\MokoSuiteBackup\Administrator\Engine\SnapshotEngine();
$result = $engine->create($contentTypes, $description);
if ($result['success']) {
$this->logTask('Snapshot complete: ' . $result['message']);
return Status::OK;
}
$this->logTask('Snapshot failed: ' . $result['message']);
return Status::KNOCKOUT;
}
}