~jstys-z/helioviewer.org/client5

« back to all changes in this revision

Viewing changes to src/php/Database/Statistics.php

  • Committer: V. Keith Hughitt
  • Date: 2009-04-01 21:08:05 UTC
  • Revision ID: hughitt1@kore-20090401210805-372f7dgih07vxk42
nightly build 04-01-2009

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<?php
2
 
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
 
/**
4
 
 * Statistics Class definition
5
 
 *
6
 
 * PHP version 5
7
 
 *
8
 
 * @category Database
9
 
 * @package  Helioviewer
10
 
 * @author   Jeff Stys <jeff.stys@nasa.gov>
11
 
 * @author   Keith Hughitt <keith.hughitt@nasa.gov>
12
 
 * @license  http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
13
 
 * @link     http://launchpad.net/helioviewer.org
14
 
 */
15
 
/**
16
 
 * A simple module for recording query statistics
17
 
 *
18
 
 * @category Database
19
 
 * @package  Helioviewer
20
 
 * @author   Jeff Stys <jeff.stys@nasa.gov>
21
 
 * @author   Keith Hughitt <keith.hughitt@nasa.gov>
22
 
 * @license  http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
23
 
 * @link     http://launchpad.net/helioviewer.org
24
 
 */
25
 
class Database_Statistics {
26
 
 
27
 
    private $_dbConnection;
28
 
 
29
 
    /**
30
 
     * Constructor
31
 
     *
32
 
     * @return void
33
 
     */
34
 
    public function __construct() {
35
 
        include_once HV_ROOT_DIR.'/src/php/Database/DbConnection.php';
36
 
        $this->_dbConnection = new Database_DbConnection();
37
 
    }
38
 
 
39
 
    /**
40
 
     * Add a new entry to the `statistics` table
41
 
     *
42
 
     * param $action string The API action to log
43
 
     *
44
 
     * @return boolean
45
 
     */
46
 
    public function log($action) {
47
 
        $sql = sprintf(
48
 
                  "INSERT INTO statistics "
49
 
                . "SET "
50
 
                .     "id "        . " = NULL, "
51
 
                .     "timestamp " . " = NULL, "
52
 
                .     "action "    . " = '%s';",
53
 
                $this->_dbConnection->link->real_escape_string($action)
54
 
               );
55
 
        try {
56
 
            $result = $this->_dbConnection->query($sql);
57
 
        }
58
 
        catch (Exception $e) {
59
 
            return false;
60
 
        }
61
 
 
62
 
        return true;
63
 
    }
64
 
 
65
 
    /**
66
 
     * Get latest usage statistics as JSON
67
 
     *
68
 
     * @param  string  Time resolution
69
 
     *
70
 
     * @return str  JSON
71
 
     */
72
 
