Completed
Push — master ( 54b2f0...ccd642 )
by Gabor
03:11
created

PDOAdapter   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 265
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 6
Bugs 3 Features 1
Metric Value
wmc 27
c 6
b 3
f 1
lcom 1
cbo 2
dl 0
loc 265
ccs 23
cts 23
cp 1
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 20 3
A getDataStorage() 0 4 1
A setDataGroup() 0 10 2
A setIdKey() 0 10 2
A getData() 0 7 1
A getDataSet() 0 7 1
A getDataCardinality() 0 7 1
B getStatementForExpression() 0 34 6
B saveData() 0 29 5
A bindValuesToStatement() 0 14 4
A deleteData() 0 6 1
1
<?php
2
/**
3
 * WebHemi.
4
 *
5
 * PHP version 5.6
6
 *
7
 * @copyright 2012 - 2016 Gixx-web (http://www.gixx-web.com)
8
 * @license   https://opensource.org/licenses/MIT The MIT License (MIT)
9
 *
10
 * @link      http://www.gixx-web.com
11
 */
12
namespace WebHemi\Adapter\Data\PDO;
13
14
use PDO;
15
use PDOStatement;
16
use WebHemi\Adapter\Data\DataAdapterInterface;
17
use WebHemi\Adapter\Exception\InitException;
18
use WebHemi\Adapter\Exception\InvalidArgumentException;
19
20
/**
21
 * Class PDOAdapter.
22
 */
