Completed
Branch master (c7fd68)
by Gaetano
06:59
created

NativeClient::resultSetToArray()   B

Complexity

Conditions 9
Paths 10

Size

Total Lines 41
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 33
dl 0
loc 41
rs 8.0555
c 0
b 0
f 0
cc 9
nc 10
nop 1
1
<?php
2
0 ignored issues
show
Coding Style introduced by
Missing file doc comment
Loading history...
3
namespace Db3v4l\Core\SqlExecutor\Forked;
4
5
use Db3v4l\API\Interfaces\SqlExecutor\Forked\CommandExecutor;
6
use Db3v4l\API\Interfaces\SqlExecutor\Forked\FileExecutor;
7
use Db3v4l\API\Interfaces\SqlExecutor\Forked\ShellExecutor;
8
use Db3v4l\Util\Process;
9
10
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
11
 * @todo allow to inject path of db clients via setter/constructor
12
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
13
class NativeClient extends ForkedExecutor implements CommandExecutor, FileExecutor, ShellExecutor
14
{
15
    const EXECUTE_COMMAND = 0;
16
    const EXECUTE_FILE = 1;
17
    const EXECUTE_SHELL = 2;
18
19
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
20
     * @param string $sql
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
21
     * @return Process
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
22
     */
23
    public function getExecuteStatementProcess($sql)
24
    {
25
        return $this->getProcess($sql, self::EXECUTE_COMMAND);
26
    }
27
28
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
29
     * @param string $filename
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
30
     * @return Process
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
31
     */
32
    public function getExecuteFileProcess($filename)
33
    {
34
        return $this->getProcess($filename, self::EXECUTE_FILE);
35
    }
36
37
    public function getExecuteShellProcess()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getExecuteShellProcess()
Loading history...
38
    {
39
        return $this->getProcess(null, self::EXECUTE_SHELL);
40
    }
41
42
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
43
     * @param string $sqlOrFilename
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
44
     * @param int $action
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
45
     * @return Process
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
46
     */
47
    protected function getProcess($sqlOrFilename, $action = self::EXECUTE_COMMAND)
48
    {
49
        $clientType = $this->getDbClientType($this->databaseConfiguration);
50
51
        // pass on _all_ env vars, including PATH. Not doing so is deprecated...
52
        $env = null;
53
54
        switch ($clientType) {
55
            case 'mysql':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
56
                $command = 'mysql';
57
                $options = [
58
                    '--host=' . $this->databaseConfiguration['host'],
59
                    '--port=' . $this->databaseConfiguration['port'] ?? '3306',
60
                    '--user=' . $this->databaseConfiguration['user'],
61
                    '-p' . $this->databaseConfiguration['password'],
62
                    '--binary-mode', // 'It also disables all mysql commands except charset and delimiter in non-interactive mode (for input piped to mysql or loaded using the source command)'
63
                    '-t',
64
                ];
65
                if (isset($this->databaseConfiguration['dbname'])) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
66
                    $options[] = $this->databaseConfiguration['dbname'];
67
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
68
                if ($action == self::EXECUTE_COMMAND) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
69
                    $options[] = '--execute=' . $sqlOrFilename;
70
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
71
               // $env = [
72
                    // problematic when wrapping the process in a call to `time`...
73
                    //'MYSQL_PWD' => $this->databaseConfiguration['password'],
74
                //];
75
                break;
76
77
            case 'psql':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
78
                $command = 'psql';
79
                $connectString = "postgresql://".$this->databaseConfiguration['user'].":".$this->databaseConfiguration['password'].
80
                    "@{$this->databaseConfiguration['host']}:".($this->databaseConfiguration['port'] ?? '5432').'/';
81
                if (isset($this->databaseConfiguration['dbname'])) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
82
                    $connectString .= $this->databaseConfiguration['dbname'];
83
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
84
                $options = [
85
                    $connectString,
86
                    '-Pfooter=off'
87
                ];
88
                // NB: this triggers a different behaviour that piping multiple commands to stdin, namely
89
                // it wraps all of the commands in a transaction and allows either sql commands or a single meta-command
90
                if ($action == self::EXECUTE_COMMAND) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
91
                    $options[] = '--command=' . $sqlOrFilename;
92
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
93
                //$env = [
94
                    // problematic when wrapping the process in a call to `time`...
95
                    //'PGPASSWORD' => $this->databaseConfiguration['password'],
96
                //];
97
                break;
98
99
            case 'sqlcmd':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
100
                $command = 'sqlcmd';
101
                $options = [
102
                    '-S' . $this->databaseConfiguration['host'] . ($this->databaseConfiguration['port'] != '' ?  ',' . $this->databaseConfiguration['port'] : ''),
103
                    '-U' . $this->databaseConfiguration['user'],
104
                    '-P' . $this->databaseConfiguration['password'],
105
                    '-r1',
106
                    '-b',
107
                ];
108
                if (isset($this->databaseConfiguration['dbname'])) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
109
                    $options[] = '-d' . $this->databaseConfiguration['dbname'];
110
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
111
                if ($action == self::EXECUTE_FILE) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
112
                    $options[] = '-i' . $sqlOrFilename;
113
                } elseif ($action == self::EXECUTE_COMMAND) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
114
                    $options[] = '-Q' . $sqlOrFilename;
115
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
116
                break;
117
118
            case 'sqlite':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
119
                $command = 'sqlite3';
120
                // 'path' is the full path to the 'master' db (for Doctrine compatibility).
121
                //  non-master dbs are supposed to reside in the same directory
122
                if (isset($this->databaseConfiguration['dbname'])) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
123
                    $options[] = dirname($this->databaseConfiguration['path']) . '/' . $this->databaseConfiguration['dbname'] . '.sqlite';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = array(); before regardless.
Loading history...
124
                } else {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
125
                    $options[] = $this->databaseConfiguration['path'];
126
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
127
128
                if ($action == self::EXECUTE_COMMAND) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
129
                    $options[] = $sqlOrFilename;
130
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
131
                break;
132
133
            // case 'sqlplus':
134
            //    $command = 'sqlplus';
135
            //    // pass on _all_ env vars, including PATH
136
            //    $env = null;
137
            //    break;
138
            default:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
139
                throw new \OutOfBoundsException("Unsupported db client '$clientType'");
140
        }
141
142
        $commandLine = $this->buildCommandLine($command, $options);
143
144
        /// @todo investigate: for psql is this better done via --file ?
145
        if ($action == self::EXECUTE_FILE && $clientType != 'sqlsrv') {
146
            $commandLine .= ' < ' . escapeshellarg($sqlOrFilename);
147
        }
148
149
        return new Process($commandLine, null, $env);
150
    }
