Completed
Push — master ( 853083...2deeb8 )
by Jared
01:46
created

DbalDriver::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Pulsar\Driver;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\DBALException;
7
use JAQB\Query\DeleteQuery;
8
use JAQB\Query\InsertQuery;
9
use JAQB\Query\SelectQuery;
10
use JAQB\Query\UpdateQuery;
11
use Pulsar\Exception\DriverException;
12
use Pulsar\Model;
13
use Pulsar\Query;
14
15
final class DbalDriver extends AbstractDriver
16
{
17
    /**
18
     * @var Connection
19
     */
20
    private $database;
21
22
    public function __construct(Connection $connection)
23
    {
24
        $this->database = $connection;
25
    }
26
27
    public function getConnection($connection): Connection
28
    {
29
        if ($connection) {
30
            throw new DriverException('Currently multiple connections are not supported');
31
        }
32
33
        return $this->database;
34
    }
35
36
    public function createModel(Model $model, array $parameters)
37
    {
38
        // build the SQL query
39
        $tablename = $model->getTablename();
40
        $values = $this->serialize($parameters);
41
        $dbQuery = new InsertQuery();
42
        $dbQuery->into($tablename)->values($values);
43
44
        // then execute the query through DBAL
45
        $db = $this->getConnection($model->getConnection());
46
47
        try {
48
            $db->executeQuery($dbQuery->build(), $dbQuery->getValues());
49
50
            return true;
51
        } catch (DBALException $original) {
52
            throw new DriverException('An error occurred in the database driver when creating the '.$model::modelName().': '.$original->getMessage(), $original->getCode(), $original);
53
        }
54
    }
55
56
    public function getCreatedId(Model $model, string $propertyName)
57
    {
58
        try {
59
            return $this->getConnection($model->getConnection())->lastInsertId();
60
        } catch (DBALException $original) {
61
            throw new DriverException('An error occurred in the database driver when getting the ID of the new '.$model::modelName().': '.$original->getMessage(), $original->getCode(), $original);
62
        }
63
    }
64
65
    public function loadModel(Model $model): ?array
66
    {
67
        // build the SQL query
68
        $tablename = $model->getTablename();
69
        $dbQuery = new SelectQuery();
70
        $dbQuery->select('*')
71
            ->from($tablename)
72
            ->where($model->ids());
73
74
        // then execute the query through DBAL
75
        $db = $this->getConnection($model->getConnection());
76
77
        try {
78
            $row = $db->fetchAssoc($dbQuery->build(), $dbQuery->getValues());
79
        } catch (DBALException $original) {
80
            throw new DriverException('An error occurred in the database driver when loading an instance of '.$model::modelName().': '.$original->getMessage(), $original->getCode(), $original);
81
        }
82
83
        if (!is_array($row)) {
84
            return null;
85
        }
86
87
        return $row;
88
    }
89
90
    public function queryModels(Query $query): array
91
    {
92
        // build the SQL query
93
        $modelClass = $query->getModel();
94
        $model = new $modelClass();
95
96
        $tablename = $model->getTablename();
97
        $dbQuery = $this->buildSelectQuery($query, $tablename);
98
        $dbQuery->select($this->prefixSelect('*', $tablename))
99
            ->limit($query->getLimit(), $query->getStart())
100
            ->orderBy($this->prefixSort($query->getSort(), $tablename));
101
102
        // then execute the query through DBAL
103
        $db = $this->getConnection($model->getConnection());
104
105
        try {
106
            return $db->fetchAll($dbQuery->build(), $dbQuery->getValues());
107
        } catch (DBALException $original) {
108
            throw new DriverException('An error occurred in the database driver while performing the '.$model::modelName().' query: '.$original->getMessage(), $original->getCode(), $original);
109
        }
110
    }
111
112
    public function updateModel(Model $model, array $parameters): bool
113
    {
114
        if (0 == count($parameters)) {
115
            return true;
116
        }
117
118
        // build the SQL query
119
        $tablename = $model->getTablename();
120
        $values = $this->serialize($parameters);
121
        $dbQuery = new UpdateQuery();
122
        $dbQuery->table($tablename)
123
            ->values($values)
124
            ->where($model->ids());
125
126
        // then execute the query through DBAL
127
        $db = $this->getConnection($model->getConnection());
128
129
        try {
130
            $db->executeQuery($dbQuery->build(), $dbQuery->getValues());
131
132
            return true;
133
        } catch (DBALException $original) {
134
            throw new DriverException('An error occurred in the database driver when updating the '.$model::modelName().': '.$original->getMessage(), $original->getCode(), $original);
135
        }
136
    }
137
138
    public function deleteModel(Model $model): bool
139
    {
140
        // build the SQL query
141
        $tablename = $model->getTablename();
142
        $dbQuery = new DeleteQuery();
143
        $dbQuery->from($tablename)
144
            ->where($model->ids());
145
146
        // then execute the query through DBAL
147
        $db = $this->getConnection($model->getConnection());
148
149
        try {
150
            $db->executeQuery($dbQuery->build(), $dbQuery->getValues());
151
152
            return true;
153
        } catch (DBALException $original) {
154
            throw new DriverException('An error occurred in the database driver while deleting the '.$model::modelName().': '.$original->getMessage(), $original->getCode(), $original);
155
        }
156
    }
157
158
    public function count(Query $query): int
159
    {
160
        // build the SQL query
161
        $modelClass = $query->getModel();
162
        $model = new $modelClass();
163
164
        $tablename = $model->getTablename();
165
        $dbQuery = $this->buildSelectQuery($query, $tablename);
166
        $dbQuery->count();
167
168
        // then execute the query through DBAL
169
        return (int) $this->executeScalar($dbQuery, $model, 'count');
170
    }
171
172
    public function sum(Query $query, string $field)
173
    {
174
        // build the SQL query
175
        $modelClass = $query->getModel();
176
        $model = new $modelClass();
177
178
        $tablename = $model->getTablename();
179
        $dbQuery = $this->buildSelectQuery($query, $tablename);
180
        $dbQuery->sum($this->prefixColumn($field, $tablename));
181
182
        // then execute the query through DBAL
183
        return (int) $this->executeScalar($dbQuery, $model, $field);
184
    }
185
186
    public function average(Query $query, string $field)
187
    {
188
        // build the SQL query
189
        $modelClass = $query->getModel();
190
        $model = new $modelClass();
191
192
        $tablename = $model->getTablename();
193
        $dbQuery = $this->buildSelectQuery($query, $tablename);
194
        $dbQuery->average($this->prefixColumn($field, $tablename));
195
196
        // then execute the query through DBAL
197
        return (int) $this->executeScalar($dbQuery, $model, $field);
198
    }
199
200
    public function max(Query $query, string $field)
201
    {
202
        // build the SQL query
203
        $modelClass = $query->getModel();
204
        $model = new $modelClass();
205
206
        $tablename = $model->getTablename();
207
        $dbQuery = $this->buildSelectQuery($query, $tablename);
208
        $dbQuery->max($this->prefixColumn($field, $tablename));
209
210
        // then execute the query through DBAL
211
        return (int) $this->executeScalar($dbQuery, $model, $field);
212
    }
213
214
    public function min(Query $query, string $field)
215
    {
216
        // build the SQL query
217
        $modelClass = $query->getModel();
218
        $model = new $modelClass();
219
220
        $tablename = $model->getTablename();
221
        $dbQuery = $this->buildSelectQuery($query, $tablename);
222
        $dbQuery->min($this->prefixColumn($field, $tablename));
223
224
        // then execute the query through DBAL
225
        return (int) $this->executeScalar($dbQuery, $model, $field);
226
    }
227
228
    //////////////////////////
229
    /// Helpers
230
    //////////////////////////
231
232
    /**
233
     * Builds a new select query.
234
     */
235
    private function buildSelectQuery(Query $query, string $tablename): SelectQuery
236
    {
237
        $dbQuery = new SelectQuery();
238
        $dbQuery->from($tablename)
239
            ->where($this->prefixWhere($query->getWhere(), $tablename));
240
241
        $this->addJoins($query, $tablename, $dbQuery);
242
243
        return $dbQuery;
244
    }
245
246
    /**
247
     * Executes a select query through DBAL and returns a scalar result.
248
     *
249
     * @return false|mixed
250
     *
251
     * @throws DriverException
252
     */
253
    private function executeScalar(SelectQuery $query, Model $model, string $field)
254
    {
255
        $db = $this->getConnection($model->getConnection());
256
257
        try {
258
            return $db->fetchColumn($query->build(), $query->getValues());
259
        } catch (DBALException $original) {
260
            throw new DriverException('An error occurred in the database driver while getting the value of '.$model::modelName().'.'.$field.': '.$original->getMessage(), $original->getCode(), $original);
261
        }
262
    }
263
264
    public function startTransaction(?string $connection): void
265
    {
266
        $this->getConnection($connection)->beginTransaction();
267
    }
268
269
    public function rollBackTransaction(?string $connection): void
270
    {
271
        $this->getConnection($connection)->rollBack();
272
    }
273
274
    public function commitTransaction(?string $connection): void
275
    {
276
        $this->getConnection($connection)->commit();
277
    }
278
}
279