Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
79.03% covered (warning)
79.03%
49 / 62
76.92% covered (warning)
76.92%
10 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
Builder
79.03% covered (warning)
79.03%
49 / 62
76.92% covered (warning)
76.92%
10 / 13
20.99
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setConnection
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 createFromSchema
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 dropDatabase
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 dropTable
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 selectTables
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 selectFields
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 createTable
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 field
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 alterTable
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 addConstraint
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 execute
63.64% covered (warning)
63.64%
7 / 11
0.00% covered (danger)
0.00%
0 / 1
6.20
 toSql
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   phpOMS\DataStorage\Database\Schema
8 * @copyright Dennis Eichhorn
9 * @license   OMS License 2.0
10 * @version   1.0.0
11 * @link      https://jingga.app
12 */
13declare(strict_types=1);
14
15namespace phpOMS\DataStorage\Database\Schema;
16
17use phpOMS\DataStorage\Database\BuilderAbstract;
18use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
19
20/**
21 * Database query builder.
22 *
23 * @package phpOMS\DataStorage\Database\Schema
24 * @license OMS License 2.0
25 * @link    https://jingga.app
26 * @since   1.0.0
27 *
28 * @property \phpOMS\DataStorage\Database\Schema\Grammar $grammar Grammar.
29 */
30class Builder extends BuilderAbstract
31{
32    /**
33     * Table to create.
34     *
35     * @var string
36     * @since 1.0.0
37     */
38    public string $createTable = '';
39
40    /**
41     * Fields.
42     *
43     * @var array<string, array{name:string, type:string, default:mixed, null:bool, primary:bool, autoincrement:bool, foreignTable:?string, foreignKey:?string}>
44     * @since 1.0.0
45     */
46    public array $createFields = [];
47
48    /**
49     * Database to drop.
50     *
51     * @var string
52     * @since 1.0.0
53     */
54    public string $dropDatabase = '';
55
56    /**
57     * Table to drop.
58     *
59     * @var array
60     * @since 1.0.0
61     */
62    public array $dropTable = [];
63
64    /**
65     * Tables.
66     *
67     * @var string[]
68     * @since 1.0.0
69     */
70    public array $selectTables = ['*'];
71
72    /**
73     * Always calls compileCreateTableSettings in the Grammar
74     *
75     * This is important to set the correct table settings (e.g. utf8mb4 instead of utf8)
76     *
77     * @var bool
78     * @since 1.0.0
79     */
80    public bool $createTableSettings = true;
81
82    /**
83     * Select fields.
84     *
85     * @var string
86     * @since 1.0.0
87     */
88    public string $selectFields = '';
89
90    /**
91     * Table to alter.
92     *
93     * @var string
94     * @since 1.0.0
95     */
96    public string $alterTable = '';
97
98    /**
99     * Column to alter.
100     *
101     * @var string
102     * @since 1.0.0
103     */
104    public string $alterColumn = '';
105
106    /**
107     * Data to add.
108     *
109     * @var array
110     * @since 1.0.0
111     */
112    public array $alterAdd = [];
113
114    public bool $hasPostQuery = false;
115
116    /**
117     * Constructor.
118     *
119     * @param ConnectionAbstract $connection Database connection
120     * @param bool               $readOnly   Query is read only
121     *
122     * @since 1.0.0
123     */
124    public function __construct(ConnectionAbstract $connection, bool $readOnly = false)
125    {
126        $this->isReadOnly = $readOnly;
127        $this->setConnection($connection);
128    }
129
130    /**
131     * Set connection for grammar.
132     *
133     * @param ConnectionAbstract $connection Database connection
134     *
135     * @return void
136     *
137     * @since 1.0.0
138     */
139    public function setConnection(ConnectionAbstract $connection) : void
140    {
141        $this->connection = $connection;
142        $this->grammar    = $connection->getSchemaGrammar();
143    }
144
145    /**
146     * Create schema builder from schema definition.
147     *
148     * @param array              $definition Database schema definition
149     * @param ConnectionAbstract $connection Database connection
150     *
151     * @return self
152     *
153     * @since 1.0.0
154     */
155    public static function createFromSchema(array $definition, ConnectionAbstract $connection) : self
156    {
157        $builder = new self($connection);
158        $builder->createTable($definition['name'] ?? '');
159
160        foreach ($definition['fields'] as $name => $def) {
161            $builder->field(
162                $name, $def['type'], $def['default'] ?? null,
163                $def['null'] ?? true, $def['primary'] ?? false, $def['unique'] ?? false, $def['autoincrement'] ?? false,
164                $def['foreignTable'] ?? null, $def['foreignKey'] ?? null,
165                $def
166            );
167        }
168
169        return $builder;
170    }
171
172    /**
173     * Drop database
174     *
175     * @param string $database Database to drop
176     *
177     * @return self
178     *
179     * @since 1.0.0
180     */
181    public function dropDatabase(string $database) : self
182    {
183        $this->type         = QueryType::DROP_DATABASE;
184        $this->dropDatabase = $database;
185
186        return $this;
187    }
188
189    /**
190     * Drop table
191     *
192     * @param string $table Table to drop
193     *
194     * @return self
195     *
196     * @since 1.0.0
197     */
198    public function dropTable(string $table) : self
199    {
200        $this->type        = QueryType::DROP_TABLE;
201        $this->dropTable[] = $table;
202
203        return $this;
204    }
205
206    /**
207     * Select all tables
208     *
209     * @return self
210     *
211     * @since 1.0.0
212     */
213    public function selectTables() : self
214    {
215        $this->type = QueryType::TABLES;
216
217        return $this;
218    }
219
220    /**
221     * Select all fields of table
222     *
223     * @param string $table Table to select fields from
224     *
225     * @return self
226     *
227     * @since 1.0.0
228     */
229    public function selectFields(string $table) : self
230    {
231        $this->type         = QueryType::FIELDS;
232        $this->selectFields = $table;
233
234        return $this;
235    }
236
237    /**
238     * Create table
239     *
240     * @param string $name Table to create
241     *
242     * @return self
243     *
244     * @since 1.0.0
245     */
246    public function createTable(string $name) : self
247    {
248        $this->type        = QueryType::CREATE_TABLE;
249        $this->createTable = $name;
250
251        return $this;
252    }
253
254    /**
255     * Define field for create
256     *
257     * @param string $name          Field name
258     * @param string $type          Field type
259     * @param mixed  $default       Default value
260     * @param bool   $isNullable    Can be null
261     * @param bool   $isPrimary     Is a primary field
262     * @param bool   $isUnique      Is a unique field
263     * @param bool   $autoincrement Autoincrements
264     * @param string $foreignTable  Foreign table (in case of foreign key)
265     * @param string $foreignKey    Foreign key
266     * @param array  $meta          Meta data
267     *
268     * @return self
269     *
270     * @since 1.0.0
271     */
272    public function field(
273        string $name, string $type, $default = null,
274        bool $isNullable = true, bool $isPrimary = false, bool $isUnique = false, bool $autoincrement = false,
275        string $foreignTable = null, string $foreignKey = null, array $meta = []
276    ) : self {
277        $this->createFields[$name] = [
278            'name'          => $name,
279            'type'          => $type,
280            'default'       => $default,
281            'null'          => $isNullable,
282            'primary'       => $isPrimary,
283            'unique'        => $isUnique,
284            'autoincrement' => $autoincrement,
285            'foreignTable'  => $foreignTable,
286            'foreignKey'    => $foreignKey,
287            'meta'          => $meta,
288        ];
289
290        return $this;
291    }
292
293    /**
294     * Alter a table.
295     *
296     * @param string $table Table
297     *
298     * @return self
299     *
300     * @since 1.0.0
301     */
302    public function alterTable(string $table) : self
303    {
304        $this->type       = QueryType::ALTER;
305        $this->alterTable = $table;
306
307        return $this;
308    }
309
310    /**
311     * Add a constraint
312     *
313     * @param string $key          Key
314     * @param string $foreignTable Foreign table
315     * @param string $foreignKey   Foreign key
316     *
317     * @return self
318     *
319     * @since 1.0.0
320     */
321    public function addConstraint(string $key, string $foreignTable, string $foreignKey, string $constraint = null) : self
322    {
323        $this->alterAdd['type']         = 'CONSTRAINT';
324        $this->alterAdd['key']          = $key;
325        $this->alterAdd['foreignTable'] = $foreignTable;
326        $this->alterAdd['foreignKey']   = $foreignKey;
327        $this->alterAdd['constraint']   = $constraint;
328
329        return $this;
330    }
331
332    /**
333     * {@inheritdoc}
334     */
335    public function execute() : ?\PDOStatement
336    {
337        $sth = null;
338
339        try {
340            $sth = $this->connection->con->prepare($this->toSql());
341            if ($sth === false) {
342                return null;
343            }
344
345            $sth->execute();
346
347            if ($this->hasPostQuery) {
348                $sqls = $this->grammar->compilePostQueries($this);
349
350                foreach ($sqls as $sql) {
351                    $this->connection->con->exec($sql);
352                }
353            }
354        } catch (\Throwable $t) {
355            // @codeCoverageIgnoreStart
356            \var_dump($t->getMessage());
357            \var_dump($this->toSql());
358
359            $sth = null;
360            // @codeCoverageIgnoreEnd
361        }
362
363        return $sth;
364    }
365
366    /**
367     * {@inheritdoc}
368     */
369    public function toSql() : string
370    {
371        return $this->grammar->compileQuery($this);
372    }
373}