Completed
Push — master ( f22a46...046041 )
by Patrick
02:27 queued 12s
created

SQLDataSet::getOrderByClause()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 3
nop 1
dl 0
loc 15
rs 9.7666
c 0
b 0
f 0
1
<?php
2
namespace Flipside\Data;
3
4
class SQLDataSet extends DataSet
5
{
6
    protected $pdo;
7
    protected $params;
8
9
    /**
10
     * Create a new SQLDataSet
11
     *
12
     * @param array $params An array containing atleast 'dsn' and possibly 'user' and 'pass'
13
     */
14
    public function __construct($params)
15
    {
16
        $this->params = $params;
17 View Code Duplication
        if(isset($params['user']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
18
        {
19
            $this->pdo = new \PDO($params['dsn'], $params['user'], $params['pass']);
20
        }
21
        else
22
        {
23
            $this->pdo = new \PDO($params['dsn']);
24
        }
25
    }
26
27
    public function __sleep()
28
    {
29
        $this->pdo = null;
30
        return array('params');
31
    }
32
33
    public function __wakeup()
34
    {
35
        $this->connect();
36
    }
37
38
    protected function connect()
39
    {
40
        if(isset($this->params['user']))
41
        {
42
            $this->pdo = new \PDO($this->params['dsn'], $this->params['user'], $this->params['pass'], array(PDO::MYSQL_ATTR_FOUND_ROWS => true));
43
        }
44
        else
45
        {
46
            $this->pdo = new \PDO($this->params['dsn']);
47
        }
48
    }
49
50
    /**
51
     * Get the number of rows affected by the query
52
     *
53
     * @param string $sql The SQL string
54
     *
55
     * @return integer The number of rows affected by the query
56
     */
57
    private function _get_row_count_for_query($sql)
58
    {
59
        $stmt = $this->pdo->query($sql);
60
        if($stmt === false)
61
        {
62
            return 0;
63
        }
64
        $count = $stmt->rowCount();
65
        if($count === 0)
66
        {
67
            $array = $stmt->fetchAll();
68
            $count = count($array);
69
        }
70
        return $count;
71
    }
72
73
    private function _tableExistsNoPrefix($name)
74
    {
75
        if($this->_get_row_count_for_query('SHOW TABLES LIKE '.$this->pdo->quote($name)) > 0)
76
        {
77
            return true;
78
        }
79
        else if($this->_get_row_count_for_query('SELECT * FROM sqlite_master WHERE name LIKE '.$this->pdo->quote($name)) > 0)
80
        {
81
            return true;
82
        }
83
        return false;
84
    }
85
86
    private function _tableExists($name)
87
    {
88
        return $this->_tableExistsNoPrefix('tbl'.$name);
89
    }
90
91
    private function _viewExists($name)
92
    {
93
        return $this->_tableExistsNoPrefix('v'.$name);
94
    }
95
96
    public function tableExists($name)
97
    {
98
        if($this->_tableExists($name))
99
        {
100
            return true;
101
        }
102
        if($this->_tableExistsNoPrefix($name))
103
        {
104
            return true;
105
        }
106
        if($this->_viewExists($name))
107
        {
108
            return true;
109
        }
110
        return false;
111
    }
112
113
    public function getTable($name)
114
    {
115
        if($this->_tableExists($name))
116
        {
117
            return new SQLDataTable($this, 'tbl'.$name);
118
        }
119
        if($this->_viewExists($name))
120
        {
121
            return new SQLDataTable($this, 'v'.$name);
122
        }
123
        if($this->_tableExistsNoPrefix($name))
124
        {
125
            return new SQLDataTable($this, $name);
126
        }
127
        throw new \Exception('No such table '.$name);
128
    }
129
130
    /**
131
     * @param boolean|array $sort The array to sort by or false to not sort
132
     */
133
    private function getOrderByClause($sort)
134
    {
135
        if(empty($sort))
136
        {
137
            return false;
138
        }
139
        $sql = ' ORDER BY ';
140
        $tmp = array();
141
        foreach($sort as $sort_col=>$dir)
0 ignored issues
show
Bug introduced by
The expression $sort of type boolean|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
142
        {
143
            array_push($tmp, $sort_col.' '.($dir === 1 ? 'ASC' : 'DESC'));
144
        }
145
        $sql .= implode($tmp, ',');
146
        return $sql;
147
    }
148
149
    /**
150
     * Convert OData style $count and $skip into SQL LIMIT
151
     *
152
     * @param boolean|string $count The number of items to return
153
     * @param boolean|string $skip The number of items to skip
154
     */
155
    private function getLimitClause($count, $skip)
156
    {
157
        if($count === false)
158
        {
159
            return false;
160
        }
161
        $count = intval($count);
162
        if($skip !== false)
163
        {
164
            $skip = intval($count);
165
            return " LIMIT $skip, $count";
166
        }
167
        return ' LIMIT '.$count;
168
    }
169
170
    /**
171
     * Read data from the specified SQL table
172
     *
173
     * @param string $tablename The name of the table to read from
174
     * @param boolean|string $where The where caluse of the SQL statement
175
     * @param string $select The colums to read
176
     * @param boolean|string $count The number of rows to read
177
     * @param boolean|string $skip The number of rows to skip over
178
     * @param boolean|array $sort The array to sort by or false to not sort
179
     *
180
     * @return false|array An array of all the returned records
181
     */
182
    public function read($tablename, $where = false, $select = '*', $count = false, $skip = false, $sort = false)
183
    {
184
        if($select === false)
185
        {
186
            $select = '*';
187
        }
188
        $sql = "SELECT $select FROM `$tablename`";
189
        if($where !== false)
190
        {
191
            $sql .= ' WHERE '.$where;
192
        }
193
        $tmp = $this->getLimitClause($count, $skip);
194
        if($tmp !== false)
195
        {
196
            $sql .= $tmp;
197
        }
198
        $tmp = $this->getOrderByClause($sort);
199
        if($tmp !== false)
200
        {
201
            $sql .= $tmp;
202
        }
203
        $stmt = $this->pdo->query($sql, \PDO::FETCH_ASSOC);
204
        if($stmt === false)
205
        {
206
            return false;
207
        }
208
        $ret = $stmt->fetchAll();
209
        if(empty($ret))
210
        {
211
            return false;
212
        }
213
        return $ret;
214
    }
215
216
    /**
217
     * Perform an SQL update on the specified table
218
     *
219
     * @param string $tablename The name of the table to insert to
220
     * @param string $where The where clause in SQL format
221
     * @param mixed $data The data to write to the table
222
     *
223
     * @return boolean true if successful, false otherwise
224
     */
225
    public function update($tablename, $where, $data)
226
    {
227
        $set = array();
228
        if(is_object($data))
229
        {
230
            $data = (array)$data;
231
        }
232
        $cols = array_keys($data);
233
        $count = count($cols);
234
        for($i = 0; $i < $count; $i++)
235
        {
236
            if($data[$cols[$i]] === null)
237
            {
238
                array_push($set, $cols[$i].'=NULL');
239
            }
240
            else
241
            {
242
                array_push($set, $cols[$i].'='.$this->pdo->quote($data[$cols[$i]]));
243
            }
244
        }
245
        $set = implode(',', $set);
246
        $sql = "UPDATE $tablename SET $set WHERE $where";
247
        $stmt = $this->pdo->query($sql);
248
        if($stmt === false)
249
        {
250 View Code Duplication
            if (php_sapi_name() !== "cli") {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
251
              error_log('DB query failed. '.print_r($this->pdo->errorInfo(), true));
252
            }
253
            return false;
254
        }
255
        else if($stmt->rowCount() === 0)
256
        {
257
            $data = $this->read($tablename, $where);
258
            if(empty($data))
259
            {
260
                return false;
261
            }
262
        }
263
        return true;
264
    }
265
266
    /**
267
     * Perform an SQL insert on the specified table
268
     *
269
     * @param string $tablename The name of the table to insert to
270
     * @param mixed $data The data to write to the table
271
     *
272
     * @return boolean true if successful, false otherwise
273
     */
274
    public function create($tablename, $data)
275
    {
276
        $set = array();
277
        if(is_object($data))
278
        {
279
            $data = (array)$data;
280
        }
281
        $cols = array_keys($data);
282
        $count = count($cols);
283
        for($i = 0; $i < $count; $i++)
284
        {
285
            if($data[$cols[$i]] === null)
286
            {
287
                array_push($set, 'NULL');
288
            }
289
            else
290
            {
291
                array_push($set, $this->pdo->quote($data[$cols[$i]]));
292
            }
293
        }
294
        $cols = implode(',', $cols);
295
        $set = implode(',', $set);
296
        $sql = "INSERT INTO $tablename ($cols) VALUES ($set);";
297
        if($this->pdo->exec($sql) === false)
298
        {
299 View Code Duplication
            if (php_sapi_name() !== "cli") {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
300
                error_log('DB query failed. '.print_r($this->pdo->errorInfo(), true));
301
            }
302
            return false;
303
        }
304
        return true;
305
    }
306
307
    /**
308
     * Perform an SQL delete on the specified table
309
     *
310
     * @param string $tablename The name of the table to insert to
311
     * @param string $where The where clause in SQL format
312
     *
313
     * @return boolean true if successful, false otherwise
314
     */
315
    public function delete($tablename, $where)
316
    {
317
        $sql = "DELETE FROM $tablename WHERE $where";
318
        if($this->pdo->exec($sql) === false)
319
        {
320
            return false;
321
        }
322
        return true;
323
    }
324
325
    /**
326
     * Perform an SQL query
327
     *
328
     * @param string $sql The raw SQL
329
     *
330
     * @return mixed false on a failure, an array of data otherwise
331
     */
332
    public function raw_query($sql)
333
    {
334
        $stmt = $this->pdo->query($sql, \PDO::FETCH_ASSOC);
335
        if($stmt === false)
336
        {
337
            return false;
338
        }
339
        $ret = $stmt->fetchAll();
340
        return $ret;
341
    }
342
343
    public function getLastError()
344
    {
345
        return $this->pdo->errorInfo();
346
    }
347
}
348
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
349