    public function getUsageStatistics($resolution) {
73
 
        require_once HV_ROOT_DIR.'/src/php/Helper/DateTimeConversions.php';
74
 
 
75
 
        // Determine time intervals to query
76
 
        $interval = $this->_getQueryIntervals($resolution);
77
 
 
78
 
        // Array to keep track of counts for each action
79
 
        $counts = array(
80
 
            "buildMovie"           => array(),
81
 
            "getClosestData"       => array(),
82
 
            "getClosestImage"      => array(),
83
 
            "getJPX"               => array(),
84
 
            "takeScreenshot"       => array(),
85
 
            "uploadMovieToYouTube" => array(),
86
 
            "embed"                => array()
87
 
        );
88
 
 
89
 
        // Summary array
90
 
        $summary = array(
91
 
            "buildMovie"           => 0,
92
 
            "getClosestData"       => 0,
93
 
            "getClosestImage"      => 0,
94
 
            "getJPX"               => 0,
95
 
            "takeScreenshot"       => 0,
96
 
            "uploadMovieToYouTube" => 0,
97
 
            "embed"                => 0
98
 
        );
99
 
 
100
 
        // Format to use for displaying dates
101
 
        $dateFormat = $this->_getDateFormat($resolution);
102
 
 
103
 
        // Start date
104
 
        $date = $interval['startDate'];
105
 
 
106
 
        // Query each time interval
107
 
        for ($i = 0; $i < $interval["numSteps"]; $i++) {
108
 
 
109
 
            // Format date for array index
110
 
            $dateIndex = $date->format($dateFormat);
111
 
 
112
 
            // MySQL-formatted date string
113
 
            $dateStart = toMySQLDateString($date);
114
 
 
115
 
            // Move to end date for the current interval
116
 
            $date->add($interval['timestep']);
117
 
 
118
 
            // Fill with zeros to begin with
119
 
            foreach ($counts as $action => $arr) {
120
 
                array_push($counts[$action], array($dateIndex => 0));
121
 
            }
122
 
            $dateEnd = toMySQLDateString($date);
123
 
 
124
 
            $sql = sprintf(
125
 
                      "SELECT action, COUNT(id) AS count "
126
 
                    . "FROM statistics "
127
 
                    . "WHERE "
128
 
                    .     "timestamp BETWEEN '%s' AND '%s' "
129
 
                    . "GROUP BY action;",
130
 
                    $this->_dbConnection->link->real_escape_string($dateStart),
131
 
                    $this->_dbConnection->link->real_escape_string($dateEnd)
132
 
                   );
133
 
            try {
134
 
                $result = $this->_dbConnection->query($sql);
135
 
            }
136
 
            catch (Exception $e) {
137
 
                return false;
138
 
            }
139
 
 
140
 
            // Append counts for each API action during that interval
141
 
            // to the appropriate array
142
 
            while ($count = $result->fetch_array(MYSQLI_ASSOC)) {
143
 
                $num = (int)$count['count'];
144
 
 
145
 
                $counts[$count['action']][$i][$dateIndex] = $num;
146
 
                $summary[$count['action']] += $num;
147
 
            }
148
 
        }
149
 
 
150
 
        // Include summary info
151
 
        $counts['summary'] = $summary;
152
 
 
153
 
        return json_encode($counts);
154
 
    }
155
 
 
156
 
    /**
157
 
     * Return date format string for the specified time resolution
158
 
     *
159
 
     * @param  string  $resolution  Time resolution string
160
 
     *
161
 
     * @return string  Date format string
162
 
     */
163
 
    public function getDataCoverageTimeline($resolution, $endDate, $interval,
164
 
        $stepSize, $steps) {
165
 
 
166
 
        require_once HV_ROOT_DIR.'/src/php/Helper/DateTimeConversions.php';
167
 
 
168
 
        $sql = 'SELECT id, name, description FROM datasources ORDER BY description';
169
 
        $result = $this->_dbConnection->query($sql);
170
 
 
171
 
        $output = array();
172
 
 
173
 
        while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
174
 
            $sourceId = $row['id'];
175
 
 
176
 
            $output['sourceId'.$sourceId] = new stdClass;
177
 
            $output['sourceId'.$sourceId]->sourceId = $sourceId;
178
 
            $output['sourceId'.$sourceId]->label = $row['description'];
179
 
            $output['sourceId'.$sourceId]->data = array();
180
 
        }
181
 
 
182
 
        // Format to use for displaying dates
183
 
        switch($resolution) {
184
 
        case "5m":
185
 
        case "15m":
186
 
        case "30m":
187
 
            $dateFormat = "Y-m-d H:i";
188
 
            break;
189
 
        case "1h":
190
 
            $dateFormat = "Y-m-d H:i";
191
 
            break;
192
 
        case "1D":
193
 
            $dateFormat = "Y-m-d";
194
 
            break;
195
 
        case "14D":
196
 
        case "1W":
197
 
            $dateFormat = "Y-m-d";
198
 
            break;
199
 
        case "30D":
200
 
        case "1M":
201
 
        case "3M":
202
 
        case "6M":
203
 
            $dateFormat = "M Y";
204
 
            break;
205
 
        case "1Y":
206
 
            $dateFormat = "Y";
207
 
            break;
208
 
        default:
209
 
            $dateFormat = "Y-m-d H:i e";
210
 
        }
211
 
 
212
 
 
213
 
