ActiveHighstockWidget::processMysqlTimestamp()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 47 and the first side effect is on line 11.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
/**
4
 * ActiveHighstockWidget class file.
5
 *
6
 * @author David Baker <[email protected]>
7
 * @link https://github.com/miloschuman/yii-highcharts/
8
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
9
 */
10
11
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'HighstockWidget.php');
12
13
/**
14
 * Usage:
15
 *
16
$this->widget('highcharts.ActiveHighstockWidget', array(
17
    'options' => array(
18
        'title' => array('text' => 'Site Percentile'),
19
        'yAxis' => array(
20
            'title' => array('text' => 'Site Rank')
21
        ),
22
        'series' => array(
23
            array(
24
                'name'  => 'Site percentile',
25
                'data'  => 'SiteRank12',        // data column in the dataprovider
26
                'time'  => 'RankDate',          // time column in the dataprovider
27
                // 'timeType'  => 'date',
28
                // defaults to a mysql timestamp, other options are 'date' (run through strtotime()) or 'plain'
29
            ),
30
            array(
31
                'name'  => 'Site percentile',
32
                'time'  => 'RankDate',          // time column in the dataprovider
33
                'type'  => 'arearange',
34
                'removeNulls' => true,
35
                'data'  => array(
36
                    'Column1',      // specify an array of data options
37
                    'Column2',      // if you are using an area range charts
38
                ),
39
            ),
40
        ),
41
    ),
42
    'dataProvider' => $dataProvider,
43
));
44
 *
45
 * @see HighchartsWidget for additional options
46
 */
47
class ActiveHighstockWidget extends HighstockWidget
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...
48
{
49
    /**
50
     * Pass in a data provider that we will turn into the series
51
     *
52
     * @var CDataProvider
53
     */
54
    public $dataProvider;
55
56
    public function run()
57
    {
58
        $data = $this->dataProvider->getData();
59
        $series = $this->options['series'];
60
61
        if (count($data) > 0) {
62
            foreach ($series as $i => $batch) {
63
                if (isset($batch['time']) && isset($batch['data']) &&
64
                    !is_array($batch['time'])
65
                ) {
66
                    $dateSeries = array();
67
                    foreach ($data as $row) {
68
69
                        if($this->shouldRemoveNullValues($series[$i], $row)) {
70
                            continue;
71
                        }
72
73
                        $dateSeries[] = $this->processRow($row, $batch);
74
                    }
75
76
                    // we'll work on the actual item, this may be PHP 5.3+ specific
77
                    $this->sortDateSeries($dateSeries);
78
79
                    // clean up our time item so we don't accidentally conflict with Highstock
80
                    unset($this->options['series'][$i]['time']);
81
82
                    // and then reset our data column with our data series
83
                    $this->options['series'][$i]['data'] = $dateSeries;
84
                }
85
            }
86
        }
87
88
        parent::run();
89
    }
90
91
    /**
92
     * Checks whether we want to remove null values from a series
93
     *
94
     * @param $series
95
     * @param $row
96
     *
97
     * @return bool
98
     */
99
    private function shouldRemoveNullValues($series, $row)
100
    {
101
        if(isset($series['removeNulls']) && $series['removeNulls'] == true) {
102
            if($row[$series['data']] == null) {
103
                return true;
104
            }
105
        }
106
107
        return false;
108
    }
109
110
    /**
111
     * Handles processing a row and readying it for Highstock
112
     *
113
     * @param $row
114
     * @param $batch
115
     * @throws Exception
116
     * @return array
117
     */
118
    protected function processRow($row, $batch)
119
    {
120
        // if we're dealing with a javascript timestamp
121
        // then just setup our array
122
        $timeType = (isset($batch['timeType'])) ? $batch['timeType'] : 'mysql';
123
124
        switch ($timeType) {
125
            case 'plain':
126
                $time = $this->processPlainTimestamp($row, $batch);
127
                break;
128
            case 'date':
129
                $time = $this->processDateString($row, $batch);
130
                break;
131
            case 'mysql':
132
                $time = $this->processMysqlTimestamp($row, $batch);
133
                break;
134
            default:
135
                $functionName = 'process' . ucfirst($timeType);
136
                if (method_exists($this, $functionName)) {
137
                    return call_user_func(array($this, $functionName), $row, $batch);
138
                } else {
139
                    throw new Exception("Can't call your custom date processing function");
140
                }
141
        }
142
143
        // process our data by running it through our data processing method
144
        $data = $this->processData($row, $batch);
145
146
        // push our data value on the front of what may be multiple data values
147
        array_unshift($data, $time);
148
149
        return $data;
150
    }
151
152
    /**
153
     * Cleans up the data column so Highstock is happy
154
     *
155
     * @param $row
156
     * @param $batch
157
     * @return array
158
     */
159
    protected function processData($row, $batch)
160
    {
161
        if(!is_array($batch['data'])) {
162
            return array($this->processDataValue($row[$batch['data']]));
163
        }
164
165
        $items = array();
166
        foreach($batch['data'] as $item) {
167
            $items[] = $this->processDataValue($row[$item]);
168
        }
169
        return $items;
170
    }
171
172
    /**
173
     * Using this means your time needs to be in JS milliseconds
174
     *
175
     * @param $row
176
     * @param $batch
177
     * @return array
178
     */
179
    protected function processPlainTimestamp($row, $batch)
180
    {
181
        return floatval($row[$batch['time']]);
182
    }
183
184
    /**
185
     * Converts dates using strtotime() to a MySQL timestamp and then changes to JS milliseconds
186
     *
187
     * @param $row
188
     * @param $batch
189
     * @return array
190
     */
191
    protected function processDateString($row, $batch)
192
    {
193
        return 1000 * floatval(strtotime($row[$batch['time']]));
194
    }
195
196
    /**
197
     * Converts a SQL unix timestamp to a JS timestamp (in milliseconds)
198
     * This is our default time processor if not specified
199
     *
200
     * @param $row
201
     * @param $batch
202
     * @return array
203
     */
204
    protected function processMysqlTimestamp($row, $batch)
205
    {
206
        return 1000 * floatval($row[$batch['time']]);
207
    }
208
209
    /**
210
     * Sorts our date series so we have all the dates from first to last
211
     *
212
     * @param $series
213
     */
214
    protected function sortDateSeries(&$series)
215
    {
216
        $dates = array();
217
218
        //sort by first column (dates ascending order)
219
        foreach ($series as $key => $row) {
220
            $dates[$key] = $row[0];
221
        }
222
        array_multisort($dates, SORT_ASC, $series);
223
    }
224
225
    /**
226
     * Highstocks won't graph a value if we have a null for it.
227
     * We want to make sure we don't cast nulls to 0 using floatval,
228
     * so we check here to make sure the value should be converted to
229
     * a float before we do anything.
230
     *
231
     * @param $value
232
     * @return float|null
233
     */
234
    protected function processDataValue($value)
235
    {
236
        return ($value === null) ? null : floatval($value);
237
    }
238
}
239