447f7b572e
Universal: PR Check / Require Docs Update (pull_request) Has been skipped
Universal: PR Check / Wiki Update Reminder (pull_request) Has been skipped
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Secret Scan (pull_request) Successful in 10s
Universal: PR Check / Validate PR (pull_request) Failing after 14s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 40s
Generic: Project CI / Lint & Validate (pull_request) Successful in 52s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 1m8s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Retention (RetentionManager and the plugin's hourly cleanup) only ever deleted local files; remote archives grew unbounded. Add an idempotent delete() to RemoteUploaderInterface + all four uploaders and have RetentionManager remove each pruned archive from the profile's enabled remotes (best-effort; failures logged). The shared restore.php is left in place since every backup overwrites it. (#229) Consolidate duplicated plumbing (#230): - New RemoteUploaderFactory replaces the createUploaderFromParams copy duplicated in BackupEngine and SteppedBackupEngine. - RetentionManager becomes the single retention authority (global-default fallback + pruneOrphans()); the system plugin delegates to it and its duplicate doCleanup()/deleteBackupRecord() logic is removed. - Backend controller, API controller and legacy cli/mokosuitebackup.php now run through the shared BackupRunner instead of BackupEngine directly. Refs #229 #230 Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
70 lines
2.2 KiB
PHP
70 lines
2.2 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @package MokoSuiteBackup
|
|
* @subpackage com_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
|
|
*/
|
|
|
|
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
/**
|
|
* Builds a remote uploader from a `#__mokosuitebackup_remotes` row.
|
|
*
|
|
* This was previously a private method duplicated in both BackupEngine and
|
|
* SteppedBackupEngine (and needed a third time by RetentionManager for remote
|
|
* deletion). It is centralised here so the type→class map and the param
|
|
* key-prefixing convention live in exactly one place.
|
|
*
|
|
* The remotes table stores per-type settings as a flat JSON object with
|
|
* un-prefixed keys (e.g. `{"host":"…","path":"/backups"}`). The concrete
|
|
* uploaders, however, read prefixed keys off a profile-shaped object
|
|
* (e.g. `sftp_host`, `s3_bucket`). This factory bridges the two.
|
|
*/
|
|
final class RemoteUploaderFactory
|
|
{
|
|
/**
|
|
* Map of remote type → the key prefix its uploader expects.
|
|
*/
|
|
private const PREFIX_MAP = [
|
|
'ftp' => 'ftp_',
|
|
'sftp' => 'sftp_',
|
|
's3' => 's3_',
|
|
'google_drive' => 'gdrive_',
|
|
];
|
|
|
|
/**
|
|
* Create an uploader for the given remote type from decoded JSON params.
|
|
*
|
|
* @param string $type Remote type: ftp, sftp, s3, google_drive
|
|
* @param array $params Key-value params decoded from the remote's JSON
|
|
*
|
|
* @return RemoteUploaderInterface
|
|
*
|
|
* @throws \InvalidArgumentException On an unknown remote type
|
|
*/
|
|
public static function create(string $type, array $params): RemoteUploaderInterface
|
|
{
|
|
$prefix = self::PREFIX_MAP[$type] ?? '';
|
|
$prefixed = [];
|
|
|
|
foreach ($params as $key => $value) {
|
|
$prefixed[$prefix . $key] = $value;
|
|
}
|
|
|
|
$fake = (object) $prefixed;
|
|
|
|
return match ($type) {
|
|
'ftp' => new FtpUploader($fake),
|
|
'sftp' => new SftpUploader($fake),
|
|
'google_drive' => new GoogleDriveUploader($fake),
|
|
's3' => new S3Uploader($fake),
|
|
default => throw new \InvalidArgumentException('Unknown remote storage type: ' . $type),
|
|
};
|
|
}
|
|
}
|