DatabaseService::getSingleByIdFromDatabase()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: famoser
5
 * Date: 23.05.2016
6
 * Time: 15:25
7
 */
8
9
namespace Famoser\XKCDCache\Services;
10
11
use Famoser\XKCDCache\Entities\Base\BaseEntity;
12
use Famoser\XKCDCache\Entities\Comic;
13
use Famoser\XKCDCache\Services\Base\BaseService;
14
use Famoser\XKCDCache\Services\Interfaces\DatabaseServiceInterface;
15
use Interop\Container\ContainerInterface;
16
use PDO;
17
18
/**
19
 * the DatabaseService allows access to the database. It abstracts sql from logic, and is type safe
20
 *
21
 * @package Famoser\XKCDCache\Helpers
22
 */
23
class DatabaseService extends BaseService implements DatabaseServiceInterface
24
{
25
    /* @var PDO $database */
26
    private $database;
27
28
    /**
29
     * DatabaseHelper constructor.
30
     *
31
     * @param ContainerInterface $container
32
     */
33 19
    public function __construct(ContainerInterface $container)
34
    {
35 19
        parent::__construct($container);
36
37 19
        $this->initializeDatabase();
38 19
    }
39
40
    /**
41
     * @return PDO
42
     */
43 16
    private function getConnection()
44
    {
45 16
        return $this->database;
46
    }
47
48
    /**
49
     * initialize the database
50
     */
51 19
    private function initializeDatabase()
52
    {
53 19
        $dataPath = $this->getSettingService()->getDbPath();
54
55 19
        if (!file_exists($dataPath)) {
56 19
            $templatePath = $this->getSettingService()->getDbTemplatePath();
57 19
            copy($templatePath, $dataPath);
58
        }
59
60 19
        $this->database = $this->constructPdo($dataPath);
61 19
    }
62
63
    /**
64
     * construct a sqlite pdo object from a path
65
     *
66
     * @param string $path
67
     * @return PDO
68
     */
69 19
    private function constructPdo($path)
70
    {
71 19
        $pdo = new PDO('sqlite:' . $path);
72 19
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
73 19
        $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
74 19
        return $pdo;
75
    }
76
77
    /**
78
     * creates the sql query
79
     *
80
     * @param BaseEntity $entity
81
     * @param null|string $where
82
     * @param null|string $orderBy
83
     * @param int $limit
84
     * @param string $selector
85
     * @return string
86
     */
87 15
    private function createQuery(BaseEntity $entity, $where = null, $orderBy = null, $limit = 1000, $selector = '*')
88
    {
89 15
        $sql = 'SELECT ' . $selector . ' FROM ' . $entity->getTableName();
90 15
        if ($where !== null) {
91 11
            $sql .= ' WHERE ' . $where;
92
        }
93 15
        if ($orderBy !== null) {
94 7
            $sql .= ' ORDER BY ' . $orderBy;
95
        }
96 15
        if ($limit > 0) {
97 9
            $sql .= ' LIMIT ' . $limit;
98
        }
99 15
        return $sql;
100
    }
101
102
    /**
103
     * executes query and fetches all results
104
     *
105
     * @param BaseEntity $entity
106
     * @param string $sql
107
     * @param null|array $parameters
108
     * @return false|array|null
109
     */
110 13
    private function executeAndFetch(BaseEntity $entity, $sql, $parameters = null)
111
    {
112 13
        $request = $this->getConnection()->prepare($sql);
113 13
        if (!$request->execute($parameters)) {
114
            return [];
115
        }
116 13
        return $request->fetchAll(PDO::FETCH_CLASS, get_class($entity));
117
    }
118
119
    /**
120
     * gets all entities which match the specified conditions from the database
121
     *
122
     * @param BaseEntity $entity
123
     * @param null|string $where
124
     * @param null|string $orderBy
125
     * @param null|array $parameters
126
     * @param int $limit
127
     * @param string $selector
128
     * @return Comic[]
129
     */
130 7
    public function getFromDatabase(
131
        BaseEntity $entity,
132
        $where = null,
133
        $parameters = null,
134
        $orderBy = null,
135
        $limit = -1,
136
        $selector = '*'
137
    )
138
    {
139 7
        $sql = $this->createQuery($entity, $where, $orderBy, $limit, $selector);
140 7
        $res = $this->executeAndFetch($entity, $sql, $parameters);
141 7
        return $res;
142
    }
143
144
    /**
145
     * counts the entities which match the conditions
146
     *
147
     * @param BaseEntity $entity
148
     * @param null|string $where
149
     * @param null|string $orderBy
150
     * @param null|array $parameters
151
     * @param int $limit
152
     * @return int|false
153
     */
154 2
    public function countFromDatabase(
155
        BaseEntity $entity,
156
        $where = null,
157
        $parameters = null,
158
        $orderBy = null,
159
        $limit = -1
160
    )
161
    {
162 2
        $sql = $this->createQuery($entity, $where, $orderBy, $limit, 'COUNT(*)');
163 2
        return $this->executeAndCount($sql, $parameters);
164
    }
165
166
    /**
167
     * gets all entities whose property is one of the values provided and which match the specified conditions
168
     *
169
     * @param BaseEntity $entity
170
     * @param string $property
171
     * @param array $values
172
     * @param bool $invertIn
173
     * @param null|string $where
174
     * @param null|string $orderBy
175
     * @param null|array $parameters
176
     * @param int $limit
177
     * @return Comic[]
178
     */
179 2
    public function getWithInFromDatabase(
180
        BaseEntity $entity,
181
        $property,
182
        $values,
183
        $invertIn = false,
184
        $where = null,
185
        $parameters = null,
186
        $orderBy = null,
187
        $limit = -1
188
    )
189
    {
190 2
        if ($parameters == null) {
191 1
            $parameters = [];
192
        }
193 2
        if ($where === null) {
194 1
            $where = ' ';
195
        } else {
196 1
            $where .= ' AND ';
197
        }
198 2
        $variables = [];
199 2
        $valueCount = count($values);
200 2
        for ($i = 0; $i < $valueCount; $i++) {
201 2
            $parameters[':' . $property . $i] = $values[$i];
202 2
            $variables[] = ':' . $property . $i;
203
        }
204 2
        if (count($variables)) {
205 2
            $where .= $property . (($invertIn) ? ' NOT' : '') . ' IN (' . implode(',', $variables) . ')';
206
        }
207 2
        $sql = $this->createQuery($entity, $where, $orderBy, $limit);
208 2
        $res = $this->executeAndFetch($entity, $sql, $parameters);
209 2
        return $res;
210
    }
211
212
    /**
213
     * get the first entry from the database which matches the conditions
214
     *
215
     * @param BaseEntity $entity
216
     * @param null|string $where
217
     * @param null|array $parameters
218
     * @param null|string $orderBy
219
     * @return Comic
220
     */
221 9
    public function getSingleFromDatabase(BaseEntity $entity, $where = null, $parameters = null, $orderBy = null)
222
    {
223 9
        $sql = $this->createQuery($entity, $where, $orderBy, 1);
224 9
        $res = $this->executeAndFetch($entity, $sql, $parameters);
225 9
        if (count($res) > 0) {
226 7
            return $res[0];
227
        }
228 7
        return null;
229
    }
230
231
    /**
232
     * save the entity to the database
233
     * if the entity was retrieved from the database before, it will replace the old data
234
     *
235
     * @param BaseEntity $entity
236
     * @return bool
237
     */
238 15
    public function saveToDatabase(BaseEntity $entity)
239
    {
240 15
        $properties = (array)$entity;
241 15
        unset($properties['id']);
242 15
        if ($entity->id > 0) {
243
            //update
244 1
            $sql = 'UPDATE ' . $entity->getTableName() . ' SET ';
245 1
            foreach ($properties as $key => $val) {
246 1
                $sql .= $key . '=:' . $key . ',';
247
            }
248 1
            $sql = substr($sql, 0, -1);
249 1
            $sql .= ' WHERE id=:id';
250 1
            $properties = (array)$entity;
251 1
            $request = $this->getConnection()->prepare($sql);
252 1
            if (!$request->execute($properties)) {
253 1
                return false;
254
            }
255
        } else {
256
            //create
257 15
            $sql = 'INSERT INTO ' . $entity->getTableName() . '(';
258 15
            foreach ($properties as $key => $val) {
259 15
                $sql .= $key . ',';
260
            }
261 15
            $sql = substr($sql, 0, -1);
262 15
            $sql .= ') VALUES (';
263 15
            foreach ($properties as $key => $val) {
264 15
                $sql .= ':' . $key . ',';
265
            }
266 15
            $sql = substr($sql, 0, -1);
267 15
            $sql .= ')';
268 15
            $request = $this->getConnection()->prepare($sql);
269 15
            if (!$request->execute($properties)) {
270
                return false;
271
            }
272 15
            $entity->id = (int)$this->getConnection()->lastInsertId();
273
        }
274 15
        return true;
275
    }
276
277
    /**
278
     * execute the specified sql query, return if the query was successful
279
     *
280
     * @param string $sql
281
     * @param null|array $parameters
282
     * @return bool
283
     */
284 1
    public function execute($sql, $parameters = null)
285
    {
286 1
        $prep = $this->getConnection()->prepare($sql);
287 1
        return $prep->execute($parameters);
288
    }
289
290
    /**
291
     * execute the specified sql query, return the FETCH_NUM result
292
     *
293
     * @param string $sql
294
     * @param null|array $parameters
295
     * @return false|int
296
     */
297 2
    public function executeAndCount($sql, $parameters = null)
298
    {
299 2
        $prep = $this->getConnection()->prepare($sql);
300 2
        if (!$prep->execute($parameters)) {
301
            return false;
302
        }
303 2
        $fetched = $prep->fetchAll(PDO::FETCH_NUM);
304 2
        if (!isset($fetched[0][0])) {
305
            return false;
306
        }
307 2
        return $fetched[0][0];
308
    }
309
310
    /**
311
     * deletes the entity from the database
312
     *
313
     * @param BaseEntity $entity
314
     * @return bool
315
     */
316 1
    public function deleteFromDatabase(BaseEntity $entity)
317
    {
318 1
        $sql = 'DELETE FROM ' . $entity->getTableName() . ' WHERE id=:id';
319 1
        $params = ['id' => $entity->id];
320 1
        $prep = $this->getConnection()->prepare($sql);
321 1
        return $prep->execute($params);
322
    }
323
324
    /**
325
     * frees up any resources / files locks
326
     * behaviour of service calls after disposing it is undefined
327
     */
328 18
    public function dispose()
329
    {
330 18
        $this->database = null;
331 18
    }
332
333
    /**
334
     * get the first entry from the database which matches the conditions
335
     *
336
     * @param BaseEntity $entity
337
     * @param int $entityId
338
     * @return Comic
339
     */
340 5
    public function getSingleByIdFromDatabase(BaseEntity $entity, $entityId)
341
    {
342 5
        return $this->getSingleFromDatabase($entity, 'id = :id', ['id' => $entityId]);
343
    }
344
}
345