        // Start date
214
 
        $date = $endDate->sub($interval);
215
 
 
216
 
        // Query each time interval
217
 
        for ($i = 0; $i < $steps; $i++) {
218
 
            $dateIndex = $date->format($dateFormat); // Format date for array index
219
 
            $dateStart = toMySQLDateString($date);   // MySQL-formatted date string
220
 
 
221
 
            // Move to end date for the current interval
222
 
            $date->add($stepSize);
223
 
 
224
 
            // Fill with zeros to begin with
225
 
            foreach ($output as $sourceId => $arr) {
226
 
                array_push($output[$sourceId]->data, array($dateIndex => 0));
227
 
            }
228
 
            $dateEnd = toMySQLDateString($date);
229
 
 
230
 
            $sql = "SELECT sourceId, SUM(count) as count FROM data_coverage_30_min " .
231
 
                   "WHERE date BETWEEN '$dateStart' AND '$dateEnd' GROUP BY sourceId;";
232
 
            //echo "\n<br />";
233
 
 
234
 
            $result = $this->_dbConnection->query($sql);
235
 
 
236
 
            // And append counts for each sourceId during that interval to the relevant array
237
 
            while ($count = $result->fetch_array(MYSQLI_ASSOC)) {
238
 
                $num = (int) $count['count'];
239
 
                $output['sourceId'.$count['sourceId']]->data[$i][$dateIndex] = $num;
240
 
            }
241
 
        }
242
 
 
243
 
        return json_encode($output);
244
 
    }
245
 
 
246
 
    /**
247
 
     * Gets latest datasource coverage and return as JSON
248
 
     */
249
 
    public function getDataCoverage($resolution, $endDate, $interval,
250
 
        $stepSize, $steps) {
251
 
 
252
 
        require_once HV_ROOT_DIR.'/src/php/Helper/DateTimeConversions.php';
253
 
 
254
 
        $sql = 'SELECT id, name, description FROM datasources ORDER BY description';
255
 
        $result = $this->_dbConnection->query($sql);
256
 
 
257
 
        $output = array();
258
 
 
259
 
        while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
260
 
            $sourceId = $row['id'];
261
 
 
262
 
            $output['sourceId'.$sourceId] = new stdClass;
263
 
            $output['sourceId'.$sourceId]->sourceId = $sourceId;
264
 
            $output['sourceId'.$sourceId]->label = $row['description'];
265
 
            $output['sourceId'.$sourceId]->data = array();
266
 
        }
267
 
 
268
 
        // Format to use for displaying dates
269
 
        switch($resolution) {
270
 
        case "5m":
271
 
        case "15m":
272
 
        case "30m":
273
 
            $dateFormat = "Y-m-d H:i";
274
 
            break;
275
 
        case "1h":
276
 
            $dateFormat = "Y-m-d H:i";
277
 
            break;
278
 
        case "1D":
279
 
            $dateFormat = "Y-m-d";
280
 
            break;
281
 
        case "14D":
282
 
        case "1W":
283
 
            $dateFormat = "Y-m-d";
284
 
            break;
285
 
        case "30D":
286
 
        case "1M":
287
 
        case "3M":
288
 
        case "6M":
289
 
            $dateFormat = "M Y";
290
 
            break;
291
 
        case "1Y":
292
 
            $dateFormat = "Y";
293
 
            break;
294
 
        default:
295
 
            $dateFormat = "Y-m-d H:i e";
296
 
        }
297
 
 
298
 
 
299
 
        // Start date
300
 
        $date = $endDate->sub($interval);
301
 
 
302
 
        // Query each time interval
