Completed
Pull Request — master (#268)
by
unknown
03:49 queued 02:35
created

Xhgui_Storage_PDO::getDateTimeFromString()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.2888
c 0
b 0
f 0
cc 5
nc 7
nop 1
1
<?php
2
class Xhgui_Storage_PDO implements \Xhgui_StorageInterface, \Xhgui_WatchedFunctionsStorageInterface {
3
4
    /**
5
     * @var \PDO
6
     */
7
    protected $connection;
8
9
    /**
10
     * PDO constructor.
11
     * @param $config
12
     */
13
    public function __construct($config)
14
    {
15
        $this->connection = new \PDO(
16
            $config['db.dsn'],
17
            !empty($config['db.user'])      ? $config['db.user'] : null,
18
            !empty($config['db.password'])  ? $config['db.password'] : null,
19
            !empty($config['db.options'])   ? $config['db.options'] : []
20
        );
21
        $this->connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
22
    }
23
24
    /**
25
     * @param \Xhgui_Storage_Filter $filter
26
     * @param bool $projections
27
     * @return \Xhgui_Storage_ResultSet
28
     */
29
    public function find(\Xhgui_Storage_Filter $filter, $projections = false)
30
    {
31
        list($query, $params) = $this->getQuery($filter, false);
32
//        print '<pre>';
33
//        print_r($query);
34
//        print_r($params);
35
//        print '</pre>';
36
//        exit;
37
        try {
38
            $stmt = $this->connection->prepare($query);
39
            $stmt->execute($params);
40
41
        } catch (\Exception $e) {
42
            print_r($e->getMessage());
43
            exit;
44
        }
45
46
        $tmp = [];
47
        while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
48
            $tmp[$row['id']] = $row;
49
            $tmp[$row['id']]['profile']    = json_decode($row['profiles'], true);
50
            $tmp[$row['id']]['meta']       = json_decode($row['meta'], true);
51
        }
52
        
53
        return new \Xhgui_Storage_ResultSet($tmp);
54
    }
55
56
    /**
57
     * @param \Xhgui_Storage_Filter $filter
58
     * @param bool $count
59
     * @return array
60
     */
61
    protected function getQuery(\Xhgui_Storage_Filter $filter, $count = false) {
62
        $params = [];
63
64
        if ($count === true) {
65
            $columns = ' count(*) as c ';
66
        } else {
67
            $columns = ' p.*, i.*, m.*, p.profile_id as _id, main_wt as duration ';
68
        }
69
70
        $sql = "
71
select 
72
    $columns
73
from 
74
    profiles as p left join 
75
    profiles_info as i on (p.profile_id = i.id) LEFT JOIN
76
    profiles_meta as m on (p.profile_id = m.profile_id)
77
";
78
79
        $where = [];
80
81
        foreach([
82
            'url'               => 'url',
83
            'method'            => 'method',
84
            'application'       => 'application',
85
            'version'           => 'version',
86
            'branch'            => 'branch',
87
            'controller'        => 'controller',
88
            'action'            => 'action',
89
            ] as $dbField => $field) {
90
91
            $method = 'get'.ucfirst($field);
92
93
            if ($filter->{$method}()) {
94
                $where[]        = ' '.$dbField.' = :'.$field.' ';
95
                $params[$field]  = $filter->{$method}();
96
            }
97
        }
98
        
99
        if ($filter->getStartDate()) {
100
            $where[]                = ' request_time >= datetime(:startDate)';
101
            $params['startDate']   = $this->getDateTimeFromString($filter->getStartDate())->format('Y-m-d H:i:s');
102
        }
103
104
        if ($filter->getEndDate()) {
105
            $where[]                = ' request_time <= datetime(:endDate)';
106
            $params['endDate']   = $this->getDateTimeFromString($filter->getEndDate())->format('Y-m-d H:i:s');
107
        }
108
109
        if (!empty($where)) {
110
            $sql .= ' WHERE '.join(' AND ', $where);
111
        }
112
113
        if ($count === true) {
114
            return [$sql, $params];
115
        }
116
117
        switch ($filter->getSort()) {
118
            case 'ct':
119
                $sql .= ' order by main_ct';
120
                break;
121
122
            case 'wt':
123
                $sql .= ' order by main_wt';
124
                break;
125
126
            case 'cpu':
127
                $sql .= ' order by main_cpu';
128
                break;
129
130
            case 'mu':
131
                $sql .= ' order by main_mu';
132
                break;
133
134
            case 'pmu':
135
                $sql .= ' order by main_pmu';
136
                break;
137
138
            case 'controller':
139
                $sql .= ' order by controller';
140
                break;
141
142
            case 'action':
143
                $sql .= ' order by action';
144
                break;
145
146
            case 'application':
147
                $sql .= ' order by application';
148
                break;
149
150
            case 'branch':
151
                $sql .= ' order by branch';
152
                break;
153
154
            case 'version':
155
                $sql .= ' order by version';
156
                break;
157
158
            default:
159
            case 'time':
0 ignored issues
show
Unused Code introduced by
case 'time': $sql .=...quest_time'; 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...
160
                $sql .= ' order by request_time';
161
                break;
162
        }
163
164
        switch ($filter->getDirection()) {
165
            case 'asc':
166
                $sql .= ' asc ';
167
                break;
168
169
            default:
170
            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...
171
                $sql .= ' desc ';
172
                break;
173
        }
174
175
        if ($filter->getPerPage()) {
176
            $sql            .= ' LIMIT :limit ';
177
            $params['limit'] = $filter->getPerPage();
178
        }
179
180
        if ($filter->getPage()) {
181
            $sql                .= ' OFFSET :offset ';
182
            $params['offset']   = ($filter->getPerPage()*($filter->getPage()-1));
183
        }
184
185
        return [$sql, $params];
186
    }
187
188
    public function aggregate(\Xhgui_Storage_Filter $filter, $col, $percentile = 1)
189
    {
190
        $stmt = $this->connection->prepare('select 
191
    * 
192
from 
193
    profiles_info
194
where 
195
    url = :url
196
');
197
        $stmt->execute(['url'=> $filter->getUrl()]);
198
        $aggregatedData = [];
199
        while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
200
            $date = new \DateTime($row['request_time']);
201
            $formattedDate = $date->format('Y-m-d');
202
            if (empty($aggregatedData[$date->format('Y-m-d')])) {
203
                $aggregatedData[$date->format('Y-m-d')] = [
204
                    'wall_times'    => [],
205
                    'cpu_times'     => [],
206
                    'mu_times'      => [],
207
                    'pmu_times'     => [],
208
                    'row_count'     => 0
209
                ];
210
            }
211
212
            $aggregatedData[$formattedDate]['wall_times'][] = $row['main_wt'];
213
            $aggregatedData[$formattedDate]['cpu_times'][]  = $row['main_ct'];
214
            $aggregatedData[$formattedDate]['mu_times'][]   = $row['main_mu'];
215
            $aggregatedData[$formattedDate]['pmu_times'][]  = $row['main_pmu'];
216
            $aggregatedData[$formattedDate]['row_count']++;
217
            $aggregatedData[$formattedDate]['_id']          = $formattedDate;
218
            $aggregatedData[$formattedDate]['raw_index']    = $aggregatedData[$formattedDate]['row_count']*($percentile/100);
219
        }
220
221
        $return = [
222
            'ok'    => 1,
223
            'result'=> array_values($aggregatedData),
224
        ];
225
        return $return;
226
    }
227
228
229
    public function count(\Xhgui_Storage_Filter $filter) {
230
        list($query, $params) = $this->getQuery($filter, true);
231
        try {
232
            $stmt = $this->connection->prepare($query);
233
            $stmt->execute($params);
234
235
        } catch (\Exception $e) {
236
            print_r($e->getMessage());
237
            exit;
238
        }
239
240
        $ret = $stmt->fetch(\PDO::FETCH_ASSOC);
241
242
        if (!empty($ret['c'])) {
243
            return $ret['c'];
244
        }
245
        return 0;
246
    }
247
248
    public function findOne($id)
249
    {
250
        $stmt = $this->connection->prepare('
251
select 
252
    * 
253
from 
254
    profiles as p left join 
255
    profiles_info as i on (p.profile_id = i.id) LEFT JOIN
256
    profiles_meta as m on (p.profile_id = m.profile_id)
257
where 
258
    p.profile_id = :id
259
');
260
261
        $stmt->execute(['id'=>$id]);
262
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
263
        $row['profile'] = json_decode($row['profiles'], true);
264
        $row['meta']    = json_decode($row['meta'], true);
265
        $row['_id']     = $id;
266
267
        return $row;
268
    }
269
270
    public function remove($id)
271
    {
272
        $this->connection->beginTransaction();
273
        try {
274
            $profileStmt = $this->connection->prepare('delete from profiles where profile_id = :id');
275
            $profileStmt->execute(['id'=>$id]);
276
277
            $metaStmt = $this->connection->prepare('delete from profiles_meta where profile_id = :id');
278
            $metaStmt->execute(['id'=>$id]);
279
280
            $infoStmt = $this->connection->prepare('delete from profiles_info where id = :id');
281
            $infoStmt->execute(['id'=>$id]);
282
            
283
            $this->connection->commit();
284
        } catch (\Exception $e) {
285
            $this->connection->rollBack();
286
        }
287
    }
288
289
    /**
290
     *
291
     */
292
    public function drop()
293
    {
294
        $this->connection->exec('delete from profiles');
295
        $this->connection->exec('delete from profiles_meta');
296
        $this->connection->exec('delete from profiles_info');
297
    }
298
299
    public function getWatchedFunctions()
300
    {
301
        $stmt = $this->connection->query('select * from watched order by name desc');
302
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
303
    }
304
305
    public function addWatchedFunction($name)
306
    {
307
        $name = trim($name);
308
        if (empty($name)) {
309
            return false;
310
        }
311
        $stmt = $this->connection->prepare('INSERT INTO watched (name) VALUES (:name)');
312
        $stmt->execute(['name'=>trim($name)]);
313
        return true;
314
    }
315
316
    public function updateWatchedFunction($id, $name)
317
    {
318
        $stmt = $this->connection->prepare('update watched set name=:name where id = :id');
319
        $stmt->execute(['id'=>$id, 'name'=>$name]);
320
    }
321
322
    public function removeWatchedFunction($id)
323
    {
324
        $stmt = $this->connection->prepare('delete from watched where id = :id');
325
        $stmt->execute(['id'=>$id]);
326
    }
327
328
    /**
329
     * @param \Xhgui_Storage_Filter $options
0 ignored issues
show
Bug introduced by
There is no parameter named $options. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
330
     * @return \DateTime
331
     */
332
    protected function getDateTimeFromString($date) {
333
334
        try {
335
            $datetime = \DateTime::createFromFormat('Y-m-d H:i:s', $date);
336
            if ($datetime instanceof \DateTime) {
337
                return $datetime;
338
            }
339
        } catch (\Exception $e){
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
340
        }
341
342
        try {
343
            $datetime = \DateTime::createFromFormat('U', $date);
344
            if ($datetime instanceof \DateTime) {
345
                return $datetime;
346
            }
347
        } catch (\Exception $e){
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
348
        }
349
350
        throw new \InvalidArgumentException('Unable to parse date');
351
    }
352
}
353