Skip to content

Commit

Permalink
Command to migrate attachments from one disk to another
Browse files Browse the repository at this point in the history
  • Loading branch information
gabsource committed Aug 20, 2021
1 parent d3f4aa0 commit 246a7bc
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 2 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,14 @@ A command is provided to cleanup the attachments not bound to a model
The `-s` (or `--since=[timeInMinutes]`) option can be set to specify
another time limit in minutes : only unbound files older than the
specified age will be deleted. This value is set to **1440** by default.

## Migrate command

To migrate **all** attachments from one source disk to another :

php artisan attachments:migrate public s3

Files are removed from source disk if successfully saved on the target disk.

## Customization

Expand Down
2 changes: 2 additions & 0 deletions src/AttachmentsServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Bnb\Laravel\Attachments;

use Bnb\Laravel\Attachments\Console\Commands\CleanupAttachments;
use Bnb\Laravel\Attachments\Console\Commands\MigrateAttachments;
use Illuminate\Support\ServiceProvider;

class AttachmentsServiceProvider extends ServiceProvider
Expand Down Expand Up @@ -31,6 +32,7 @@ public function boot()
if ($this->app->runningInConsole()) {
$this->commands([
CleanupAttachments::class,
MigrateAttachments::class,
]);
}
}
Expand Down
155 changes: 155 additions & 0 deletions src/Console/Commands/MigrateAttachments.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<?php
/**
* laravel
*
* @author Jérémy GAULIN <[email protected]>
* @copyright 2017 - B&B Web Expertise
*/

namespace Bnb\Laravel\Attachments\Console\Commands;

use Bnb\Laravel\Attachments\Attachment;
use Carbon\Carbon;
use Exception;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;
use Lang;
use Log;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Throwable;

class MigrateAttachments extends Command
{

protected $signature = 'attachments:migrate';


public function __construct()
{
parent::__construct();

$this->setDescription(Lang::get('attachments::messages.console.migrate_description'));

$this->getDefinition()->addArgument(new InputArgument('from', InputArgument::REQUIRED,
Lang::get('attachments::messages.console.migrate_option_from')))
;

$this->getDefinition()->addArgument(new InputArgument('to', InputArgument::REQUIRED,
Lang::get('attachments::messages.console.migrate_option_to')))
;
}


public function handle()
{
if ($this->argument('from') === $this->argument('to')) {
$this->error(Lang::get('attachments::messages.console.migrate_error_missing'));

return;
}

if (empty(config(sprintf('filesystems.disks.%s', $this->argument('from'))))) {
$this->error(Lang::get('attachments::messages.console.migrate_error_from'));

return;
}

if (empty(config(sprintf('filesystems.disks.%s', $this->argument('to'))))) {
$this->error(Lang::get('attachments::messages.console.migrate_error_to'));

return;
}

try {
Storage::disk($this->argument('from'))
->has('.')
;
} catch (Exception $e) {
$this->error(Lang::get('attachments::messages.console.migrate_invalid_from'));
}
try {

Storage::disk($this->argument('to'))
->has('.')
;
} catch (Exception $e) {
$this->error(Lang::get('attachments::messages.console.migrate_invalid_to'));
}

$query = Attachment::query()
->where('disk', '=', $this->argument('from'));

$this
->getOutput()
->progressStart($query->count())
;

do {
$deferred = [];
$continue = true;

try {
$items = $query
->take(10)
->get()
->each(function (Attachment $attachment) use (&$deferred) {
if ($this->move($attachment, $deferred)) {
$attachment->disk = $this->argument('to');

$attachment->save();
}

$this
->getOutput()
->progressAdvance()
;
});
} catch (Exception $e) {
$continue = false;

$this->error($e->getMessage());
Log::error($e);
}

foreach ($deferred as $callable) {
try {
$callable();
} catch (Exception | Throwable $e) {
$this->warn(sprintf('Failed to clean source file : %s', $e->getMessage()));
Log::error($e);
}
}
} while ($continue && $items->isNotEmpty());

$this
->getOutput()
->progressFinish()
;
}


private function move(Attachment $attachment, &$deferred)
{
$from = $attachment->disk;
$to = $this->argument('to');
$filepath = $attachment->filepath;

if ( ! Storage::disk($from)->exists($filepath)) {
return true;
}

Storage::disk($to)
->put($filepath, Storage::disk($from)->get($filepath))
;

$deferred[] = function () use ($from, $filepath) {
Storage::disk($from)
->delete($filepath)
;
};

return true;
}
}
10 changes: 9 additions & 1 deletion translations/en/messages.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,13 @@
'cleanup_confirm' => 'Do you confirm the deletion of unbound attachments ?',
'cleanup_option_since' => 'Minimum age (in minutes) of the attachment to delete (based on modification date).',
'cleanup_no_data' => 'No attachment to handle.',
'migrate_description' => 'Migrate attachments from given disk to another keeping path.',
'migrate_option_from' => 'Source disk.',
'migrate_option_to' => 'Destination disk.',
'migrate_error_missing' => 'Cannot not migrate to the same disk.',
'migrate_error_from' => 'Unknown source disk.',
'migrate_error_to' => 'Unknown target disk.',
'migrate_invalid_from' => 'Unreadable source disk.',
'migrate_invalid_to' => 'Unreadable destination disk.',
],
];
];
10 changes: 9 additions & 1 deletion translations/fr/messages.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,13 @@
'cleanup_confirm' => 'Confirmez-vous vouloir supprimer les pièces jointes non liées à un modèle ?',
'cleanup_option_since' => 'Âge minimum (en minutes) des données à supprimer (se base sur la date de modification).',
'cleanup_no_data' => 'Aucune pièce jointe à traiter.',
'migrate_description' => 'Migre les pièces jointes d’un disque donné vers un autre en conservant le chemin.',
'migrate_option_from' => 'Disque d’origine.',
'migrate_option_to' => 'Disque de destination.',
'migrate_error_missing' => 'Impossible de migrer vers le même disque.',
'migrate_error_from' => 'Disque d’origine inconnu.',
'migrate_error_to' => 'Disque de destination inconnu.',
'migrate_invalid_from' => 'Disque d’origine illisible.',
'migrate_invalid_to' => 'Disque de destination illisible.',
],
];
];

0 comments on commit 246a7bc

Please sign in to comment.