Failed Conditions
Push — master ( 5fbadf...673c47 )
by Adrien
07:14
created

AbstractDatabase::loadTriggers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 0
cts 3
cp 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Service;
6
7
/**
8
 * Tool to reload the entire local database from remote database for a given site
9
 * Requirements:
10
 * - ssh access to remote server (via ~/.ssh/config)
11
 * - both local and remote sites must be accesible via: /sites/MY_SITE
12
 * - both local and remote config/autoload/local.php files must contains the database connection info
13
 */
14
abstract class AbstractDatabase
15
{
16
    /**
17
     * Dump data from database on $remote server
18
     *
19
     * @param string $remote
20
     * @param string $dumpFile path
21
     */
22
    private static function dumpDataRemotely($remote, $dumpFile): void
23
    {
24
        $sshCmd = <<<STRING
25
        ssh $remote "cd /sites/$remote/ && php7.1 bin/dump-data $dumpFile"
26
STRING;
27
28
        echo "dumping data $dumpFile on $remote...\n";
29
        self::executeLocalCommand($sshCmd);
30
    }
31
32
    /**
33
     * Dump data from database
34
     *
35
     * @param string $dumpFile path
36
     */
37
    public static function dumpData($dumpFile): void
38
    {
39
        $config = require 'config/autoload/local.php';
40
        $dbConfig = $config['doctrine']['connection']['orm_default']['params'];
41
        $host = $dbConfig['host'];
42
        $username = $dbConfig['user'];
43
        $database = $dbConfig['dbname'];
44
        $password = $dbConfig['password'];
45
46
        echo "dumping $dumpFile...\n";
47
        $dumpCmd = "mysqldump -v --user=$username --password=$password --host=$host $database | gzip > $dumpFile";
48
        self::executeLocalCommand($dumpCmd);
49
    }
50
51
    /**
52
     * Copy a file from $remote
53
     *
54
     * @param string $remote
55
     * @param string $dumpFile
56
     */
57
    private static function copyFile($remote, $dumpFile): void
58
    {
59
        $copyCmd = <<<STRING
60
        scp $remote:$dumpFile $dumpFile
61
STRING;
62
63
        echo "copying dump to $dumpFile ...\n";
64
        self::executeLocalCommand($copyCmd);
65
    }
66
67
    /**
68
     * Load SQL dump in local database
69
     *
70
     * @param string $dumpFile
71
     */
72
    public static function loadData($dumpFile): void
73
    {
74
        $config = require 'config/autoload/local.php';
75
        $dbConfig = $config['doctrine']['connection']['orm_default']['params'];
76
        $host = $dbConfig['host'];
77
        $username = $dbConfig['user'];
78
        $database = $dbConfig['dbname'];
79
        $password = $dbConfig['password'];
80
81
        $dumpFile = realpath($dumpFile);
82
        echo "loading dump $dumpFile...\n";
83
        if (!is_readable($dumpFile)) {
84
            throw new \Exception("Cannot read dump file \"$dumpFile\"");
85
        }
86
87
        self::executeLocalCommand(PHP_BINARY . ' ./vendor/bin/doctrine orm:schema-tool:drop --ansi --full-database --force');
88
        self::executeLocalCommand("gunzip -c \"$dumpFile\" | mysql --user=$username --password=$password --host=$host $database");
89
        self::executeLocalCommand(PHP_BINARY . ' ./vendor/bin/doctrine-migrations --ansi migrations:migrate --no-interaction');
90
        self::loadTriggers();
91
    }
92
93
    public static function loadRemoteData($remote): void
94
    {
95
        $dumpFile = "/tmp/$remote." . exec('whoami') . '.backup.sql.gz';
96
        self::dumpDataRemotely($remote, $dumpFile);
97
        self::copyFile($remote, $dumpFile);
98
        self::loadData($dumpFile);
99
100
        echo "database updated\n";
101
    }
102
103
    /**
104
     * Execute a shell command and throw exception if fails
105
     *
106
     * @param string $command
107
     *
108
     * @throws \Exception
109
     */
110
    public static function executeLocalCommand($command): void
111
    {
112
        $return_var = null;
113
        $fullCommand = "$command 2>&1";
114
        passthru($fullCommand, $return_var);
115
        if ($return_var) {
116
            throw new \Exception('FAILED executing: ' . $command);
117
        }
118
    }
119
120
    /**
121
     * Load test data
122
     */
123
    public static function loadTestData(): void
124
    {
125
        self::executeLocalCommand(PHP_BINARY . ' ./vendor/bin/doctrine orm:schema-tool:drop --ansi --full-database --force');
126
        self::executeLocalCommand(PHP_BINARY . ' ./vendor/bin/doctrine-migrations migrations:migrate --ansi --no-interaction');
127
        self::importFile('tests/data/fixture.sql');
128
        self::loadTriggers();
129
    }
130
131
    /**
132
     * Load triggers
133
     */
134
    public static function loadTriggers(): void
135
    {
136
        self::importFile('data/triggers.sql');
137
    }
138
139
    /**
140
     * Import a SQL file into DB
141
     *
142
     * This use mysql command, instead of DBAL methods, to allow to see errors if any, and
143
     * also because it seems trigger creation do not work with DBAL for some unclear reasons.
144
     *
145
     * @param string $file
146
     */
147
    private static function importFile(string $file): void
148
    {
149
        $file = realpath($file);
150
        echo 'importing ' . $file . "\n";
151
        $connection = _em()->getConnection();
152
        $database = $connection->getDatabase();
153
        $username = $connection->getUsername();
154
        $password = empty($connection->getPassword()) ? '' : '-p' . $connection->getPassword();
155
156
        $importCommand = "more $file | mysql -u $username $password $database";
157
158
        self::executeLocalCommand($importCommand);
159
    }
160
}
161