PDO::multi()   B
last analyzed

Complexity

Conditions 5
Paths 4

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 4
nop 2
dl 0
loc 19
ccs 11
cts 11
cp 1
crap 5
rs 8.8571
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
/*
5
 +-----------------------------------------------------------------------------+
6
 | PHPPackage - PDO Wrapper
7
 +-----------------------------------------------------------------------------+
8
 | Copyright (c)2018 (http://github.com/phppackage/pdo-wrapper)
9
 +-----------------------------------------------------------------------------+
10
 | This source file is subject to MIT License
11
 | that is bundled with this package in the file LICENSE.
12
 |
13
 | If you did not receive a copy of the license and are unable to
14
 | obtain it through the world-wide-web, please send an email
15
 | to [email protected] so we can send you a copy immediately.
16
 +-----------------------------------------------------------------------------+
17
 | Authors:
18
 |   Lawrence Cherone <[email protected]>
19
 +-----------------------------------------------------------------------------+
20
 */
21
22
namespace PHPPackage\PDOWrapper;
23
24
class PDO extends \PDO
25
{
26
    /**
27
     * @var string
28
     */
29
    private $dsn;
30
    private $username;
31
    private $password;
32
33
    /**
34
     * @var array Default options for database connection.
35
     */
36
    private $options = array(
37
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
38
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
39
        PDO::ATTR_EMULATE_PREPARES   => false
40
    );
41
42
    /**
43
     * PDO construct, defaults to tmp sqlite file if no arguments are passed.
44
     *
45
     * @param string $dsn
46
     * @param string $username
47
     * @param string $password
48
     * @param array  $options
49
     */
50 21
    public function __construct(
51
        string $dsn = null,
52
        string $username = null,
53
        string $password = null,
54
        array  $options = []
55
    ) {
56 21
        $this->dsn = $dsn;
57 21
        $this->username = $username;
58 21
        $this->password = $password;
59 21
        $this->options = $options+$this->options;
60
61 21
        if (is_null($this->dsn)) {
62 13
            $this->dsn = 'sqlite:/'.sys_get_temp_dir().'/PDOWrapper.db';
63
        }
64
65 21
        parent::__construct($this->dsn, $this->username, $this->password, $this->options);
66 21
    }
67
68
    /**
69
     * Get database name from dsn
70
     *
71
     * @throws RuntimeException
72
     * @return string
73
     */
74 4
    public function getDatabaseName(): string
75
    {
76 4
        return (new Database($this))->name($this->dsn);
77
    }
78
79
    /**
80
     * Create database
81
     *
82
     * @return bool
83
     */
84 1
    public function createDatabase(string $name): bool
85
    {
86 1
        return (new Database($this))->create($name, $this->username, $this->password);
87
    }
88
    
89
    /**
90
     * Returns an array of databases
91
     * @return mixed
92
     */
93 2
    public function databases(): array
94
    {
95 2
        return (new Database($this))->databases();
96
    }
97
98
    /**
99
     * Enumarate PDO attributes
100
     *
101
     * @param string $key Pick out a attribute by key
102
     * @return mixed
103
     */
104 6
    public function info(string $key = null)
105
    {
106 6
        return (new Database($this))->info($key);
107
    }
108
109
    /**
110
     * Returns an array of tables
111
     * @return array
112
     */
113 1
    public function tables(): array
114
    {
115 1
        return (new Database($this))->tables();
116
    }
117
118
    /**
119
     * Run query and return PDOStatement or row_count
120
     *
121
     * @param string $sql
122
     * @param array  $values
123
     * @throws InvalidArgumentException
124
     * @return mixed
125
     */
126 4
    public function run(string $sql, array $values = [])
127
    {
128 4
        if (empty($sql)) {
129 1
            throw new \InvalidArgumentException('1st argument cannot be empty');
130
        }
131
132 4
        if (empty($values)) {
133 3
            return $this->query($sql);
134
        }
135
136 3
        if (!is_array($values[0])) {
137 3
            $stmt = $this->prepare($sql);
138 3
            $stmt->execute($values);
139 3
            return $stmt;
140
        }
141
142 1
        return $this->multi($sql, $values);
143
    }
144
145
    /**
146
     * Execute multiple querys which returns row count
147
     *
148
     * @param string $sql
149
     * @param array  $values
150
     * @throws InvalidArgumentException
151
     * @return int
152
     */
153 2
    public function multi(string $sql, array $values = []): int
154
    {
155 2
        if (empty($sql)) {
156 1
            throw new \InvalidArgumentException('1st argument cannot be empty');
157
        }
158
159 2
        if (empty($values[0]) || !is_array($values[0])) {
160 1
            throw new \InvalidArgumentException('2nd argument must be an array of arrays');
161
        }
162
163 2
        $stmt = $this->prepare($sql);
164
165 2
        $row_count = 0;
166 2
        foreach ($values as $value) {
167 2
            $stmt->execute($value);
168 2
            $row_count += $stmt->rowCount();
169
        }
170
171 2
        return $row_count;
172
    }
173
174
    /**
175
     * Return all rows in result set
176
     *
177
     * @param string $sql
178
     * @param array  $values
179
     * @return array
180
     */
181 1
    public function all(string $sql, array $values = []): array
182
    {
183 1
        return $this->run($sql, $values)->fetchAll();
184
    }
185
    
186
    /**
187
     * Return first row in result set
188
     *
189
     * @param string $sql
190
     * @param array  $values
191
     * @return array
192
     */
193 1
    public function row(string $sql, array $values = []): array
194
    {
195 1
        return $this->run($sql, $values)->fetch();
196
    }
197
    
198
    /**
199
     * Return first column cell in result set
200
     *
201
     * @param string $sql
202
     * @param array  $values
203
     * @return array
204
     */
205 1
    public function cell(string $sql, array $values = []): string
206
    {
207 1
        return $this->run($sql, $values)->fetchColumn();
208
    }
209
210
    /**
211
     * Checks system requirements for import/export methods
212
     *  - Supports only mySQL
213
     *
214
     * @param string $method
215
     * @throws RuntimeException
216
     * @return void
217
     */
218 5
    private function checkImportExportRequirements(string $method)
219
    {
220 5
        if ($this->info('DRIVER_NAME') !== 'mysql') {
221 1
            new \RuntimeException('Driver not supported for '.$method.'()');
222
        }
223
224 5
        if (!function_exists('shell_exec')) {
225 1
            new \RuntimeException('shell_exec must be enabled for '.$method.'()');
226
        }
227
228 5
        if (empty(shell_exec('which gzip'))) {
229 1
            new \RuntimeException('gzip must be installed to use '.$method.'()');
230
        }
231
232 5
        if (empty(shell_exec('which zcat'))) {
233 1
            new \RuntimeException('zcat must be installed to use '.$method.'()');
234
        }
235
236 5
        if (empty(shell_exec('which mysqldump'))) {
237 1
            new \RuntimeException('mysqldump must be installed to use '.$method.'()');
238
        }
239 5
    }
240
241
    /**
242
     * Import database (using )
243
     *
244
     * @param string $file
245
     * @param bool   $backup Do backup before import
246
     * @throws RuntimeException
247
     * @return bool
248
     */
249 2
    public function import(string $file, bool $backup = true)
250
    {
251 2
        $this->checkImportExportRequirements('import');
252
253 2
        if (!file_exists($file)) {
254 1
            throw new \DomainException('Import file does not exist');
255
        }
256
257
        // set working vars
258 1
        $database = $this->getDatabaseName();
259 1
        $dir = dirname($file);
260
261
        // backup current
262 1
        if ($backup) {
263 1
            $this->export($dir);
264
        }
265
266
        // restore
267 1
        `zcat {$dir}/{$file} | mysql --user={$this->username} --password={$this->password} {$database}`;
268
269 1
        return true;
270
    }
271
272
    /**
273
     * Export database using mysqldump
274
     *
275
     * @param string $destination Directory to store database exports
276
     * @throws DomainException
277
     * @return string
278
     */
279 3
    public function export($destination = './'): string
280
    {
281 3
        $this->checkImportExportRequirements('export');
282
283 3
        if (!is_dir($destination)) {
284 1
            throw new \DomainException('Export destination must be a directory');
285
        }
286
287
        // set working vars
288 2
        $database = $this->getDatabaseName();
289 2
        $date = date_create()->format('Y-m-d_H:i:s');
290 2
        $destination = rtrim($destination, '/');
291
292 2
        `mysqldump --add-drop-table --user={$this->username} --password={$this->password} --host=127.0.0.1 {$database} | gzip > {$destination}/{$date}.sql.gz &`;
293
294 2
        return $destination.'/'.$date.'.sql.gz';
295
    }
296
297
298
    /**
299
     * Magic caller, so can return a BadMethodCallException
300
     *
301
     * @param string $method
302
     * @param array  $arguments
303
     * @throws BadMethodCallException
304
     * @return mixed
305
     */
306 1
    public function __call($method, $arguments)
307
    {
308 1
        if (!method_exists($this, $method)) {
309 1
            throw new \BadMethodCallException('Call to undefined method '.__CLASS__.'::'.$method.'()');
310
        }
311
312
        // @codeCoverageIgnoreStart
313
        return $this->{$method}(...$arguments);
314
        // @codeCoverageIgnoreEnd
315
    }
316
}
317