Completed
Push — master ( a36a2e...782846 )
by Sergii
05:45
created

Database::exec()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
c 1
b 1
f 1
dl 0
loc 13
rs 9.4285
cc 1
eloc 7
nc 1
nop 1
1
<?php
2
/**
3
 * @author Sergii Bondarenko, <[email protected]>
4
 */
5
namespace Drupal\TqExtension\Utils\Database;
6
7
// Helpers.
8
use Behat\DebugExtension\Debugger;
9
10
class Database
11
{
12
    use Debugger;
13
14
    /**
15
     * MySQL and MySQLDump login arguments.
16
     *
17
     * @var string
18
     */
19
    private $credentials = '-u%s -p%s -h%s -P%s';
20
    /**
21
     * Name of original database.
22
     *
23
     * @var string
24
     */
25
    private $source = '';
26
    /**
27
     * Name of temporary database that will store data from original.
28
     *
29
     * @var string
30
     */
31
    private $temporary = '';
32
    /**
33
     * Indicates that DB was cloned.
34
     *
35
     * @var bool
36
     */
37
    private $cloned = false;
38
39
    /**
40
     * @param string $connection
41
     *   Database connection name (key in $databases array from settings.php).
42
     */
43
    public function __construct($connection)
44
    {
45
        if (!defined('DRUPAL_ROOT') || !function_exists('conf_path')) {
46
            throw new \RuntimeException('Drupal is not bootstrapped.');
47
        }
48
49
        $databases = [];
50
51
        require sprintf('%s/%s/settings.php', DRUPAL_ROOT, conf_path());
52
53
        if (empty($databases[$connection])) {
54
            throw new \InvalidArgumentException(sprintf('The "%s" database connection does not exist.', $connection));
55
        }
56
57
        $db = $databases[$connection]['default'];
58
59
        foreach (['port' => 3306, 'host' => '127.0.0.1'] as $option => $default) {
60
            if (empty($db[$option])) {
61
                $db[$option] = $default;
62
            }
63
        }
64
65
        self::debug([__CLASS__]);
66
67
        $this->source = $db['database'];
68
        $this->temporary = "tqextension_$this->source";
69
        $this->credentials = sprintf($this->credentials, $db['username'], $db['password'], $db['host'], $db['port']);
70
    }
71
72
    /**
73
     * Clone a database.
74
     */
75
    public function __clone()
76
    {
77
        // Drop and create temporary DB and copy source into it.
78
        $this->copy($this->source, $this->temporary);
79
        $this->cloned = true;
80
    }
81
82
    /**
83
     * Restore original database.
84
     */
85
    public function __destruct()
86
    {
87
        if ($this->cloned) {
88
            // Drop and create source DB and copy temporary into it.
89
            $this->copy($this->temporary, $this->source);
90
            // Kill temporary DB.
91
            $this->drop($this->temporary);
92
        }
93
    }
94
95
    /**
96
     * @param string $name
97
     *   Name of the database to check.
98
     *
99
     * @return bool
100
     *   Checking state.
101
     */
102
    public function exist($name)
103
    {
104
        return !empty($this->exec("mysql -e 'show databases' | grep '^$name$'"));
105
    }
106
107
    /**
108
     * @param string $name
109
     *   Name of the database to drop.
110
     */
111
    public function drop($name)
112
    {
113
        if ($this->exist($name)) {
114
            $this->exec("mysql -e '%s database $name;'", __FUNCTION__);
115
        }
116
    }
117
118
    /**
119
     * @param string $name
120
     *   Name of the database to create.
121
     */
122
    public function create($name)
123
    {
124
        if (!$this->exist($name)) {
125
            $this->exec("mysql -e '%s database $name;'", __FUNCTION__);
126
        }
127
    }
128
129
    /**
130
     * @param string $source
131
     *   Source DB name.
132
     * @param string $destination
133
     *   Name of the new DB.
134
     */
135
    public function copy($source, $destination)
136
    {
137
        $this->drop($destination);
138
        $this->create($destination);
139
        $this->exec("mysqldump $source | mysql $destination");
140
    }
141
142
    /**
143
     * Executes a shell command.
144
     *
145
     * @param string $command
146
     *   Command to execute.
147
     *
148
     * @return string
149
     *   Result of a shell command.
150
     */
151
    private function exec($command)
152
    {
153
        // Adding credentials after "mysql" and "mysqldump" commands.
154
        $command = preg_replace(
155
            '/(mysql(?:dump)?)/',
156
            "\\1 $this->credentials",
157
            vsprintf($command, array_slice(func_get_args(), 1))
158
        );
159
160
        self::debug(['%s'], [$command]);
161
162
        return trim(shell_exec($command));
163
    }
164
}
165