1<?php
2
3
4namespace ComboStrap;
5
6
7class SqliteRequest
8{
9    const UPSERT_REQUEST = "Upsert";
10    const SELECT_REQUEST = "Select";
11
12    /**
13     * delete, insert, update, query with parameters
14     */
15    const PARAMETRIZED_REQUEST = "Parametrized";
16    const STATEMENT_REQUEST = "Statement";
17    /**
18     * @var Sqlite
19     */
20    private $sqlite;
21    /**
22     * @var string
23     */
24    private $tableName;
25    /**
26     * @var array
27     */
28    private $data;
29    /**
30     * @var SqliteResult
31     */
32    private $result;
33    /**
34     * @var string
35     */
36    private $query;
37
38    private \helper_plugin_sqlite $sqlitePlugin;
39
40    /**
41     * A statement that is not a query
42     * @var ?string
43     */
44    private ?string $statement = null;
45    /**
46     * The SQL parameters
47     * @var array |null
48     */
49    private ?array $parameters = null;
50
51    /**
52     * SqliteRequest constructor.
53     * @param Sqlite $sqlite
54     */
55    public function __construct(Sqlite $sqlite)
56    {
57        $this->sqlite = $sqlite;
58        $this->sqlitePlugin = $sqlite->getSqlitePlugin();
59    }
60
61    public function setTableRow(string $tableName, array $data): SqliteRequest
62    {
63        $this->tableName = $tableName;
64        $this->data = $data;
65        return $this;
66    }
67
68    /**
69     * @throws ExceptionCompile
70     */
71    public function execute(): SqliteResult
72    {
73        $sqLiteAdapater = $this->sqlitePlugin->getAdapter();
74        $requestType = $this->getRequestType();
75        switch ($requestType) {
76            case self::UPSERT_REQUEST:
77                $statement = $this->getParametrizeReplaceQuery($this->tableName, $this->data);
78                $values = array_values($this->data);
79                $res = $this->executeParametrizedStatement($statement, $values);
80                $queryExecuted = "Upsert of table $this->tableName";
81                break;
82            case self::SELECT_REQUEST:
83                $res = $this->sqlitePlugin->query($this->query);
84                $queryExecuted = $this->query;
85                break;
86            case self::PARAMETRIZED_REQUEST:
87                $res = $this->executeParametrizedStatement($this->statement, $this->parameters);
88                $queryExecuted = array_merge([$this->statement], $this->parameters);
89                break;
90            case self::STATEMENT_REQUEST:
91                if (!Sqlite::isJuneVersion($sqLiteAdapater)) {
92                    /** @noinspection PhpUndefinedMethodInspection */
93                    $res = $sqLiteAdapater->executeQuery($this->statement);
94                } else {
95                    $res = $sqLiteAdapater->query($this->statement);
96                }
97                $queryExecuted = $this->statement;
98                break;
99            default:
100                throw new ExceptionCompile("The request type ($requestType) was not processed");
101        }
102
103
104        if ($res === null) {
105            throw new ExceptionCompile("No Sql request was found to be executed");
106        }
107
108        if ($res === false) {
109            $message = $this->getErrorMessage();
110            throw new ExceptionCompile("Error in the $requestType. Message: {$message}");
111        }
112
113        if (!$res instanceof \PDOStatement) {
114            $message = $this->getErrorMessage();
115            throw new ExceptionCompile("Error in the request type `$requestType`. res is not a PDOStatement but as the value ($res). Message: {$message}, Query: {$queryExecuted}");
116        }
117
118        $this->result = new SqliteResult($this, $res);
119        return $this->result;
120    }
121
122    public
123    function getErrorMessage(): string
124    {
125        $adapter = $this->sqlitePlugin->getAdapter();
126        if ($adapter === null) {
127            throw new ExceptionRuntimeInternal("The database adapter is null, no error info can be retrieved");
128        }
129        if (!Sqlite::isJuneVersion($adapter)) {
130            /** @noinspection PhpUndefinedMethodInspection */
131            $do = $adapter->getDb();
132        } else {
133            $do = $adapter->getPdo();
134        }
135        if ($do === null) {
136            throw new ExceptionRuntimeInternal("The database object is null, it seems that the database connection has been closed. Are you in two differents execution context ?");
137        }
138        $errorInfo = $do->errorInfo();
139        $message = "";
140        $errorCode = $errorInfo[0];
141        if ($errorCode === '0000') {
142            $message = ("No rows were deleted or updated");
143        }
144        $errorInfoAsString = implode(", ", $errorInfo);
145        return "$message. : {$errorInfoAsString}";
146    }
147
148    public
149    function getSqliteConnection(): Sqlite
150    {
151        return $this->sqlite;
152    }
153
154    public
155    function close()
156    {
157
158        if ($this->result !== null) {
159            $this->result->close();
160            $this->result = null;
161        }
162
163    }
164
165    public
166    function setQuery(string $string): SqliteRequest
167    {
168        $this->query = $string;
169        return $this;
170    }
171
172    /**
173     * @param string $executableSql
174     * @param array $parameters
175     * @return SqliteResult
176     */
177    public
178    function setQueryParametrized(string $executableSql, array $parameters): SqliteRequest
179    {
180        $this->statement = $executableSql;
181        $this->parameters = $parameters;
182        return $this;
183
184    }
185
186    /**
187     * @param string $statement
188     * @return $this - a statement that will execute
189     */
190    public
191    function setStatement(string $statement): SqliteRequest
192    {
193        $this->statement = $statement;
194        return $this;
195    }
196
197    private
198    function getRequestType(): string
199    {
200        if ($this->data !== null && $this->tableName !== null) {
201
202            return self::UPSERT_REQUEST;
203
204        }
205
206        if ($this->query !== null) {
207
208            return self::SELECT_REQUEST;
209
210        }
211
212        if ($this->parameters !== null) {
213
214            return self::PARAMETRIZED_REQUEST;
215
216        }
217
218        return self::STATEMENT_REQUEST;
219
220    }
221
222    /**
223     * @param string $table
224     * @param array $data
225     * @return string - a replace parametrized query
226     */
227    private function getParametrizeReplaceQuery(string $table, array $data): string
228    {
229        $columns = array_map(function ($column) {
230            return '"' . $column . '"';
231        }, array_keys($data));
232        $placeholders = array_pad([], count($columns), '?');
233        /** @noinspection SqlResolve */
234        return 'REPLACE INTO "' . $table . '" (' . join(',', $columns) . ') VALUES (' . join(',',
235                $placeholders) . ')';
236    }
237
238    private function executeParametrizedStatement(string $statement, array $values): \PDOStatement
239    {
240        $sqLiteAdapater = $this->sqlitePlugin->getAdapter();
241        $queryParametrized = array_merge([$statement], $values);
242        if (!Sqlite::isJuneVersion($sqLiteAdapater)) {
243            /** @noinspection PhpParamsInspection */
244            return $sqLiteAdapater->query($queryParametrized);
245        }
246        $values = array_values($values);
247        return $sqLiteAdapater->query($statement, $values);
248    }
249
250}
251