AbstractStorage   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 263
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 0
loc 263
c 0
b 0
f 0
wmc 25
lcom 1
cbo 1
rs 10

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A setConnection() 0 5 1
A getConnection() 0 4 1
A setTableName() 0 5 1
A getTableName() 0 4 1
A setIdColumn() 0 5 1
A getIdColumn() 0 4 1
A getNumberOfRows() 0 7 1
A selectQuery() 0 7 1
A insert() 0 17 1
A columnsToPlaceholders() 0 10 2
A find() 0 19 2
A findAllBy() 0 16 3
A assembleEquality() 0 11 2
B updateWhere() 0 25 2
A findOneBy() 0 10 2
A exists() 0 5 1
A deleteWhere() 0 14 1
1
<?php
2
3
namespace Koine\Repository\Storage\Pdo;
4
5
use Koine\Repository\Exception\RecordNotFoundException;
6
use Koine\Repository\Storage\StorageInterface;
7
use PDO;
8
9
abstract class AbstractStorage implements StorageInterface
10
{
11
    /**
12
     * @var PDO
13
     */
14
    private $connection;
15
16
    /**
17
     * @var string
18
     */
19
    private $tableName;
20
21
    /**
22
     * @var string
23
     */
24
    private $idColumn;
25
26
    /**
27
     * @param PDO    $connection
28
     * @param string $tableName
29
     * @param string $idColumn
30
     */
31
    public function __construct(PDO $connection, $tableName, $idColumn = 'id')
32
    {
33
        $this->setConnection($connection);
34
        $this->setTableName($tableName);
35
        $this->setIdColumn($idColumn);
36
    }
37
38
    /**
39
     * @param PDO $connection
40
     *
41
     * @return self
42
     */
43
    public function setConnection(PDO $connection)
44
    {
45
        $this->connection = $connection;
46
        return $this;
47
    }
48
49
    /**
50
     * @return PDO
51
     */
52
    public function getConnection()
53
    {
54
        return $this->connection;
55
    }
56
57
    /**
58
     * @param string $tableName
59
     *
60
     * @return self
61
     */
62
    public function setTableName($tableName)
63
    {
64
        $this->tableName = (string) $tableName;
65
        return $this;
66
    }
67
68
    /**
69
     * @return string
70
     */
71
    public function getTableName()
72
    {
73
        return $this->tableName;
74
    }
75
76
    /**
77
     * @param string $idColumn
78
     *
79
     * @return self
80
     */
81
    public function setIdColumn($idColumn)
82
    {
83
        $this->idColumn = (string) $idColumn;
84
        return $this;
85
    }
86
87
    /**
88
     * @return string
89
     */
90
    public function getIdColumn()
91
    {
92
        return $this->idColumn;
93
    }
94
95
    /**
96
     * @return int
97
     */
98
    public function getNumberOfRows()
99
    {
100
        $tableName = $this->getTableName();
101
        $records = $this->selectQuery("SELECT count(*) as count FROM $tableName");
102
103
        return (int) $records[0]['count'];
104
    }
105
106
    /**
107
     * @param string $sql
108
     * @param array  $params
109
     *
110
     * @return array
111
     */
112
    private function selectQuery($sql, array $params = array())
113
    {
114
        $stmt = $this->getConnection()->prepare($sql);
115
        $stmt->execute($params);
116
117
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
118
    }
119
120
    /**
121
     * @param array $values
122
     */
123
    public function insert(array $values)
124
    {
125
        $sql = 'INSERT INTO %s (%s) VALUES (%s)';
126
        $columnNames = array_keys($values);
127
        $columns = implode(', ', $columnNames);
128
        $placeholders = implode(', ', $this->columnsToPlaceholders($columnNames));
129
        $sql = sprintf(
130
            $sql,
131
            $this->getTableName(),
132
            $columns,
133
            $placeholders
134
        );
135
        $stmt = $this->getConnection()->prepare($sql);
136
        $stmt->execute($values);
137
138
        return $this->getConnection()->lastInsertId();
139
    }
140
141
    /**
142
     * @param array  $columns
143
     * @param string $placeholderPrefix
144
     *
145
     * @return array
146
     */
147
    private function columnsToPlaceholders(array $columns, $placeholderPrefix = '')
148
    {
149
        $placeholders = array();
150
151
        foreach ($columns as $column) {
152
            $placeholders[$column] = ":$placeholderPrefix$column";
153
        }
154
155
        return $placeholders;
156
    }
157
158
    public function find($id)
159
    {
160
        $resultSet = $this->findAllBy(array(
161
            $this->getIdColumn() => $id,
162
        ));
163
164
        if (count($resultSet)) {
165
            return $resultSet[0];
166
        }
167
168
        throw new RecordNotFoundException(
169
            sprintf(
170
                '%s record not found by %s %s',
171
                $this->getTableName(),
172
                $this->getIdColumn(),
173
                $id
174
            )
175
        );
176
    }
177
178
    public function findAllBy(array $conditions = array(), $limit = null, $offset = 0)
179
    {
180
        $sql = sprintf('SELECT * FROM %s', $this->getTableName());
181
182
        if ($conditions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $conditions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
183
            $whereConditions = $this->assembleEquality($conditions);
184
            $where = sprintf('WHERE %s', implode(' AND ', $whereConditions));
185
            $sql .= " $where";
186
        }
187
188
        if ($limit) {
189
            $sql .= sprintf(' LIMIT %s, %s', (int) $offset, (int) $limit);
190
        }
191
192
        return $this->selectQuery($sql, $conditions);
193
    }
194
195
    private function assembleEquality(array $conditions, $placeholderPrefix = '')
196
    {
197
        $placeholders = $this->columnsToPlaceholders(array_keys($conditions), $placeholderPrefix);
198
        $equalities = array();
199
200
        foreach ($placeholders as $column => $placeholder) {
201
            $equalities[] = "$column = $placeholder";
202
        }
203
204
        return $equalities;
205
    }
206
207
    /**
208
     * @param array $conditions
209
     * @param array $values
210
     */
211
    public function updateWhere(array $conditions, array $values)
212
    {
213
        $conditionsParams = array();
214
215
        foreach ($conditions as $column => $value) {
216
            $conditionsParams["_$column"] = $value;
217
        }
218
219
        $conditions = $this->assembleEquality($conditions, '_');
220
        $conditionsString = implode(' AND ', $conditions);
221
222
        $modifications = $this->assembleEquality($values);
223
        $modificationsString = implode(', ', $modifications);
224
225
        $sql = sprintf(
226
            'UPDATE %s SET %s WHERE %s',
227
            $this->getTableName(),
228
            $modificationsString,
229
            $conditionsString
230
        );
231
232
        $params = array_merge($conditionsParams, $values);
233
        $stmt = $this->getConnection()->prepare($sql);
234
        $stmt->execute($params);
235
    }
236
237
    public function findOneBy(array $conditions)
238
    {
239
        $result = $this->findAllBy($conditions, 1);
240
241
        if ($result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
242
            return $result[0];
243
        }
244
245
        throw new RecordNotFoundException('Record not found');
246
    }
247
248
    public function exists(array $conditions)
249
    {
250
        $resultSet = $this->findAllBy($conditions, 1);
251
        return count($resultSet) !== 0;
252
    }
253
254
    /**
255
     * @param array $conditions
256
     */
257
    public function deleteWhere(array $conditions)
258
    {
259
        $equalities = $this->assembleEquality($conditions);
260
        $conditionsString = implode(' AND ', $equalities);
261
262
        $sql = sprintf(
263
            'DELETE FROM %s WHERE %s',
264
            $this->getTableName(),
265
            $conditionsString
266
        );
267
268
        $stmt = $this->getConnection()->prepare($sql);
269
        $stmt->execute($conditions);
270
    }
271
}
272