Jacek Kowalski
4 hours ago 6b9278a5d57091fce636dbb640b380cfb990db6c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<?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);
        }
    }
}