<?php
|
declare(strict_types=1);
|
|
namespace App\Command;
|
|
use App\LegacyImport\CoverImporter;
|
use App\LegacyImport\CoverImportReport;
|
use App\LegacyImport\ImportReport;
|
use App\LegacyImport\LegacyImporter;
|
use Symfony\Component\Console\Attribute\AsCommand;
|
use Symfony\Component\Console\Attribute\Option;
|
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
|
#[AsCommand(
|
name: 'app:import-legacy',
|
description: 'Imports books and covers from the old database schema',
|
help: <<<'HELP'
|
Reads the <info>ksiazki</info>, <info>pozycz</info> and <info>pozycz_historia</info> tables from the database at
|
<info>LEGACY_DATABASE_URL</info> and writes them to the database at <info>DATABASE_URL</info>.
|
|
Books already in the target, by ID, are kept as they are along with their loans, so the import can
|
be run again to pick up books added to the legacy database since. Rows the new schema cannot hold
|
are left out and listed in the output.
|
|
Use <info>--dry-run</info> to run the whole import and roll it back.
|
|
With <info>--covers=DIR</info>, legacy cover files in <info>DIR</info> are attached to the books already
|
in the target database.
|
HELP,
|
)]
|
class ImportLegacyCommand {
|
public function __construct(
|
private readonly LegacyImporter $importer,
|
private readonly CoverImporter $coverImporter,
|
) {
|
}
|
|
public function __invoke(
|
SymfonyStyle $io,
|
#[Option('Run the import, then roll it back')] bool $dryRun = false,
|
#[Option('Import the cover files from directory into the existing books')] ?string $covers = null,
|
): int {
|
$this->import($io, $dryRun);
|
|
if ($covers !== null) {
|
$this->importCovers($io, $covers, $dryRun);
|
}
|
|
return Command::SUCCESS;
|
}
|
|
private function import(SymfonyStyle $io, bool $dryRun): void {
|
$report = $this->importer->import($dryRun);
|
$this->printReport($io, $report);
|
$io->success($dryRun ? 'Dry run finished; nothing was saved.' : 'Import finished.');
|
}
|
|
private function printReport(SymfonyStyle $io, ImportReport $report): void {
|
$io->table(['Target table', 'Rows'], [
|
['book', $report->books],
|
['ousted_book', $report->oustedBooks],
|
['borrow', $report->borrows],
|
['borrow_history', $report->borrowHistory],
|
['ousted_borrow_history', $report->oustedBorrowHistory],
|
['already in target, kept', $report->alreadyPresent],
|
]);
|
|
if ($report->invalidIsbns) {
|
$io->warning(\sprintf('%d numbers are not valid ISBNs and were kept as text labels:', \count($report->invalidIsbns)));
|
$io->listing($report->invalidIsbns);
|
}
|
|
if ($report->skipped) {
|
$io->warning(\sprintf('%d rows were left out:', \count($report->skipped)));
|
$io->listing($report->skipped);
|
}
|
}
|
|
private function importCovers(SymfonyStyle $io, string $directory, bool $dryRun): void {
|
$report = $this->coverImporter->import($directory, $dryRun);
|
$this->printCoverReport($io, $report);
|
$io->success($dryRun ? 'Dry run finished; nothing was saved.' : \sprintf('%d covers imported.', $report->imported()));
|
}
|
|
private function printCoverReport(SymfonyStyle $io, CoverImportReport $report): void {
|
$io->table(['Source', 'Books'], [
|
['own/, by book ID', $report->ownById],
|
['own/, by ISBN', $report->ownByIsbn],
|
['by ISBN', $report->byIsbn],
|
['already had a cover, kept', $report->alreadyCovered],
|
]);
|
|
if ($report->failed) {
|
$io->warning(\sprintf('%d files could not be imported:', \count($report->failed)));
|
$io->listing($report->failed);
|
}
|
|
if ($report->unmatched) {
|
$io->note(\sprintf('%d files match no book:', \count($report->unmatched)));
|
$io->listing($report->unmatched);
|
}
|
|
if ($report->ignored) {
|
$io->note(\sprintf('%d files are named neither by ISBN-13 nor by book ID, and were ignored:', \count($report->ignored)));
|
$io->listing($report->ignored);
|
}
|
}
|
}
|