23
class PDOAdapter implements DataAdapterInterface
24
{
25
    /** @var PDO */
26
    private $dataStorage;
27
    /** @var string */
28
    private $dataGroup = null;
29
    /** @var string */
30
    private $idKey = null;
31
32
    /**
33
     * PDOAdapter constructor.
34
     *
35
     * @param PDO $dataStorage
36
     *
37
     * @throws InvalidArgumentException
38
     */
39 4
    public function __construct($dataStorage = null)
40
    {
41 4
        if (!$dataStorage instanceof PDO) {
42 1
            $type = gettype($dataStorage);
43
44 1
            if ($type == 'object') {
45 1
                $type = get_class($dataStorage);
46
            }
47
48 1
            $message = sprintf(
49 1
                'Can\'t create %s instance. The parameter must be an instance of PDO, %s given.',
50 1
                __CLASS__,
51
                $type
52
            );
53
54 1
            throw new InvalidArgumentException($message);
55
        }
56
57 4
        $this->dataStorage = $dataStorage;
58 4
    }
59
60
    /**
61
     * Returns the Data Storage instance.
62
     *
63
     * @return PDO
64
     */
65 1
    public function getDataStorage()
66
    {
67 1
        return $this->dataStorage;
68
    }
69
70
    /**
71
     * Set adapter data group. For Databases this can be the Tables.
72
     *
73
     * @param string $dataGroup
74
     *
75
     * @throws InitException
76
     *
77
     * @return PDOAdapter
78
     */
79 1
    public function setDataGroup($dataGroup)
80
    {
81 1
        if (!empty($this->dataGroup)) {
82 1
            throw new InitException('Can\'t re-initialize dataGroup property. Property is already set.');
83
        }
84
85 1
        $this->dataGroup = $dataGroup;
86
87 1
        return $this;
88
    }
89
90
    /**
91
     * Set adapter ID key. For Databases this can be the Primary key. Only simple key is allowed.
92
     *
93
     * @param string $idKey
94
     *
95
     * @throws InitException
96
     *
97
     * @return PDOAdapter
98
     */
99 1
    public function setIdKey($idKey)
100
    {
101 1
        if (!empty($this->idKey)) {
102 1
            throw new InitException('Can\'t re-initialize idKey property. Property is already set.');
103
        }
104
105 1
        $this->idKey = $idKey;
106
107 1
        return $this;
108
    }
109
110
    /**
111
     * Get exactly one "row" of data according to the expression.
112
     *
113
     * @param mixed $identifier
114
     *
115
     * @return array
116
     *
117
     * @codeCoverageIgnore Don't test external library.
118
     */
119
    public function getData($identifier)
120
    {
121
        $statement = $this->getDataStorage()->prepare("SELECT * FROM {$this->dataGroup} WHERE {$this->idKey}=?");
122
        $statement->execute([$identifier]);
123
124
        return $statement->fetch(PDO::FETCH_ASSOC);
125
    }
126
127
    /**
128
     * Get a set of data according to the expression and the chunk.
129
     *
130
     * @param array $expression
131
     * @param int   $limit
132
     * @param int   $offset
133
     *
134
     * @return array
135
     *
136
     * @codeCoverageIgnore Don't test external library.
137
     */
138
    public function getDataSet(array $expression, $limit = null, $offset = null)
139
    {
140
        $statement = $this->getStatementForExpression($expression, $limit, $offset);
141
        $statement->execute();
142
143
        return $statement->fetchAll(PDO::FETCH_ASSOC);
144
    }
145
146
    /**
147
     * Get the number of matched data in the set according to the expression.
148
     *
149
     * @param array $expression
150
     *
151
     * @return int
152
     *
153
     * @codeCoverageIgnore Don't test external library.
154
     */
155
    public function getDataCardinality(array $expression)
156
    {
157
        $statement = $this->getStatementForExpression($expression);
158
        $statement->execute();
159
160
        return $statement->rowCount();
161
    }
162
163
    /**
164
     * Build query statement from the expression.
165
     *
166
     * @param array $expression
167
     * @param int   $limit
168
     * @param int   $offset
169
     *
170
     * @return PDOStatement
171
     *
172
     * @codeCoverageIgnore Don't test external library.
173
     */
174
    private function getStatementForExpression(array $expression, $limit = null, $offset = null)
175
    {
176
        $query = "SELECT * FROM {$this->dataGroup}";
177
        $queryParams = [];
178
        $queryBind = [];
179
180
        // Prepare WHERE expression.
181
        if (!empty($expression)) {
182
            $query .= ' WHERE ';
183
184
            foreach ($expression as $column => $value) {
185
                // allow special cases
186
                // @example  ['my_column LIKE ?' => 'some value%']
187
                $queryParams[] = strpos($column, '?') === false ? "{$column}=?" : $column;
188
                $queryBind[] = $value;
189
            }
190
191
            $query .= implode(' AND ', $queryParams);
192
        }
193
194
        // Prepare LIMIT and OFFSET
195
        if (!empty($limit)) {
196
            $query .= " LIMIT {$limit}";
197
198
            if (!is_null($offset)) {
199
                $query .= " OFFSET {$offset}";
200
            }
201
        }
202
203
        $statement = $this->getDataStorage()->prepare($query);
204
        $this->bindValuesToStatement($statement, $queryBind);
205
206
        return $statement;
207
    }
208
209
    /**
210
     * Insert or update entity in the storage.
211
     *
212
     * @param mixed $identifier
213
     * @param array $data
214
     *
215
     * @return mixed The ID of the saved entity in the storage
216
     *
217
     * @codeCoverageIgnore Don't test external library.
218
     */
219
    public function saveData($identifier, array $data)
220
    {
221
        if (empty($identifier)) {
222
            $query = "INSERT INTO {$this->dataGroup}";
223
        } else {
224
            $query = "UPDATE {$this->dataGroup}";
225
        }
226
227
        $queryData = [];
228
        $queryBind = [];
229
230
        foreach ($data as $fieldName => $value) {
231
            $queryData[] = "{$fieldName}=?";
232
            $queryBind[] = $value;
233
        }
234
235
        $query .= ' SET '.implode(', ', $queryData);
236
237
        if (!empty($identifier)) {
238
            $query .= " WHERE {$this->idKey}=?";
239
            $queryBind[] = $identifier;
240
        }
241
242
        $statement = $this->getDataStorage()->prepare($query);
243
        $this->bindValuesToStatement($statement, $queryBind);
244
        $statement->execute();
245
246
        return empty($identifier) ? $this->getDataStorage()->lastInsertId() : $identifier;
247
    }
248
249
    /**
250
     * Binds values to the statement.
251
     *
252
     * @param PDOStatement $statement
253
     * @param array        $queryBind
254
     *
255
     * @codeCoverageIgnore Don't test external library.
256
     */
257
    private function bindValuesToStatement(PDOStatement &$statement, array $queryBind)
258
    {
259
        foreach ($queryBind as $index => $data) {
260
            $paramType = PDO::PARAM_STR;
261
262
            if (is_null($data)) {
263
                $paramType = PDO::PARAM_NULL;
264
            } elseif (is_numeric($data)) {
265
                $paramType = PDO::PARAM_INT;
266
            }
267
268
            $statement->bindValue($index + 1, $data, $paramType);
269
        }
270
    }
271
272
    /**
273
     * Removes an entity from the storage.
274
     *
275
     * @param mixed $identifier
276
     *
277
     * @return bool
278
     *
279
     * @codeCoverageIgnore Don't test external library.
280
     */
281
    public function deleteData($identifier)
282
    {
283
        $statement = $this->getDataStorage()->prepare("DELETE FROM WHERE {$this->idKey}=?");
284
285
        return $statement->execute([$identifier]);
286
    }
287
}
288