138 lines
4.9 KiB
PHP
138 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class ImportLegacyFavourites extends Command
|
|
{
|
|
/**
|
|
* The name and signature of the console command.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $signature = 'import:legacy-favourites
|
|
{--connection=legacy : Legacy DB connection name}
|
|
{--table=favourites : Legacy favourites table name}
|
|
{--id-column=id : ID column to use for chunking}
|
|
{--map-user=user_id : Column name for user id}
|
|
{--map-artwork=artwork_id : Column name for artwork id}
|
|
{--map-created=datum : Column name for created timestamp}
|
|
{--chunk=500 : Chunk size}';
|
|
|
|
/**
|
|
* The console command description.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $description = 'Copy legacy favourites (from another DB connection) into user_favorites';
|
|
|
|
public function handle(): int
|
|
{
|
|
$connection = $this->option('connection');
|
|
$table = $this->option('table');
|
|
$idColumn = $this->option('id-column');
|
|
$mapUser = $this->option('map-user');
|
|
$mapArtwork = $this->option('map-artwork');
|
|
$mapCreated = $this->option('map-created');
|
|
$chunk = (int) $this->option('chunk');
|
|
|
|
$this->info("Using connection='{$connection}', table='{$table}', idColumn='{$idColumn}'");
|
|
|
|
try {
|
|
$legacy = DB::connection($connection);
|
|
} catch (\Throwable $e) {
|
|
$this->error('Cannot connect to legacy connection: '.$e->getMessage());
|
|
return 1;
|
|
}
|
|
|
|
try {
|
|
$schema = $legacy->getSchemaBuilder();
|
|
} catch (\Throwable $e) {
|
|
$this->error('Failed to get schema builder for legacy connection: '.$e->getMessage());
|
|
return 1;
|
|
}
|
|
|
|
if (! $schema->hasTable($table)) {
|
|
$this->error("Table '{$table}' does not exist on connection '{$connection}'");
|
|
return 1;
|
|
}
|
|
|
|
$this->info('Starting import...');
|
|
|
|
$attempted = 0;
|
|
$inserted = 0;
|
|
|
|
// Try chunkById for efficient processing; fallback to cursor if id column missing
|
|
try {
|
|
$legacy->table($table)
|
|
->select([$idColumn, $mapUser, $mapArtwork, $mapCreated])
|
|
->orderBy($idColumn)
|
|
->chunkById($chunk, function ($rows) use (&$attempted, &$inserted, $mapUser, $mapArtwork, $mapCreated) {
|
|
$batch = [];
|
|
foreach ($rows as $r) {
|
|
$attempted++;
|
|
$batch[] = [
|
|
'user_id' => $r->{$mapUser},
|
|
'artwork_id' => $r->{$mapArtwork},
|
|
'created_at' => $r->{$mapCreated} ?? now(),
|
|
];
|
|
}
|
|
|
|
if (count($batch) > 0) {
|
|
$res = DB::table('user_favorites')->insertOrIgnore($batch);
|
|
// insertOrIgnore may return number inserted on some drivers; approximate otherwise
|
|
if (is_int($res)) {
|
|
$inserted += $res;
|
|
} else {
|
|
$inserted += count($batch);
|
|
}
|
|
}
|
|
|
|
$this->info("Processed {$attempted} rows, approx inserted {$inserted}");
|
|
});
|
|
} catch (\Throwable $e) {
|
|
$this->warn('chunkById failed, falling back to cursor: '.$e->getMessage());
|
|
|
|
$cursor = $legacy->table($table)
|
|
->select([$mapUser, $mapArtwork, $mapCreated])
|
|
->orderBy($mapCreated)
|
|
->cursor();
|
|
|
|
$batch = [];
|
|
foreach ($cursor as $r) {
|
|
$attempted++;
|
|
$batch[] = [
|
|
'user_id' => $r->{$mapUser},
|
|
'artwork_id' => $r->{$mapArtwork},
|
|
'created_at' => $r->{$mapCreated} ?? now(),
|
|
];
|
|
|
|
if (count($batch) >= $chunk) {
|
|
$res = DB::table('user_favorites')->insertOrIgnore($batch);
|
|
if (is_int($res)) {
|
|
$inserted += $res;
|
|
} else {
|
|
$inserted += count($batch);
|
|
}
|
|
$this->info("Processed {$attempted} rows, approx inserted {$inserted}");
|
|
$batch = [];
|
|
}
|
|
}
|
|
|
|
if (count($batch) > 0) {
|
|
$res = DB::table('user_favorites')->insertOrIgnore($batch);
|
|
if (is_int($res)) {
|
|
$inserted += $res;
|
|
} else {
|
|
$inserted += count($batch);
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->info("Import complete. Attempted {$attempted}, approx inserted {$inserted}.");
|
|
return 0;
|
|
}
|
|
}
|