Completed
Push — master ( 8e1e89...bfefcf )
by Mark
10s
created

Xhgui_Profiles::delete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
/**
3
 * Contains logic for getting/creating/removing profile records.
4
 */
5
class Xhgui_Profiles
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
6
{
7
    protected $_collection;
8
9
    protected $_mapper;
10
11
    public function __construct(MongoDb $db)
12
    {
13
        $this->_collection = $db->results;
0 ignored issues
show
Bug introduced by
The property results does not seem to exist in MongoDB.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
14
        $this->_mapper = new Xhgui_Db_Mapper();
15
    }
16
17
    /**
18
     * Get the latest profile data.
19
     *
20
     * @return Xhgui_Profile
21
     */
22
    public function latest()
23
    {
24
        $cursor = $this->_collection->find()
25
            ->sort(array('meta.request_date' => -1))
26
            ->limit(1);
27
        $result = $cursor->getNext();
28
        return $this->_wrap($result);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->_wrap($result); of type Xhgui_Profile|array adds the type array to the return on line 28 which is incompatible with the return type documented by Xhgui_Profiles::latest of type Xhgui_Profile.
Loading history...
29
    }
30
31
    public function query($conditions, $fields = null)
32
    {
33
        return $this->_collection->find($conditions, $fields);
34
    }
35
36
    /**
37
     * Get a single profile run by id.
38
     *
39
     * @param string $id The id of the profile to get.
40
     * @return Xhgui_Profile
41
     */
42
    public function get($id)
43
    {
44
        return $this->_wrap($this->_collection->findOne(array(
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->_wrap($this->_col...> new \MongoId($id)))); of type Xhgui_Profile|array adds the type array to the return on line 44 which is incompatible with the return type documented by Xhgui_Profiles::get of type Xhgui_Profile.
Loading history...
45
            '_id' => new MongoId($id)
46
        )));
47
    }
48
49
    /**
50
     * Get the list of profiles for a simplified url.
51
     *
52
     * @param string $url The url to load profiles for.
53
     * @param array $options Pagination options to use.
54
     * @param array $conditions The search options.
55
     * @return MongoCursor
56
     */
57
    public function getForUrl($url, $options, $conditions = array())
58
    {
59
        $conditions = array_merge(
60
            (array)$conditions,
61
            array('simple_url' => $url)
62
        );
63
        $options = array_merge($options, array(
64
            'conditions' => $conditions,
65
        ));
66
        return $this->paginate($options);
67
    }
68
69
    public function paginate($options)
70
    {
71
        $opts = $this->_mapper->convert($options);
72
73
        $totalRows = $this->_collection->find(
74
            $opts['conditions'],
75
            array('_id' => 1))->count();
76
77
        $totalPages = max(ceil($totalRows / $opts['perPage']), 1);
78
        $page = 1;
79
        if (isset($options['page'])) {
80
            $page = min(max($options['page'], 1), $totalPages);
81
        }
82
83
        $projection = false;
84
        if (isset($options['projection'])) {
85
            if ($options['projection'] === true) {
86
                $projection = array('meta' => 1, 'profile.main()' => 1);
87
            } else {
88
                $projection = $options['projection'];
89
            }
90
        }
91
92
        if ($projection === false) {
93
            $cursor = $this->_collection->find($opts['conditions'])
94
                ->sort($opts['sort'])
95
                ->skip((int)($page - 1) * $opts['perPage'])
96
                ->limit($opts['perPage']);
97
        } else {
98
            $cursor = $this->_collection->find($opts['conditions'], $projection)
99
                ->sort($opts['sort'])
100
                ->skip((int)($page - 1) * $opts['perPage'])
101
                ->limit($opts['perPage']);
102
        }
103
104
        return array(
105
            'results' => $this->_wrap($cursor),
106
            'sort' => $opts['sort'],
107
            'direction' => $opts['direction'],
108
            'page' => $page,
109
            'perPage' => $opts['perPage'],
110
            'totalPages' => $totalPages
111
        );
112
    }
113
114
    /**
115
     * Get the Percentile metrics for a URL
116
     *
117
     * This will group data by date and returns only the
118
     * percentile + date, making the data ideal for time series graphs
119
     *
120
     * @param integer $percentile The percentile you want. e.g. 90.
121
     * @param string $url
122
     * @param array $search Search options containing date_start and or date_end
123
     * @return array Array of metrics grouped by date
124
     */
125
    public function getPercentileForUrl($percentile, $url, $search = array())
