* @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), }; } }