303
 
        for ($i = 0; $i < $steps; $i++) {
304
 
            $dateIndex = $date->format($dateFormat); // Format date for array index
305
 
            $dateStart = toMySQLDateString($date);   // MySQL-formatted date string
306
 
 
307
 
            // Move to end date for the current interval
308
 
            $date->add($stepSize);
309
 
 
310
 
            // Fill with zeros to begin with
311
 
            foreach ($output as $sourceId => $arr) {
312
 
                array_push($output[$sourceId]->data, array($dateIndex => 0));
313
 
            }
314
 
            $dateEnd = toMySQLDateString($date);
315
 
 
316
 
            $sql = "SELECT sourceId, SUM(count) as count FROM data_coverage_30_min " .
317
 
                   "WHERE date BETWEEN '$dateStart' AND '$dateEnd' GROUP BY sourceId;";
318
 
            //echo "\n<br />";
319
 
 
320
 
            $result = $this->_dbConnection->query($sql);
321
 
 
322
 
            // And append counts for each sourceId during that interval to the relevant array
323
 
            while ($count = $result->fetch_array(MYSQLI_ASSOC)) {
324
 
                $num = (int) $count['count'];
325
 
                $output['sourceId'.$count['sourceId']]->data[$i][$dateIndex] = $num;
326
 
            }
327
 
        }
328
 
 
329
 
        return json_encode($output);
330
 
    }
331
 
 
332
 
    /**
333
 
     * Update data source coverage data for the last 7 Days
334
 
     * (or specified time period).
335
 
     */
336
 
    public function updateDataCoverage($period=null) {
337
 
 
338
 
        if ( gettype($period) == 'string' &&
339
 
             preg_match('/^([0-9]+)([mhDMY])$/', $period, $matches) === 1 ) {
340
 
 
341
 
            $magnitude   = $matches[1];
342
 
            $period_abbr = $matches[2];
343
 
        }
344
 
        else {
345
 
            $magnitude   =  7;
346
 
            $period_abbr = 'D';
347
 
        }
348
 
 
349
 
        switch ($period_abbr) {
350
 
        case 'm':
351
 
            $interval = 'INTERVAL '.$magnitude.' MINUTE';
352
 
            break;
353
 
        case 'h':
354
 
            $interval = 'INTERVAL '.$magnitude.' HOUR';
355
 
            break;
356
 
        case 'D':
357
 
            $interval = 'INTERVAL '.$magnitude.' DAY';
358
 
            break;
359
 
        case 'M':
360
 
            $interval = 'INTERVAL '.$magnitude.' MONTH';
361
 
            break;
362
 
        case 'Y':
363
 
            $interval = 'INTERVAL '.$magnitude.' YEAR';
364
 
            break;
365
 
        default:
366
 
            $interval = 'INTERVAL 7 DAY';
367
 
        }
368
 
 
369
 
        $sql = 'REPLACE INTO ' .
370
 
                    'data_coverage_30_min ' .
371
 
                '(date, sourceId, count) ' .
372
 
                'SELECT ' .
373
 
                    'SQL_BIG_RESULT SQL_BUFFER_RESULT SQL_NO_CACHE ' .
374
 
                    'CONCAT( ' .
375
 
                        'DATE_FORMAT(date, "%Y-%m-%d %H:"), '    .
376
 
                        'LPAD((MINUTE(date) DIV 30)*30, 2, "0"), ' .
377
 
                        '":00") AS "bin", ' .
378
 
                    'sourceId, ' .
379
 
                    'COUNT(id) ' .
380
 
                'FROM ' .
381
 
                    'data ' .
382
 
                'WHERE ' .
383
 
                    'date >= DATE_SUB(NOW(),'.$interval.') ' .
384
 
                'GROUP BY ' .
385
 
                    'bin, ' .
386
 
                    'sourceId;';
387
 
        $result = $this->_dbConnection->query($sql);
388
 
 
389
 
 
390
 
        $output = array(
391
 
            'result'     => $result,
392
 
            'interval'     => $interval
393
 
        );
394
 
 
395
 
        return json_encode($output);
396
 
    }
