annotate views_calc_plugin_style_chart.inc @ 1:cedf71edacf5

Views Calc: Total du group dans le cas d'un group by
author Franck Deroche <franck@defr.org>
date Thu, 06 Aug 2009 19:09:42 +0200
parents 0651c02e6ed7
children
rev   line source
franck@0 1 <?php
franck@0 2 // $Id: views_calc_plugin_style_chart.inc,v 1.7 2009/04/20 19:38:42 karens Exp $
franck@0 3
franck@0 4 /**
franck@0 5 * @file
franck@0 6 * Contains the chart style plugin.
franck@0 7 */
franck@0 8
franck@0 9 /**
franck@0 10 * Style plugin to render view as a chart.
franck@0 11 *
franck@0 12 * @ingroup views_style_plugins
franck@0 13 */
franck@0 14 class views_calc_plugin_style_chart extends views_plugin_style {
franck@0 15 // Set default options.
franck@0 16 function options(&$options) {
franck@0 17 $options['format'] = 'pie2D';
franck@0 18 $options['height'] = 200;
franck@0 19 $options['width'] = 400;
franck@0 20 $options['color'] = 'ffffff';
franck@0 21 $options['aggregation_field'] = '';
franck@0 22 $options['calc_fields'] = array();
franck@0 23 $options['calc'] = 'COUNT';
franck@0 24 $options['precision'] = 2;
franck@0 25 }
franck@0 26
franck@0 27 // Generate a form for setting options.
franck@0 28 function options_form(&$form, &$form_state) {
franck@0 29 parent::options_form($form, $form_state);
franck@0 30
franck@0 31 $form['format'] = array(
franck@0 32 '#type' => 'select',
franck@0 33 '#title' => t('Chart format'),
franck@0 34 '#options' => array(
franck@0 35 'line2D' => t('Line 2D'),
franck@0 36 'hbar2D' => t('Horizontal Bar 2D'),
franck@0 37 'vbar2D' => t('Vertical Bar 2D'),
franck@0 38 'pie2D' => t('Pie 2D'),
franck@0 39 'pie3D' => t('Pie 3D'),
franck@0 40 'venn' => t('Venn'),
franck@0 41 'scatter' => t('Scatter Plot')
franck@0 42 ),
franck@0 43 '#default_value' => $this->options['format'],
franck@0 44 );
franck@0 45 $form['height'] = array(
franck@0 46 '#type' => 'textfield',
franck@0 47 '#title' => t('Chart height'),
franck@0 48 '#default_value' => $this->options['height'],
franck@0 49 '#required' => TRUE, // Google charts breaks if it is empty.
franck@0 50 '#description' => t('An integer value, the number of pixels of height for this chart.'),
franck@0 51 );
franck@0 52 $form['width'] = array(
franck@0 53 '#type' => 'textfield',
franck@0 54 '#title' => t('Chart width'),
franck@0 55 '#default_value' => $this->options['width'],
franck@0 56 '#required' => TRUE, // Google charts breaks if it is empty.
franck@0 57 '#description' => t('An integer value, the number of pixels of width for this chart.'),
franck@0 58 );
franck@0 59 $form['color'] = array(
franck@0 60 '#type' => 'textfield',
franck@0 61 '#title' => t('Background color'),
franck@0 62 '#default_value' => $this->options['color'],
franck@0 63 '#description' => t('In hexadecimal format (RRGGBB). Do not use the # symbol.'),
franck@0 64 '#required' => TRUE, // Google charts breaks if it is empty.
franck@0 65 );
franck@0 66 $form['show_legend'] = array(
franck@0 67 '#type' => 'checkbox',
franck@0 68 '#title' => t('Show legend'),
franck@0 69 '#default_value' => $this->options['show_legend'],
franck@0 70 '#description' => t('Display legend next to the chart.'),
franck@0 71 );
franck@0 72
franck@0 73 $form['aggregation_field'] = array(
franck@0 74 '#type' => 'select',
franck@0 75 '#title' => t('Aggregation field'),
franck@0 76 '#options' => $this->aggregated_field_options(),
franck@0 77 '#default_value' => $this->options['aggregation_field'],
franck@0 78 '#description' => t('Select a field to aggreagate the results on.')
franck@0 79 );
franck@0 80 // TODO Charts module cannot currently handle more than one series,
franck@0 81 // update Multiple to TRUE if that changes.
franck@0 82 $form['calc_fields'] = array(
franck@0 83 '#type' => 'select',
franck@0 84 '#title' => t('Computation field'),
franck@0 85 '#options' => $this->aggregated_field_options(),
franck@0 86 '#default_value' => $this->calc_fields(),
franck@0 87 '#multiple' => FALSE,
franck@0 88 '#description' => t('Select field to perform computations on.')
franck@0 89 );
franck@0 90 $form['calc'] = array(
franck@0 91 '#type' => 'select',
franck@0 92 '#title' => t('Computation to perform'),
franck@0 93 '#options' => $this->calc_options(),
franck@0 94 '#default_value' => $this->options['calc'],
franck@0 95 );
franck@0 96 $form['precision'] = array(
franck@0 97 '#type' => 'select',
franck@0 98 '#title' => t('Precision'),
franck@0 99 '#options' => range(0, 4),
franck@0 100 '#default_value' => $this->options['precision'],
franck@0 101 '#description' => t('Decimal points to use in computed values.'),
franck@0 102 );
franck@0 103 }
franck@0 104
franck@0 105 function calc_options() {
franck@0 106 return array(
franck@0 107 '' => t('None'),
franck@0 108 'SUM' => t('Sum'),
franck@0 109 'COUNT' => t('Count'),
franck@0 110 'AVG' => t('Average'),
franck@0 111 'MIN' => t('Minimum'),
franck@0 112 'MAX' => t('Maximum'),
franck@0 113 );
franck@0 114 }
franck@0 115
franck@0 116 /**
franck@0 117 * Create an options array of available fields from this view.
franck@0 118 */
franck@0 119 function aggregated_field_options() {
franck@0 120 $field_names = array();
franck@0 121 $handlers = $this->display->handler->get_handlers('field');
franck@0 122 foreach ($handlers as $field => $handler) {
franck@0 123 if ($label = $handler->label()) {
franck@0 124 $field_names[$field] = $label;
franck@0 125 }
franck@0 126 else {
franck@0 127 $field_names[$field] = $handler->ui_name();
franck@0 128 }
franck@0 129 }
franck@0 130 return $field_names;
franck@0 131 }
franck@0 132
franck@0 133 /**
franck@0 134 * Make sure calc_fields is always an array, even when not multiple.
franck@0 135 */
franck@0 136 function calc_fields() {
franck@0 137 $calc_fields = (array) $this->options['calc_fields'];
franck@0 138 return array_values($calc_fields);
franck@0 139 }
franck@0 140
franck@0 141 // Define and display a chart from the grouped values.
franck@0 142 function render() {
franck@0 143 // Scan all Views data and insert them into a series.
franck@0 144 $data = array();
franck@0 145
franck@0 146 // Get values from rows.
franck@0 147 foreach ($this->calc_fields() as $calc) {
franck@0 148 foreach ($this->view->result as $row) {
franck@0 149 foreach ($this->view->field as $key => $field) {
franck@0 150 if ($key == $this->options['aggregation_field']) {
franck@0 151 $legend_field = array_key_exists($calc, $this->view->field) ? $this->view->field[$calc] : NULL;
franck@0 152 $legend = !empty($legend_field->options['label']) ? $legend_field->options['label'] : NULL;
franck@0 153 if ($this->options['show_legend']) {
franck@0 154 $data[$calc]['#legend'] = $legend;
franck@0 155 }
franck@0 156 $value['#label'] = strip_tags(theme_views_view_field($this->view, $this->view->field[$key], $row)); // .': '. $row->$calc;
franck@0 157 $value['#value'] = $row->$calc;
franck@0 158 $data[$calc][] = $value;
franck@0 159 }
franck@0 160 }
franck@0 161 }
franck@0 162 }
franck@0 163
franck@0 164 // Get chart settings from options form.
franck@0 165 $legend_field = $this->view->field[$this->options['aggregation_field']];
franck@0 166 $chart = array(
franck@0 167 '#type' => $this->options['format'],
franck@0 168 '#height' => $this->options['height'],
franck@0 169 '#width' => $this->options['width'],
franck@0 170 '#color' => $this->options['color'],
franck@0 171 );
franck@0 172
franck@0 173 // Use the view title as the chart title.
franck@0 174 $chart['#title'] = $this->view->get_title();
franck@0 175
franck@0 176 // Insert series into the chart array.
franck@0 177 foreach ($data as $series) {
franck@0 178 $chart[] = $series;
franck@0 179 }
franck@0 180
franck@0 181 // Print the chart.
franck@0 182 return charts_chart($chart);
franck@0 183 }
franck@0 184
franck@0 185 function query() {
franck@0 186 parent::query();
franck@0 187
franck@0 188 // Clear the fields out, we'll replace them with calculated values.
franck@0 189 $this->view->query->clear_fields();
franck@0 190 // Clear out any sorting, it can create unexpected results
franck@0 191 // when Views adds aggregation values for the sorts.
franck@0 192 $this->view->query->orderby = array();
franck@0 193
franck@0 194 // Add the grouping information to the query.
franck@0 195 // Field setting of array('aggregate' => TRUE) tells Views not to force
franck@0 196 // another aggregation in for this field.
franck@0 197
franck@0 198 foreach ($this->view->field as $field) {
franck@0 199 $query_field = substr($field->field, 0, 3) == 'cid' ? $field->definition['calc'] : $field->table .'.'. $field->field;
franck@0 200 $query_alias = $field->field_alias;
franck@0 201
franck@0 202 // Add the aggregation.
franck@0 203 if ($field->field == $this->options['aggregation_field']) {
franck@0 204 $this->view->query->add_orderby(NULL, NULL, 'asc', $query_alias);
franck@0 205 $this->view->query->add_groupby($query_field);
franck@0 206 if (substr($field->field, 0, 3) == 'cid') {
franck@0 207 $this->view->query->add_field(NULL, $query_field, $field->field, array('aggregate' => TRUE));
franck@0 208 }
franck@0 209 else {
franck@0 210 $this->view->query->add_field($field->table, $field->field, NULL, array('aggregate' => TRUE));
franck@0 211 }
franck@0 212 }
franck@0 213 // Add computed values.
franck@0 214 if (in_array($field->field, $this->calc_fields())) {
franck@0 215 $sql = "ROUND(". $this->options['calc'] ."($query_field), ". $this->options['precision'] .")";
franck@0 216 $this->view->query->add_field(NULL, $sql, $field->field, array('aggregate' => TRUE));
franck@0 217
franck@0 218 // TODO This part is not relationship-safe, needs additional work
franck@0 219 // to join in the right table if the computation is done
franck@0 220 // on a field that comes from a relationship.
franck@0 221
franck@0 222 // Make sure the table with the right alias name is available
franck@0 223 // (it might have been dropped during Views optimizations.)
franck@0 224 $this->view->query->add_table($field->table);
franck@0 225 }
franck@0 226 }
franck@0 227 }
franck@0 228 }