Completed
Push — master ( 06ade8...5dbfe3 )
by Patrick
02:29
created

SQLDataSet   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 305
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 0
loc 305
rs 8.439
c 0
b 0
f 0
wmc 47
lcom 1
cbo 2

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 2
A _get_row_count_for_query() 0 15 3
A _tableExistsNoPrefix() 0 12 3
A _tableExists() 0 4 1
A _viewExists() 0 4 1
A tableExists() 0 16 4
A getTable() 0 16 4
A getOrderByClause() 0 15 4
A getLimitClause() 0 14 3
C read() 0 33 7
B update() 0 28 5
B create() 0 30 5
A delete() 0 9 2
A raw_query() 0 10 2
A getLastError() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like SQLDataSet often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SQLDataSet, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Data;
3
4
class SQLDataSet extends DataSet
5
{
6
    protected $pdo;
7
8
    /**
9
     * Create a new SQLDataSet
10
     *
11
     * @param array $params An array containing atleast 'dsn' and possibly 'user' and 'pass'
12
     */
13
    public function __construct($params)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
14
    {
15
        if(isset($params['user']))
16
        {
17
            $this->pdo = new \PDO($params['dsn'], $params['user'], $params['pass']);
18
        }
19
        else
20
        {
21
            $this->pdo = new \PDO($params['dsn']);
22
        }
23
    }
24
25
    /**
26
     * Get the number of rows affected by the query
27
     *
28
     * @param string $sql The SQL string
29
     *
30
     * @return integer The number of rows affected by the query
31
     */
32
    private function _get_row_count_for_query($sql)
33
    {
34
        $stmt = $this->pdo->query($sql);
35
        if($stmt === false)
36
        {
37
            return 0;
38
        }
39
        $count = $stmt->rowCount();
40
        if($count === 0)
41
        {
42
            $array = $stmt->fetchAll();
43
            $count = count($array);
44
        }
45
        return $count;
46
    }
47
48
    private function _tableExistsNoPrefix($name)
49
    {
50
        if($this->_get_row_count_for_query('SHOW TABLES LIKE '.$this->pdo->quote($name)) > 0)
51
        {
52
            return true;
53
        }
54
        else if($this->_get_row_count_for_query('SELECT * FROM sqlite_master WHERE name LIKE '.$this->pdo->quote($name)) > 0)
55
        {
56
            return true;
57
        }
58
        return false;
59
    }
60
61
    private function _tableExists($name)
62
    {
63
        return $this->_tableExistsNoPrefix('tbl'.$name);
64
    }
65
66
    private function _viewExists($name)
67
    {
68
        return $this->_tableExistsNoPrefix('v'.$name);
69
    }
70
71
    public function tableExists($name)
72
    {
73
        if($this->_tableExists($name))
74
        {
75
            return true;
76
        }
77
        if($this->_tableExistsNoPrefix($name))
78
        {
79
            return true;
80
        }
81
        if($this->_viewExists($name))
82
        {
83
            return true;
84
        }
85
        return false;
86
    }
87
88
    public function getTable($name)
89
    {
90
        if($this->_tableExists($name))
91
        {
92
            return new SQLDataTable($this, 'tbl'.$name);
93
        }
94
        if($this->_viewExists($name))
95
        {
96
            return new SQLDataTable($this, 'v'.$name);
97
        }
98
        if($this->_tableExistsNoPrefix($name))
99
        {
100
            return new SQLDataTable($this, $name);
101
        }
102
        throw new \Exception('No such table '.$name);
103
    }
104
105
    /**
106
     * @param boolean|array $sort The array to sort by or false to not sort
107
     */
108
    private function getOrderByClause($sort)
109
    {
110
        if(empty($sort))
111
        {
112
            return false;
113
        }
114
        $sql = ' ORDER BY ';
115
        $tmp = array();
116
        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...
117
        {
118
            array_push($tmp, $sort_col.' '.($dir === 1 ? 'ASC' : 'DESC'));
119
        }
120
        $sql .= implode($tmp, ',');
121
        return $sql;
122
    }
123
124
    /**
125
     * Convert OData style $count and $skip into SQL LIMIT
126
     *
127
     * @param boolean|string $count The number of items to return
128
     * @param boolean|string $skip The number of items to skip
129
     */
130
    private function getLimitClause($count, $skip)
131
    {
132
        if($count === false)
133
        {
134
            return false;
135
        }
136
        $count = intval($count);
137
        if($skip !== false)
138
        {
139
            $skip = intval($count);
140
            return " LIMIT $skip, $count";
141
        }
142
        return ' LIMIT '.$count;
143
    }
144
145
    /**
146
     * Read data from the specified SQL table
147
     *
148
     * @param string $tablename The name of the table to read from
149
     * @param boolean|string $where The where caluse of the SQL statement
150
     * @param string $select The colums to read
151
     * @param boolean|string $count The number of rows to read
152
     * @param boolean|string $skip The number of rows to skip over
153
     * @param boolean|array $sort The array to sort by or false to not sort
154
     *
155
     * @return false|array An array of all the returned records
156
     */
157
    public function read($tablename, $where = false, $select = '*', $count = false, $skip = false, $sort = false)
158
    {
159
        if($select === false)
160
        {
161
            $select = '*';
162
        }
163
        $sql = "SELECT $select FROM `$tablename`";
164
        if($where !== false)
165
        {
166
            $sql .= ' WHERE '.$where;
167
        }
168
        $tmp = $this->getLimitClause($count, $skip);
169
        if($tmp !== false)
170
        {
171
            $sql .= $tmp;
172
        }
173
        $tmp = $this->getOrderByClause($sort);
174
        if($tmp !== false)
175
        {
176
            $sql .= $tmp;
177
        }
178
        $stmt = $this->pdo->query($sql, \PDO::FETCH_ASSOC);
179
        if($stmt === false)
180
        {
181
            return false;
182
        }
183
        $ret = $stmt->fetchAll();
184
        if(empty($ret))
185
        {
186
            return false;
187
        }
188
        return $ret;
189
    }
190
191
    /**
192
     * Perform an SQL update on the specified table
193
     *
194
     * @param string $tablename The name of the table to insert to
195
     * @param string $where The where clause in SQL format
196
     * @param mixed $data The data to write to the table
197
     *
198
     * @return boolean true if successful, false otherwise
199
     */
200
    public function update($tablename, $where, $data)
201
    {
202
        $set = array();
203
        if(is_object($data))
204
        {
205
            $data = (array)$data;
206
        }
207
        $cols = array_keys($data);
208
        $count = count($cols);
209
        for($i = 0; $i < $count; $i++)
210
        {
211
            if($data[$cols[$i]] === null)
212
            {
213
                array_push($set, $cols[$i].'=NULL');
214
            }
215
            else
216
            {
217
                array_push($set, $cols[$i].'='.$this->pdo->quote($data[$cols[$i]]));
218
            }
219
        }
220
        $set = implode(',', $set);
221
        $sql = "UPDATE $tablename SET $set WHERE $where";
222
        if($this->pdo->exec($sql) === false)
223
        {
224
            return false;
225
        }
226
        return true;
227
    }
228
229
    /**
230
     * Perform an SQL insert on the specified table
231
     *
232
     * @param string $tablename The name of the table to insert to
233
     * @param mixed $data The data to write to the table
234
     *
235
     * @return boolean true if successful, false otherwise
236
     */
237
    public function create($tablename, $data)
238
    {
239
        $set = array();
240
        if(is_object($data))
241
        {
242
            $data = (array)$data;
243
        }
244
        $cols = array_keys($data);
245
        $count = count($cols);
246
        for($i = 0; $i < $count; $i++)
247
        {
248
            if($data[$cols[$i]] === null)
249
            {
250
                array_push($set, 'NULL');
251
            }
252
            else
253
            {
254
                array_push($set, $this->pdo->quote($data[$cols[$i]]));
255
            }
256
        }
257
        $cols = implode(',', $cols);
258
        $set = implode(',', $set);
259
        $sql = "INSERT INTO $tablename ($cols) VALUES ($set);";
260
        if($this->pdo->exec($sql) === false)
261
        {
262
            //error_log($sql);
263
            return false;
264
        }
265
        return true;
266
    }
267
268
    /**
269
     * Perform an SQL delete on the specified table
270
     *
271
     * @param string $tablename The name of the table to insert to
272
     * @param string $where The where clause in SQL format
273
     *
274
     * @return boolean true if successful, false otherwise
275
     */
276
    public function delete($tablename, $where)
277
    {
278
        $sql = "DELETE FROM $tablename WHERE $where";
279
        if($this->pdo->exec($sql) === false)
280
        {
281
            return false;
282
        }
283
        return true;
284
    }
285
286
    /**
287
     * Perform an SQL query
288
     *
289
     * @param string $sql The raw SQL
290
     *
291
     * @return mixed false on a failure, an array of data otherwise
292
     */
293
    public function raw_query($sql)
294
    {
295
        $stmt = $this->pdo->query($sql, \PDO::FETCH_ASSOC);
296
        if($stmt === false)
297
        {
298
            return false;
299
        }
300
        $ret = $stmt->fetchAll();
301
        return $ret;
302
    }
303
304
    public function getLastError()
305
    {
306
        return $this->pdo->errorInfo();
307
    }
308
}
309
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
310