Completed
Push — master ( 3a75ac...d68dc3 )
by Alejandro
23s
created

DatabaseConfigCustomizer::process()   B

Complexity

Conditions 9
Paths 68

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 9

Importance

Changes 0
Metric Value
cc 9
nc 68
nop 2
dl 0
loc 37
rs 7.7724
c 0
b 0
f 0
ccs 22
cts 22
cp 1
crap 9
1
<?php
2
declare(strict_types=1);
3
4
namespace Shlinkio\Shlink\Installer\Config\Plugin;
5
6
use Shlinkio\Shlink\Installer\Model\CustomizableAppConfig;
7
use Shlinkio\Shlink\Installer\Util\AskUtilsTrait;
8
use Symfony\Component\Console\Style\SymfonyStyle;
9
use Symfony\Component\Filesystem\Exception\IOException;
10
use Symfony\Component\Filesystem\Filesystem;
11
use function array_diff;
12
use function array_keys;
13
use function Shlinkio\Shlink\Common\contains;
14
15
class DatabaseConfigCustomizer implements ConfigCustomizerInterface
16
{
17
    use AskUtilsTrait;
18
19
    public const DRIVER = 'DRIVER';
20
    public const NAME = 'NAME';
21
    public const USER = 'USER';
22
    public const PASSWORD = 'PASSWORD';
23
    public const HOST = 'HOST';
24
    public const PORT = 'PORT';
25
    private const DRIVER_DEPENDANT_OPTIONS = [
26
        self::DRIVER,
27
        self::NAME,
28
        self::USER,
29
        self::PASSWORD,
30
        self::HOST,
31
        self::PORT,
32
    ];
33
    private const EXPECTED_KEYS = self::DRIVER_DEPENDANT_OPTIONS; // Same now, but could change in the future
34
35
    private const DATABASE_DRIVERS = [
36
        'MySQL' => 'pdo_mysql',
37
        'PostgreSQL' => 'pdo_pgsql',
38
        'SQLite' => 'pdo_sqlite',
39
    ];
40
41
    /**
42
     * @var Filesystem
43
     */
44
    private $filesystem;
45
46 4
    public function __construct(Filesystem $filesystem)
47
    {
48 4
        $this->filesystem = $filesystem;
49 4
    }
50
51
    /**
52
     * @throws IOException
53
     */
54 4
    public function process(SymfonyStyle $io, CustomizableAppConfig $appConfig): void
55
    {
56 4
        $titlePrinted = false;
57 4
        $db = $appConfig->getDatabase();
58 4
        $doImport = $appConfig->hasDatabase();
59 4
        $keysToAskFor = $doImport ? array_diff(self::EXPECTED_KEYS, array_keys($db)) : self::EXPECTED_KEYS;
60
61
        // If the user selected to keep DB, try to import SQLite database
62 4
        if ($doImport) {
63 3
            $this->importSqliteDbFile($io, $appConfig);
64
        }
65
66 4
        if (empty($keysToAskFor)) {
67 1
            return;
68
        }
69
70
        // If the driver is one of the params to ask for, ask for it first
71 3
        if (contains(self::DRIVER, $keysToAskFor)) {
72 1
            $io->title('DATABASE');
73 1
            $titlePrinted = true;
74 1
            $db[self::DRIVER] = $this->ask($io, self::DRIVER);
75 1
            $keysToAskFor = array_diff($keysToAskFor, [self::DRIVER]);
76
        }
77
78
        // If driver is SQLite, do not ask any driver-dependant option
79 3
        if ($db[self::DRIVER] === self::DATABASE_DRIVERS['SQLite']) {
80 1
            $keysToAskFor = array_diff($keysToAskFor, self::DRIVER_DEPENDANT_OPTIONS);
81
        }
82
83 3
        if (! $titlePrinted && ! empty($keysToAskFor)) {
84 1
            $io->title('DATABASE');
85
        }
86 3
        foreach ($keysToAskFor as $key) {
87 2
            $db[$key] = $this->ask($io, $key, $db);
88
        }
89 3
        $appConfig->setDatabase($db);
90 3
    }
91
92 3
    private function importSqliteDbFile(SymfonyStyle $io, CustomizableAppConfig $appConfig): void
93
    {
94 3
        if ($appConfig->getDatabase()[self::DRIVER] !== self::DATABASE_DRIVERS['SQLite']) {
95 2
            return;
96
        }
97
98
        try {
99 1
            $this->filesystem->copy(
100 1
                $appConfig->getImportedInstallationPath() . '/' . CustomizableAppConfig::SQLITE_DB_PATH,
101 1
                CustomizableAppConfig::SQLITE_DB_PATH
102
            );
103
        } catch (IOException $e) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\Filesystem\Exception\IOException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
104
            $io->error('It wasn\'t possible to import the SQLite database');
105
            throw $e;
106
        }
107 1
    }
108
109 2
    private function ask(SymfonyStyle $io, string $key, array $params = [])
110
    {
111
        switch ($key) {
112 2
            case self::DRIVER:
113 1
                $databases = array_keys(self::DATABASE_DRIVERS);
114 1
                $dbType = $io->choice('Select database type', $databases, $databases[0]);
115 1
                return self::DATABASE_DRIVERS[$dbType];
116 2
            case self::NAME:
117 1
                return $io->ask('Database name', 'shlink');
118 2
            case self::USER:
119 2
                return $this->askRequired($io, 'username', 'Database username');
120 2
            case self::PASSWORD:
121 1
                return $this->askRequired($io, 'password', 'Database password');
122 2
            case self::HOST:
123 2
                return $io->ask('Database host', 'localhost');
124 2
            case self::PORT:
125 2
                return $io->ask('Database port', $this->getDefaultDbPort($params[self::DRIVER]));
126
        }
127
128
        return '';
129
    }
130
131 2
    private function getDefaultDbPort(string $driver): string
132
    {
133 2
        return $driver === 'pdo_mysql' ? '3306' : '5432';
134
    }
135
}
136