151
152
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
153
     * @see https://www.doctrine-project.org/projects/doctrine-dbal/en/2.10/reference/configuration.html for supported aliases
0 ignored issues
show
Coding Style introduced by
Tag @see cannot be grouped with parameter tags in a doc comment
Loading history...
Coding Style introduced by
Tag value for @see tag indented incorrectly; expected 4 spaces but found 1
Loading history...
154
     * @param array $connectionConfiguration
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
155
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
156
     */
157
    protected function getDbClientType(array $connectionConfiguration)
158
    {
159
        $vendor = $connectionConfiguration['vendor'];
160
        return str_replace(
161
            array('mariadb', 'mssql', 'oracle', 'postgresql'),
162
            array('mysql', 'sqlcmd', 'sqlplus', 'psql'),
163
            $vendor
164
        );
165
    }
166
167
    /**
168
     * Transforms a resultSet string, formatted as per the default way of the db client, into an array
169
     * @todo tested on single-column SELECTs so far
0 ignored issues
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
Coding Style introduced by
Tag @todo cannot be grouped with parameter tags in a doc comment
Loading history...
Coding Style introduced by
Tag value for @todo tag indented incorrectly; expected 3 spaces but found 1
Loading history...
170
     * @param $string
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
171
     * @return string[]
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
172
     */
173
    public function resultSetToArray($string)
174
    {
175
        switch ($this->databaseConfiguration['vendor']) {
176
            case 'mariadb':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
177
            case 'mysql':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
178
                // 'table format', triggered by using the -t option for the client
179
                $output = explode("\n", $string);
180
                array_shift($output); // '+--+'
181
                array_shift($output); // headers
182
                array_shift($output); // '+--+'
183
                array_pop($output); // '+--+'
184
                foreach($output as &$line) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
Coding Style introduced by
Expected "foreach (...) {\n"; found "foreach(...) {\n"
Loading history...
185
                    $line = trim($line, '|');
186
                    $line = trim($line);
187
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
188
                return $output;
189
            //case 'oracle':
190
            case 'postgresql':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
191
                $output = explode("\n", $string);
192
                array_shift($output); // headers
193
                array_shift($output); // '---'
194
                //array_pop($output); // '(N rows)'
195
                foreach($output as &$line) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
Coding Style introduced by
Expected "foreach (...) {\n"; found "foreach(...) {\n"
Loading history...
196
                    $line = trim($line);
197
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
198
                return $output;
199
            case 'sqlite':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
200
                $output = explode("\n", $string);
201
                return $output;
202
            case 'mssql':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
203
                $output = explode("\n", $string);
204
                array_shift($output);
205
                array_shift($output); // '---'
206
                array_pop($output); // blank line
207
                array_pop($output); // '(N rows affected)'
208
                foreach($output as &$line) {
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
Coding Style introduced by
Expected "foreach (...) {\n"; found "foreach(...) {\n"
Loading history...
209
                    $line = trim($line);
210
                }
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
211
                return $output;
212
            default:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
213
                throw new \OutOfBoundsException("Unsupported database type '{$this->databaseConfiguration['vendor']}'");
214
        }
215
    }
216
}
217