397
 
 
398
 
    /**
399
 
     * Determines date format to use for the x-axis of the requested resolution
400
 
     */
401
 
    private function _getDateFormat($resolution) {
402
 
        switch ($resolution) {
403
 
            case "hourly":
404
 
                return "ga";  // 4pm
405
 
                break;
406
 
            case "daily":
407
 
                return "D";   // Tues
408
 
                break;
409
 
            case "weekly":
410
 
                return "M j"; // Feb 3
411
 
                break;
412
 
            case "monthly":
413
 
                return "M y"; // Feb 09
414
 
                break;
415
 
            case "yearly":
416
 
                return "Y";   // 2009
417
 
                break;
418
 
        }
419
 
    }
420
 
 
421
 
    /**
422
 
     * Determine time inveral specification for statistics query
423
 
     *
424
 
     * @param  string  $resolution  Time resolution string
425
 
     *
426
 
     * @return array   Array specifying a time interval
427
 
     */
428
 
    private function _getQueryIntervals($resolution) {
429
 
 
430
 
        date_default_timezone_set('UTC');
431
 
 
432
 
        // Variables
433
 
        $date     = new DateTime();
434
 
        $timestep = null;
435
 
        $numSteps = null;
436
 
 
437
 
        // For hourly resolution, keep the hours value, otherwise set to zero
438
 
        $hour = ($resolution == "hourly") ? (int) $date->format("H") : 0;
439
 
 
440
 
        // Round end time to nearest hour or day to begin with (may round other units later)
441
 
        $date->setTime($hour, 0, 0);
442
 
 
443
 
        // Hourly
444
 
        if ($resolution == "hourly") {
445
 
            $timestep = new DateInterval("PT1H");
446
 
            $numSteps = 24;
447
 
 
448
 
            $date->add($timestep);
449
 
 
450
 
            // Subtract 24 hours
451
 
            $date->sub(new DateInterval("P1D"));
452
 
        }
453
 
 
454
 
        // Daily
455
 
        else if ($resolution == "daily") {
456
 
            $timestep = new DateInterval("P1D");
457
 
            $numSteps = 28;
458
 
 
459
 
            $date->add($timestep);
460
 
 
461
 
            // Subtract 4 weeks
462
 
            $date->sub(new DateInterval("P4W"));
463
 
        }
464
 
 
465
 
        // Weekly
466
 
        else if ($resolution == "weekly") {
467
 
            $timestep = new DateInterval("P1W");
468
 
            $numSteps = 26;
469
 
 
470
 
            $date->add(new DateInterval("P1D"));
471
 
 
472
 
            // Subtract 25 weeks
473
 
            $date->sub(new DateInterval("P25W"));
474
 
        }
475
 
 
476
 
        // Monthly
477
 
        else if ($resolution == "monthly") {
478
 
            $timestep = new DateInterval("P1M");
479
 
            $numSteps = 24;
480
 
 
481
 
            $date->modify('first day of next month');
482
 
            $date->sub(new DateInterval("P24M"));
483
 
        }
484
 
 
485
 
        // Yearly
486
 
        else if ($resolution == "yearly") {
487
 
            $timestep = new DateInterval("P1Y");
488
 
            $numSteps = 8;
489
 
 
490
 
            $year = (int) $date->format("Y");
491
 
            $date->setDate($year - $numSteps + 1, 1, 1);
492
 
        }
493
 
 
494
 
        // Array to store time intervals
495
 
        $intervals = array(
496
 
            "startDate" => $date,
497
 
            "timestep"  => $timestep,
498
 
            "numSteps"  => $numSteps
499
 
        );
500
 
 
501
 
        return $intervals;
502
 
    }
503
 
}
504
 
?>