126
    {
127
        $result = $this->_mapper->convert(array(
128
            'conditions' => $search + array('simple_url' => $url)
129
        ));
130
        $match = $result['conditions'];
131
132
        $col = '$meta.request_date';
133 View Code Duplication
        if (!empty($search['limit']) && $search['limit'][0] == "P") {
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...
134
            $col = '$meta.request_ts';
135
        }
136
137
        $results = $this->_collection->aggregate(array(
138
            array('$match' => $match),
139
            array(
140
                '$project' => array(
141
                    'date' => $col,
142
                    'profile.main()' => 1
143
                )
144
            ),
145
            array(
146
                '$group' => array(
147
                    '_id' => '$date',
148
                    'row_count' => array('$sum' => 1),
149
                    'wall_times' => array('$push' => '$profile.main().wt'),
150
                    'cpu_times' => array('$push' => '$profile.main().cpu'),
151
                    'mu_times' => array('$push' => '$profile.main().mu'),
152
                    'pmu_times' => array('$push' => '$profile.main().pmu'),
153
                )
154
            ),
155
            array(
156
                '$project' => array(
157
                    'date' => '$date',
158
                    'row_count' => '$row_count',
159
                    'raw_index' => array(
160
                        '$multiply' => array(
161
                            '$row_count',
162
                            $percentile / 100
163
                        )
164
                    ),
165
                    'wall_times' => '$wall_times',
166
                    'cpu_times' => '$cpu_times',
167
                    'mu_times' => '$mu_times',
168
                    'pmu_times' => '$pmu_times',
169
                )
170
            ),
171
            array('$sort' => array('_id' => 1)),
172
            ),
173
            array('cursor' => array('batchSize' => 0))
174
        );
175
176
        if (empty($results['result'])) {
177
            return array();
178
        }
179
        $keys = array(
180
            'wall_times' => 'wt',
181
            'cpu_times' => 'cpu',
182
            'mu_times' => 'mu',
183
            'pmu_times' => 'pmu'
184
        );
185
        foreach ($results['result'] as &$result) {
186
            $result['date'] = ($result['_id'] instanceof MongoDate) ? date('Y-m-d H:i:s', $result['_id']->sec) : $result['_id'];
187
            unset($result['_id']);
188
            $index = max(round($result['raw_index']) - 1, 0);
189
            foreach ($keys as $key => $out) {
190
                sort($result[$key]);
191
                $result[$out] = isset($result[$key][$index]) ? $result[$key][$index] : null;
192
                unset($result[$key]);
193
            }
194
        }
195
        return $results['result'];
196
    }
197
198
    /**
199
     * Get the Average metrics for a URL
200
     *
201
     * This will group data by date and returns only the
202
     * avg + date, making the data ideal for time series graphs
203
     *
204
     * @param string $url
205
     * @param array $search Search options containing date_start and or date_end
206
     * @return array Array of metrics grouped by date
207
     */
208
    public function getAvgsForUrl($url, $search = array())
209
    {
210
        $match = array('meta.simple_url' => $url);
211
        if (isset($search['date_start'])) {
212
            $match['meta.request_date']['$gte'] = (string)$search['date_start'];
213
        }
214
        if (isset($search['date_end'])) {
215
            $match['meta.request_date']['$lte'] = (string)$search['date_end'];
216
        }
217
        $results = $this->_collection->aggregate(array(
218
            array('$match' => $match),
219
            array(
220
                '$project' => array(
221
                    'date' => '$meta.request_date',
222
                    'profile.main()' => 1,
223
                )
224
            ),
225
            array(
226
                '$group' => array(
227
                    '_id' => '$date',
228
                    'avg_wt' => array('$avg' => '$profile.main().wt'),
229
                    'avg_cpu' => array('$avg' => '$profile.main().cpu'),
230
                    'avg_mu' => array('$avg' => '$profile.main().mu'),
231
                    'avg_pmu' => array('$avg' => '$profile.main().pmu'),
232
                )
233
            ),
234
            array('$sort' => array('_id' => 1))
235
        ));
236
        if (empty($results['result'])) {
237
            return array();
238
        }
239
        foreach ($results['result'] as $i => $result) {
240
            $results['result'][$i]['date'] = $result['_id'];
241
            unset($results['result'][$i]['_id']);
242
        }
243
        return $results['result'];
244
    }
245
246
    /**
247
     * Get a paginated set of results.
248
     *
249
     * @param array $options The find options to use.
250
     * @return array An array of result data.
251
     */
252
    public function getAll($options = array())
253
    {
254
        return $this->paginate($options);
255
    }
256
257
    /**
258
     * Insert a profile run.
259
     *
260
     * Does unchecked inserts.
261
     *
262
     * @param array $profile The profile data to save.
263
     */
264
    public function insert($profile)
265
    {
266
        return $this->_collection->insert($profile, array('w' => 0));
267
    }
268
269
    /**
270
     * Delete a profile run.
271
     *
272
     * @param $id The profile id to delete.
273
     * @return array|bool
274
     */
275
    public function delete($id)
276
    {
277
        return $this->_collection->remove(array('_id' => new MongoId($id)), array());
278
    }
279
280
    /**
281
     * Used to truncate a collection.
282
     *
283
     * Primarly used in test cases to reset the test db.
284
     *
285
     * @return boolean
286
     */
287
    public function truncate()
288
    {
289
        return $this->_collection->drop();
290
    }
291
292
    /**
293
     * Converts arrays + MongoCursors into Xhgui_Profile instances.
294
     *
295
     * @param array|MongoCursor $data The data to transform.
296
     * @return Xhgui_Profile|array The transformed/wrapped results.
297
     */
298
    protected function _wrap($data)
299
    {
300
        if ($data === null) {
301
            throw new Exception('No profile data found.');
302
        }
303
304
        if (is_array($data)) {
305
            return new Xhgui_Profile($data);
306
        }
307
        $results = array();
308
        foreach ($data as $row) {
309
            $results[] = new Xhgui_Profile($row);
310
        }
311
        return $results;
312
    }
313
}
314