Completed
Pull Request — master (#268)
by
unknown
01:16
created

Xhgui_Storage_PDO::getQuery()   F

Complexity

Conditions 23
Paths 4656

Size

Total Lines 127

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 127
rs 0
c 0
b 0
f 0
cc 23
nc 4656
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Get profiles using PDO database connection
4
 */
5
class Xhgui_Storage_PDO extends Xhgui_Storage_Abstract implements \Xhgui_StorageInterface,
6
    \Xhgui_WatchedFunctionsStorageInterface
7
{
8
9
    /**
10
     * @var \PDO
11
     */
12
    protected $connection;
13
14
    /**
15
     * PDO constructor.
16
     * @param $config
17
     */
18
    public function __construct($config)
19
    {
20
        $this->connection = new \PDO(
21
            $config['db.dsn'],
22
            !empty($config['db.user'])      ? $config['db.user'] : null,
23
            !empty($config['db.password'])  ? $config['db.password'] : null,
24
            !empty($config['db.options'])   ? $config['db.options'] : []
25
        );
26
        $this->connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
27
        $this->connection->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
28
    }
29
30
    /**
31
     * @inheritDoc
32
     * @param \Xhgui_Storage_Filter $filter
33
     * @param bool $projections
34
     * @return \Xhgui_Storage_ResultSet
35
     */
36
    public function find(\Xhgui_Storage_Filter $filter, $projections = false)
37
    {
38
        list($query, $params) = $this->getQuery($filter, false);
39
        
40
        try {
41
            $stmt = $this->connection->prepare($query);
42
            $stmt->execute($params);
43
        } catch (\Exception $e) {
44
            print_r($e->getMessage());
45
            exit;
46
        }
47
48
        $tmp = [];
49
        while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
50
            $tmp[$row['id']] = $row;
51
            $tmp[$row['id']]['profile']    = json_decode($row['profiles'], true);
52
            $tmp[$row['id']]['meta']       = json_decode($row['meta'], true);
53
        }
54
        
55
        return new \Xhgui_Storage_ResultSet($tmp);
56
    }
57
58
    /**
59
     * Get query that is used for both list and count
60
     *
61
     * @param \Xhgui_Storage_Filter $filter
62
     * @param bool $count
63
     * @return array
64
     */
65
    protected function getQuery(\Xhgui_Storage_Filter $filter, $count = false)
66
    {
67
        $params = [];
68
69
        if ($count === true) {
70
            $columns = ' count(*) as c ';
71
        } else {
72
            $columns = ' p.*, i.*, m.*, p.profile_id as _id, main_wt as duration ';
73
        }
74
75
        $sql = "
76
select 
77
    $columns
78
from 
79
    profiles as p left join 
80
    profiles_info as i on (p.profile_id = i.id) LEFT JOIN
81
    profiles_meta as m on (p.profile_id = m.profile_id)
82
";
83
84
        $where = [];
85
86
        foreach ([
87
            'url'               => 'url',
88
            'method'            => 'method',
89
            'application'       => 'application',
90
            'version'           => 'version',
91
            'branch'            => 'branch',
92
            'controller'        => 'controller',
93
            'action'            => 'action',
94
            ] as $dbField => $field) {
95
            $method = 'get'.ucfirst($field);
96
97
            if ($filter->{$method}()) {
98
                $where[]        = ' '.$dbField.' = :'.$field.' ';
99
                $params[$field]  = $filter->{$method}();
100
            }
101
        }
102
        
103
        if ($filter->getStartDate()) {
104
            $where[]                = ' request_time >= :startDate';
105
            $params['startDate']   = $this->getDateTimeFromString($filter->getStartDate(), 'start')
0 ignored issues
show
Documentation introduced by
$filter->getStartDate() is of type object<DateTime>, but the function expects a string|integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
106
                                          ->format('Y-m-d H:i:s');
107
        }
108
109
        if ($filter->getEndDate()) {
110
            $where[]                = ' request_time <= :endDate';
111
            $params['endDate']   = $this->getDateTimeFromString($filter->getEndDate(), 'end')
0 ignored issues
show
Documentation introduced by
$filter->getEndDate() is of type object<DateTime>, but the function expects a string|integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
112
                                        ->format('Y-m-d H:i:s');
113
        }
114
115
        if (!empty($where)) {
116
            $sql .= ' WHERE '.join(' AND ', $where);
117
        }
118
119
        if ($count === true) {
120
            return [$sql, $params];
121
        }
122
123
        switch ($filter->getSort()) {
124
            case 'ct':
125
                $sql .= ' order by main_ct';
126
                break;
127
128
            case 'wt':
129
                $sql .= ' order by main_wt';
130
                break;
131
132
            case 'cpu':
133
                $sql .= ' order by main_cpu';
134
                break;
135
136
            case 'mu':
137
                $sql .= ' order by main_mu';
138
                break;
139
140
            case 'pmu':
141
                $sql .= ' order by main_pmu';
142
                break;
143
144
            case 'controller':
145
                $sql .= ' order by controller';
146
                break;
147
148
            case 'action':
149
                $sql .= ' order by action';
150
                break;
151
152
            case 'application':
153
                $sql .= ' order by application';
154
                break;
155
156
            case 'branch':
157
                $sql .= ' order by branch';
158
                break;
159
160
            case 'version':
161
                $sql .= ' order by version';
162
                break;
163
164
            case 'time':
165
            default:
166
                $sql .= ' order by request_time';
167
                break;
168
        }
169
170
        switch ($filter->getDirection()) {
171
            case 'asc':
172
                $sql .= ' asc ';
173
                break;
174
175
            default:
176
            case 'desc':
0 ignored issues
show
Unused Code introduced by
case 'desc': $sql .= ' desc '; break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
177
                $sql .= ' desc ';
178
                break;
179
        }
180
181
        if ($filter->getPerPage()) {
182
            $sql            .= ' LIMIT :limit ';
183
            $params['limit'] = (int)$filter->getPerPage();
184
        }
185
186
        if ($filter->getPage()) {
187
            $sql                .= ' OFFSET :offset ';
188
            $params['offset']   = (int)($filter->getPerPage()*($filter->getPage()-1));
189
        }
190
        return [$sql, $params];
191
    }
192
193
    /**
194
     * @inheritDoc
195
     * @param Xhgui_Storage_Filter $filter
196
     * @param $col
197
     * @param int $percentile
198
     * @return array
199
     * @throws Exception
200
     */
201
    public function aggregate(\Xhgui_Storage_Filter $filter, $col, $percentile = 1)
202
    {
203
        $stmt = $this->connection->prepare('select 
204
    * 
205
from 
206
    profiles_info
207
where 
208
    url = :url
209
');
210
        $stmt->execute(['url'=> $filter->getUrl()]);
211
        $aggregatedData = [];
212
        while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
213
            $date = new \DateTime($row['request_time']);
214
            $formattedDate = $date->format('Y-m-d');
215
            if (empty($aggregatedData[$date->format('Y-m-d')])) {
216
                $aggregatedData[$date->format('Y-m-d')] = [
217
                    'wall_times'    => [],
218
                    'cpu_times'     => [],
219
                    'mu_times'      => [],
220
                    'pmu_times'     => [],
221
                    'row_count'     => 0
222
                ];
223
            }
224
225
            $aggregatedData[$formattedDate]['wall_times'][] = $row['main_wt'];
226
            $aggregatedData[$formattedDate]['cpu_times'][]  = $row['main_ct'];
227
            $aggregatedData[$formattedDate]['mu_times'][]   = $row['main_mu'];
228
            $aggregatedData[$formattedDate]['pmu_times'][]  = $row['main_pmu'];
229
            $aggregatedData[$formattedDate]['row_count']++;
230
            $aggregatedData[$formattedDate]['_id']          = $formattedDate;
231
            $aggregatedData[$formattedDate]['raw_index']    =
232
                $aggregatedData[$formattedDate]['row_count']*($percentile/100);
233
        }
234
235
        $return = [
236
            'ok'    => 1,
237
            'result'=> array_values($aggregatedData),
238
        ];
239
        return $return;
240
    }
241
242
    /**
243
     * @inheritDoc
244
     * @@param Xhgui_Storage_Filter $filter
245
     * @return int
246
     */
247
    public function count(\Xhgui_Storage_Filter $filter)
248
    {
249
        list($query, $params) = $this->getQuery($filter, true);
250
        try {
251
            $stmt = $this->connection->prepare($query);
252
            $stmt->execute($params);
253
        } catch (\Exception $e) {
254
            print_r($e->getMessage());
255
            exit;
256
        }
257
258
        $ret = $stmt->fetch(\PDO::FETCH_ASSOC);
259
260
        if (!empty($ret['c'])) {
261
            return $ret['c'];
262
        }
263
        return 0;
264
    }
265
266
    /**
267
     * @inheritDoc
268
     * @param $id
269
     * @return mixed
270
     */
271
    public function findOne($id)
272
    {
273
        $stmt = $this->connection->prepare('
274
select 
275
    * 
276
from 
277
    profiles as p left join 
278
    profiles_info as i on (p.profile_id = i.id) LEFT JOIN
279
    profiles_meta as m on (p.profile_id = m.profile_id)
280
where 
281
    p.profile_id = :id
282
');
283
284
        $stmt->execute(['id'=>$id]);
285
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
286
        $row['profile'] = json_decode($row['profiles'], true);
287
        $row['meta']    = json_decode($row['meta'], true);
288
        $row['_id']     = $id;
289
290
        return $row;
291
    }
292
293
    /**
294
     * @inheritDoc
295
     * @param $id
296
     */
297
    public function remove($id)
298
    {
299
        $this->connection->beginTransaction();
300
        try {
301
            $profileStmt = $this->connection->prepare('delete from profiles where profile_id = :id');
302
            $profileStmt->execute(['id'=>$id]);
303
304
            $metaStmt = $this->connection->prepare('delete from profiles_meta where profile_id = :id');
305
            $metaStmt->execute(['id'=>$id]);
306
307
            $infoStmt = $this->connection->prepare('delete from profiles_info where id = :id');
308
            $infoStmt->execute(['id'=>$id]);
309
            
310
            $this->connection->commit();
311
        } catch (\Exception $e) {
312
            $this->connection->rollBack();
313
        }
314
    }
315
316
    /**
317
     * @inheritDoc
318
     * Remove all data from profile tables
319
     */
320
    public function drop()
321
    {
322
        $this->connection->exec('delete from profiles');
323
        $this->connection->exec('delete from profiles_meta');
324
        $this->connection->exec('delete from profiles_info');
325
    }
326
327
    /**
328
     * @inheritDoc
329
     * @return array
330
     */
331
    public function getWatchedFunctions()
332
    {
333
        $stmt = $this->connection->query('select * from watched order by name desc');
334
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
335
    }
336
337
    /**
338
     * @inheritDoc
339
     * @param $name
340
     * @return bool
341
     */
342
    public function addWatchedFunction($name)
343
    {
344
        $name = trim($name);
345
        if (empty($name)) {
346
            return false;
347
        }
348
        $stmt = $this->connection->prepare('INSERT INTO watched (name) VALUES (:name)');
349
        $stmt->execute(['name'=>trim($name)]);
350
        return true;
351
    }
352
353
    /**
354
     * @inheritDoc
355
     * @param $id
356
     * @param $name
357
     */
358
    public function updateWatchedFunction($id, $name)
359
    {
360
        $stmt = $this->connection->prepare('update watched set name=:name where id = :id');
361
        $stmt->execute(['id'=>$id, 'name'=>$name]);
362
    }
363
364
    /**
365
     * @inheritDoc
366
     * @param $id
367
     */
368
    public function removeWatchedFunction($id)
369
    {
370
        $stmt = $this->connection->prepare('delete from watched where id = :id');
371
        $stmt->execute(['id'=>$id]);
372
    }
373
374
    /**
375
     * @inheritDoc
376
     * @param array $data
377
     */
378
    public function insert(array $data)
379
    {
380
        // TODO: Implement insert() method.
381
    }
382
383
    /**
384
     * @inheritDoc
385
     * @param $_id
386
     * @param array $data
387
     */
388
    public function update($_id, array $data)
389
    {
390
        // TODO: Implement update() method.
391
    }
392
}
393