Test Failed
Push — main ( 54a4e4...6238c5 )
by Daniel
10:17
created

InputOutputDatabases::setBatchDataIntoDatabase()   B

Complexity

Conditions 8
Paths 73

Size

Total Lines 40
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 8
eloc 32
c 1
b 0
f 1
nc 73
nop 3
dl 0
loc 40
rs 8.1635
1
<?php
2
3
/*
4
 * The MIT License
5
 *
6
 * Copyright 2022 - 2024 Daniel Popiniuc.
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated documentation files (the "Software"), to deal
10
 * in the Software without restriction, including without limitation the rights
11
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
 * copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
 * THE SOFTWARE.
25
 */
26
27
namespace danielgp\io_operations;
28
29
trait InputOutputDatabases
30
{
31
32
    public $strErrorText            = null;
33
    private $arrayConnectionDetails = [];
34
    private $bolDebugText           = false;
35
    private $objConnection          = null;
36
37
    public function establishDatabaseConnectionFlexible(string $strDatabaseType, array $arrayConnectionParameters)
38
    {
39
        if (http_response_code() != 200) {
40
            return null;
41
        }
42
        $arrayAuth = [
43
            'U' => '',
44
            'P' => '',
45
        ];
46
        if (array_key_exists('Authentication', $arrayConnectionParameters)) {
47
            $arrayAuth = [
48
                'U' => $arrayConnectionParameters['Authentication']['Username'],
49
                'P' => $arrayConnectionParameters['Authentication']['Password'],
50
            ];
51
        }
52
        switch ($strDatabaseType) {
53
            case 'MySQL':
54
                $strDsn             = 'mysql:'
55
                    . implode(';', [
56
                        'host=' . $arrayConnectionParameters['Host'],
57
                        'dbname=' . $arrayConnectionParameters['Database'],
58
                        'port=' . $arrayConnectionParameters['Port'],
59
                        'charset=' . $arrayConnectionParameters['Charset'],
60
                        'collation=' . $arrayConnectionParameters['Collation'],
61
                ]);
62
                $aConnectionOptions = [
63
                    \PDO::ATTR_ERRMODE          => \PDO::ERRMODE_EXCEPTION,
64
                    \PDO::MYSQL_ATTR_FOUND_ROWS => TRUE,
65
                ];
66
                break;
67
            case 'SQLite':
68
                $strDsn             = 'sqlite:' . $arrayConnectionParameters['FileName'];
69
                $aConnectionOptions = [
70
                    \PDO::ATTR_EMULATE_PREPARES => false,
71
                    \PDO::ATTR_ERRMODE          => \PDO::ERRMODE_EXCEPTION,
72
                ];
73
                break;
74
        }
75
        $this->arrayConnectionDetails['DatabaseType'] = $strDatabaseType;
76
        $this->exposeDebugText('Database connection DSN: ' . $strDsn);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $strDsn does not seem to be defined for all execution paths leading up to this point.
Loading history...
77
        if ($arrayAuth['U'] != '') {
78
            $this->exposeDebugText('Database connection username: ' . $arrayAuth['U']);
79
        }
80
        try {
81
            $this->objConnection = new \PDO($strDsn, $arrayAuth['U'], $arrayAuth['P'], $aConnectionOptions);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $aConnectionOptions does not seem to be defined for all execution paths leading up to this point.
Loading history...
82
            $this->exposeDebugText('Database connection established: '
83
                . $this->getResultsAsJson($this->objConnection));
84
        } catch (\RuntimeException $e) {
85
            if (!headers_sent()) {
86
                http_response_code(403);
87
            }
88
            $this->strErrorText = vsprintf('Conectarea la [%s] a întâmpinat o eroare'
89
                . ', detaliile sunt după cum urmează: %s', [
90
                $strDatabaseType,
91
                $e->getMessage(),
92
            ]);
93
            $this->exposeDebugText('Database connection: ' . $this->strErrorText);
94
        }
95
    }
96
97
    public function exposeDebugText(string $strText)
98
    {
99
        if ($this->bolDebugText) {
100
            error_log($strText);
101
        }
102
    }
103
104
    public function getQueryFromFile(array $arrayInputs)
105
    {
106
        $this->exposeDebugText('Query file is: ' . $arrayInputs['queryFileName']);
107
        $fileContent = $this->getFileEntireContent($arrayInputs['queryFileName']);
0 ignored issues
show
Bug introduced by
It seems like getFileEntireContent() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

107
        /** @scrutinizer ignore-call */ 
108
        $fileContent = $this->getFileEntireContent($arrayInputs['queryFileName']);
Loading history...
108
        $strRawQuery = $fileContent;
109
        if (is_array($fileContent)) {
110
            $strRawQueryAsIs = implode(' ', $fileContent);
111
            $this->exposeDebugText('Query as read from file: ' . $strRawQueryAsIs);
112
            $arrayToClean    = [
113
                str_repeat(' ', 12),
114
                str_repeat(' ', 8),
115
                str_repeat(' ', 4),
116
                str_repeat(' ', 2),
117
            ];
118
            $strRawQuery     = str_replace($arrayToClean, ' ', $strRawQueryAsIs);
119
        }
120
        $sReturn = $strRawQuery;
121
        if (array_key_exists('queryParameterValues', $arrayInputs) && ($arrayInputs['queryParameterValues'] !== [])) {
122
            $sReturn = vsprintf($strRawQuery, $arrayInputs['queryParameterValues']);
123
        }
124
        return $sReturn;
125
    }
126
127
    public function getResultsAsJson(array|\PDO $arrayResults)
128
    {
129
        $encodingFlags = (JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
130
        return json_encode($arrayResults, $encodingFlags);
131
    }
132
133
    public function getResultsThroughVerification(array $arrayResult)
134
    {
135
        $strReturn = $arrayResult;
136
        if (is_null($arrayResult)) {
0 ignored issues
show
introduced by
The condition is_null($arrayResult) is always false.
Loading history...
137
            if (!headers_sent()) {
138
                http_response_code(403);
139
            }
140
            $this->strErrorText = 'NU există date pe server cu valorile introduse!';
141
            $this->exposeDebugText('No data (NULL): ' . $this->strErrorText);
142
        } elseif (is_array($arrayResult)) {
0 ignored issues
show
introduced by
The condition is_array($arrayResult) is always true.
Loading history...
143
            if ($arrayResult == []) {
144
                if (!headers_sent()) {
145
                    http_response_code(403);
146
                }
147
                $this->strErrorText = 'NU există date pe server cu valorile introduse!';
148
                $this->exposeDebugText('Empty results: ' . $this->strErrorText);
149
            }
150
        }
151
        return $strReturn;
152
    }
153
154
    public function getResultsUsingQuery(string $strQuery, string $strFetchingType = \PDO::FETCH_ASSOC)
155
    {
156
        if (is_null($this->objConnection)) {
157
            return null;
158
        }
159
        $result = [];
160
        try {
161
            $stmt = $this->objConnection->prepare($strQuery);
162
            $this->exposeDebugText('Before Query execution: ' . $strQuery);
163
            $stmt->execute();
164
            if (substr($strQuery, 0, 7) === 'INSERT ') {
165
                $this->exposeDebugText('INSERT detected');
166
                $intLastInsertId = $this->objConnection->lastInsertId();
167
                $this->exposeDebugText('Last insert ID: ' . $intLastInsertId);
168
                switch ($intLastInsertId) {
169
                    case '0':
170
                        $intRowsAffected = 0;
171
                        break;
172
                    default:
173
                        $intRowsAffected = $stmt->rowCount();
174
                        break;
175
                }
176
                $result = [
177
                    'lastInsertId' => $intLastInsertId,
178
                    'rowsAffected' => $intRowsAffected,
179
                ];
180
                $this->exposeDebugText('Rows affected: ' . $this->getResultsAsJson($result));
181
            } elseif ((substr($strQuery, 0, 7) === 'UPDATE ') || (substr($strQuery, 0, 5) === 'CALL ')) {
182
                $this->exposeDebugText('UPDATE/CALL detected');
183
                $result = [
184
                    'rowsAffected' => $stmt->rowCount(),
185
                ];
186
                $this->exposeDebugText('Rows affected: ' . $this->getResultsAsJson($result));
187
            } elseif (($stmt->rowCount() == 0) && ($this->arrayConnectionDetails['DatabaseType'] != 'SQLite')) {
188
                $this->exposeDebugText('0 RowCount seen');
189
                $result = [
190
                    'rowsAffected' => 0,
191
                ];
192
                $this->exposeDebugText('Rows affected: ' . $this->getResultsAsJson($result));
193
            } else {
194
                $result = $stmt->fetchAll($strFetchingType);
195
            }
196
            $objReturn = $this->getResultsThroughVerification($result);
197
            $this->exposeDebugText('Return after verification:' . $this->getResultsAsJson($objReturn));
198
            return $objReturn;
199
        } catch (\PDOException $e) {
200
            if (!headers_sent()) {
201
                http_response_code(403);
202
            }
203
            $this->strErrorText = vsprintf('Eroare întâlnită, mesajul de la serverul de date este [%s]', [
204
                $e->getMessage(),
205
            ]);
206
            $this->exposeDebugText('After Query execution: ' . $this->strErrorText);
207
        }
208
    }
209
210
    public function getStoredQuery($objClass, $label, $given_parameters = null)
211
    {
212
        $sReturn = call_user_func_array([$objClass, 'setRightQuery'], [$label, $given_parameters]);
213
        if ($sReturn === false) {
214
            $this->exposeDebug('<b>' . $label . '</b> was not defined!');
0 ignored issues
show
Bug introduced by
The method exposeDebug() does not exist on danielgp\io_operations\InputOutputDatabases. Did you maybe mean exposeDebugText()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

214
            $this->/** @scrutinizer ignore-call */ 
215
                   exposeDebug('<b>' . $label . '</b> was not defined!');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
215
        }
216
        return $sReturn;
217
    }
218
219
    public function setBatchDataIntoDatabase(string $strQuery, array $arrayDataToWrite, string $strWhich)
220
    {
221
        if (is_null($this->objConnection)) {
222
            return null;
223
        }
224
        $arrayParameterValues = [];
225
        try {
226
            $stmt            = $this->objConnection->prepare($strQuery);
227
            $intRowsAffected = 0;
228
            foreach ($arrayDataToWrite as $intLine => $arrayValues) {
229
                $arrayParameterValues = [];
230
                foreach ($arrayValues as $strFieldName => $strValue) {
231
                    $strFieldName = ':' . str_replace(' ', '_', $strFieldName);
232
                    if ($strValue == 'NULL') {
233
                        $strValue = null;
234
                    }
235
                    $stmt->bindValue($strFieldName, $strValue);
236
                    $arrayParameterValues[$strFieldName] = chr(39) . $strValue . chr(39);
237
                }
238
                $stmt->execute();
239
                $intRowsAffected += $stmt->rowCount();
240
            }
241
            $this->exposeDebugText('Number of rows affected: ' . $intRowsAffected);
242
            $stmt->closeCursor();
243
        } catch (\PDOException $e) {
244
            if ($e->getCode() == 23000) {
245
                $this->exposeDebugText('Unique constraint case: ' . $e->getMessage());
246
            } else {
247
                if (!headers_sent()) {
248
                    http_response_code(403);
249
                }
250
                $this->strErrorText = vsprintf('Error %s encoutered, message is [%s]', [
251
                    $e->getCode(),
252
                    $e->getMessage(),
253
                ]);
254
                $this->exposeDebugText('After Query execution: ' . $this->strErrorText);
255
                error_log('Parametrized query: ' . $strQuery);
256
                error_log('After Query execution: ' . $this->strErrorText);
257
                error_log('Attempted parameters: ' . json_encode($arrayParameterValues));
258
                error_log('Attempted query: ' . str_replace(array_keys($arrayParameterValues), array_values($arrayParameterValues), $strQuery));
259
            }
260
        }
261
    }
262
}
263