Completed
Pull Request — master (#268)
by
unknown
02:52 queued 01:29
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
6
    \Xhgui_StorageInterface,
7
    \Xhgui_WatchedFunctionsStorageInterface
8
{
9
10
    /**
11
     * @var \PDO
12
     */
13
    protected $connection;
14
15
    /**
16
     * PDO constructor.
17
     * @param $config
18
     */
19
    public function __construct($config)
20
    {
21
        $this->connection = new \PDO(
22
            $config['db.dsn'],
23
            !empty($config['db.user'])      ? $config['db.user'] : null,
24
            !empty($config['db.password'])  ? $config['db.password'] : null,
25
            !empty($config['db.options'])   ? $config['db.options'] : []
26
        );
27
        $this->connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
28
        $this->connection->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
29
    }
30
31
    /**
32
     * @inheritDoc
33
     * @param \Xhgui_Storage_Filter $filter
34
     * @param bool $projections
35
     * @return \Xhgui_Storage_ResultSet
36
     */
37
    public function find(\Xhgui_Storage_Filter $filter, $projections = false)
38
    {
39
        list($query, $params) = $this->getQuery($filter, false);
40
        
41
        try {
42
            $stmt = $this->connection->prepare($query);
43
            $stmt->execute($params);
44
        } catch (\Exception $e) {
45
            print_r($e->getMessage());
46
            exit;
47
        }
48
49
        $tmp = [];
50
        while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
51
            $tmp[$row['id']] = $row;
52
            $tmp[$row['id']]['profile']    = json_decode($row['profiles'], true);
53
            $tmp[$row['id']]['meta']       = json_decode($row['meta'], true);
54
        }
55
        
56
        return new \Xhgui_Storage_ResultSet($tmp);
57
    }
58
59
    /**
60
     * Get query that is used for both list and count
61
     *
62
     * @param \Xhgui_Storage_Filter $filter
63
     * @param bool $count
64
     * @return array
65
     */
66
    protected function getQuery(\Xhgui_Storage_Filter $filter, $count = false)
67
    {
68
        $params = [];
69
70
        if ($count === true) {
71
            $columns = ' count(*) as c ';
72
        } else {
73
            $columns = ' p.*, i.*, m.*, p.profile_id as _id, main_wt as duration ';
74
        }
75
76
        $sql = "
77
select 
78
    $columns
79
from 
80
    profiles as p left join 
81
    profiles_info as i on (p.profile_id = i.id) LEFT JOIN
82
    profiles_meta as m on (p.profile_id = m.profile_id)
83
";
84
85
        $where = [];
86
87
        foreach ([
88
            'url'               => 'url',
89
            'method'            => 'method',
90
            'application'       => 'application',
91
            'version'           => 'version',
92
            'branch'            => 'branch',
93
            'controller'        => 'controller',
94
            'action'            => 'action',
95
            ] as $dbField => $field) {
96
            $method = 'get'.ucfirst($field);
97
98
            if ($filter->{$method}()) {
99
                $where[]        = ' '.$dbField.' = :'.$field.' ';
100
                $params[$field]  = $filter->{$method}();
101
            }
102
        }
103
        
104
        if ($filter->getStartDate()) {
105
            $where[]                = ' request_time >= :startDate';
106
            $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...
107
                                          ->format('Y-m-d H:i:s');
108
        }
109
110
        if ($filter->getEndDate()) {
111
            $where[]                = ' request_time <= :endDate';
112
            $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...
113
                                        ->format('Y-m-d H:i:s');
114
        }
115
116
        if (!empty($where)) {
117
            $sql .= ' WHERE '.join(' AND ', $where);
118
        }
119
120
        if ($count === true) {
121
            return [$sql, $params];
122
        }
123
124
        switch ($filter->getSort()) {
125
            case 'ct':
126
                $sql .= ' order by main_ct';
127
                break;
128
129
            case 'wt':
130
                $sql .= ' order by main_wt';
131
                break;
132
133
            case 'cpu':
134
                $sql .= ' order by main_cpu';
135
                break;
136
137
            case 'mu':
138
                $sql .= ' order by main_mu';
139
                break;
140
141
            case 'pmu':
142
                $sql .= ' order by main_pmu';
143
                break;
144
145
            case 'controller':
146
                $sql .= ' order by controller';
147
                break;
148
149
            case 'action':
150
                $sql .= ' order by action';
151
                break;
152
153
            case 'application':
154
                $sql .= ' order by application';
155
                break;
156
157
            case 'branch':
158
                $sql .= ' order by branch';
159
                break;
160
161
            case 'version':
162
                $sql .= ' order by version';
163
                break;
164
165
            case 'time':
166
            default:
167
                $sql .= ' order by request_time';
168
                break;
169
        }
170
171
        switch ($filter->getDirection()) {
172
            case 'asc':
173
                $sql .= ' asc ';
174
                break;
175
176
            default:
177
            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...
178
                $sql .= ' desc ';
179
                break;
180
        }
181
182
        if ($filter->getPerPage()) {
183
            $sql            .= ' LIMIT :limit ';
184
            $params['limit'] = (int)$filter->getPerPage();
185
        }
186
187
        if ($filter->getPage()) {
188
            $sql                .= ' OFFSET :offset ';
189
            $params['offset']   = (int)($filter->getPerPage()*($filter->getPage()-1));
190
        }
191
        return [$sql, $params];
192
    }
193
194
    /**
195
     * @inheritDoc
196
     * @param Xhgui_Storage_Filter $filter
197
     * @param $col
198
     * @param int $percentile
199
     * @return array
200
     * @throws Exception
201
     */
202
    public function aggregate(\Xhgui_Storage_Filter $filter, $col, $percentile = 1)
203
    {
204
        $stmt = $this->connection->prepare('select 
205
    * 
206
from 
207
    profiles_info
208
where 
209
    url = :url
210
');
211
        $stmt->execute(['url'=> $filter->getUrl()]);
212
        $aggregatedData = [];
213
        while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
214
            $date = new \DateTime($row['request_time']);
215
            $formattedDate = $date->format('Y-m-d');
216
            if (empty($aggregatedData[$date->format('Y-m-d')])) {
217
                $aggregatedData[$date->format('Y-m-d')] = [
218
                    'wall_times'    => [],
219
                    'cpu_times'     => [],
220
                    'mu_times'      => [],
221
                    'pmu_times'     => [],
222
                    'row_count'     => 0
223
                ];
224
            }
225
226
            $aggregatedData[$formattedDate]['wall_times'][] = $row['main_wt'];
227
            $aggregatedData[$formattedDate]['cpu_times'][]  = $row['main_ct'];
228
            $aggregatedData[$formattedDate]['mu_times'][]   = $row['main_mu'];
229
            $aggregatedData[$formattedDate]['pmu_times'][]  = $row['main_pmu'];
230
            $aggregatedData[$formattedDate]['row_count']++;
231
            $aggregatedData[$formattedDate]['_id']          = $formattedDate;
232
            $aggregatedData[$formattedDate]['raw_index']    =
233
                $aggregatedData[$formattedDate]['row_count']*($percentile/100);
234
        }
235
236
        $return = [
237
            'ok'    => 1,
238
            'result'=> array_values($aggregatedData),
239
        ];
240
        return $return;
241
    }
242
243
    /**
244
     * @inheritDoc
245
     * @@param Xhgui_Storage_Filter $filter
246
     * @return int
247
     */
248
    public function count(\Xhgui_Storage_Filter $filter)
249
    {
250
        list($query, $params) = $this->getQuery($filter, true);
251
        try {
252
            $stmt = $this->connection->prepare($query);
253
            $stmt->execute($params);
254
        } catch (\Exception $e) {
255
            print_r($e->getMessage());
256
            exit;
257
        }
258
259
        $ret = $stmt->fetch(\PDO::FETCH_ASSOC);
260
261
        if (!empty($ret['c'])) {
262
            return $ret['c'];
263
        }
264
        return 0;
265
    }
266
267
    /**
268
     * @inheritDoc
269
     * @param $id
270
     * @return mixed
271
     */
272
    public function findOne($id)
273
    {
274
        $stmt = $this->connection->prepare('
275
select 
276
    * 
277
from 
278
    profiles as p left join 
279
    profiles_info as i on (p.profile_id = i.id) LEFT JOIN
280
    profiles_meta as m on (p.profile_id = m.profile_id)
281
where 
282
    p.profile_id = :id
283
');
284
285
        $stmt->execute(['id'=>$id]);
286
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
287
        $row['profile'] = json_decode($row['profiles'], true);
288
        $row['meta']    = json_decode($row['meta'], true);
289
        $row['_id']     = $id;
290
291
        return $row;
292
    }
293
294
    /**
295
     * @inheritDoc
296
     * @param $id
297
     */
298
    public function remove($id)
299
    {
300
        $this->connection->beginTransaction();
301
        try {
302
            $profileStmt = $this->connection->prepare('delete from profiles where profile_id = :id');
303
            $profileStmt->execute(['id'=>$id]);
304
305
            $metaStmt = $this->connection->prepare('delete from profiles_meta where profile_id = :id');
306
            $metaStmt->execute(['id'=>$id]);
307
308
            $infoStmt = $this->connection->prepare('delete from profiles_info where id = :id');
309
            $infoStmt->execute(['id'=>$id]);
310
            
311
            $this->connection->commit();
312
        } catch (\Exception $e) {
313
            $this->connection->rollBack();
314
        }
315
    }
316
317
    /**
318
     * @inheritDoc
319
     * Remove all data from profile tables
320
     */
321
    public function drop()
322
    {
323
        $this->connection->exec('delete from profiles');
324
        $this->connection->exec('delete from profiles_meta');
325
        $this->connection->exec('delete from profiles_info');
326
    }
327
328
    /**
329
     * @inheritDoc
330
     * @return array
331
     */
332
    public function getWatchedFunctions()
333
    {
334
        $stmt = $this->connection->query('select * from watched order by name desc');
335
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
336
    }
337
338
    /**
339
     * @inheritDoc
340
     * @param $name
341
     * @return bool
342
     */
343
    public function addWatchedFunction($name)
344
    {
345
        $name = trim($name);
346
        if (empty($name)) {
347
            return false;
348
        }
349
        $stmt = $this->connection->prepare('INSERT INTO watched (name) VALUES (:name)');
350
        $stmt->execute(['name'=>trim($name)]);
351
        return true;
352
    }
353
354
    /**
355
     * @inheritDoc
356
     * @param $id
357
     * @param $name
358
     */
359
    public function updateWatchedFunction($id, $name)
360
    {
361
        $stmt = $this->connection->prepare('update watched set name=:name where id = :id');
362
        $stmt->execute(['id'=>$id, 'name'=>$name]);
363
    }
364
365
    /**
366
     * @inheritDoc
367
     * @param $id
368
     */
369
    public function removeWatchedFunction($id)
370
    {
371
        $stmt = $this->connection->prepare('delete from watched where id = :id');
372
        $stmt->execute(['id'=>$id]);
373
    }
374
375
    /**
376
     * @inheritDoc
377
     * @param array $data
378
     */
379
    public function insert(array $data)
380
    {
381
        // TODO: Implement insert() method.
382
    }
383
384
    /**
385
     * @inheritDoc
386
     * @param $_id
387
     * @param array $data
388
     */
389
    public function update($_id, array $data)
390
    {
391
        // TODO: Implement update() method.
392
    }
393
}
394