annotate views_calc_table.inc @ 0:0651c02e6ed7

views_calc 1.3
author Franck Deroche <franck@defr.org>
date Wed, 05 Aug 2009 18:20:29 +0200
parents
children cedf71edacf5 b0a976e17cc7
rev   line source
franck@0 1 <?php
franck@0 2 // $Id: views_calc_table.inc,v 1.15 2009/04/22 02:21:41 karens Exp $
franck@0 3 /**
franck@0 4 * @file
franck@0 5 * Copied from the table style plugin.
franck@0 6 */
franck@0 7
franck@0 8 /**
franck@0 9 * Style plugin to render each item as a row in a table.
franck@0 10 *
franck@0 11 * @ingroup views_style_plugins
franck@0 12 */
franck@0 13 class views_calc_table extends views_plugin_style_table {
franck@0 14
franck@0 15 function option_definition() {
franck@0 16 $options = parent::option_definition();
franck@0 17
franck@0 18 $options['detailed_values'] = array('default' => 0);
franck@0 19 return $options;
franck@0 20 }
franck@0 21
franck@0 22 /**
franck@0 23 * Render the given style.
franck@0 24 */
franck@0 25 function options_form(&$form, &$form_state) {
franck@0 26 parent::options_form($form, $form_state);
franck@0 27 $form['#theme'] = 'views_calc_ui_table';
franck@0 28
franck@0 29 $form['detailed_values'] = array(
franck@0 30 '#title' => t('Show details'),
franck@0 31 '#type' => 'select',
franck@0 32 '#options' => array(0 => t('Yes'), 1 => t('No')),
franck@0 33 '#default_value' => $this->options['detailed_values'],
franck@0 34 '#description' => t("Select 'Yes' to show detailed values followed by column calculations, 'No' to surpress details and show only calculated column totals."),
franck@0 35 );
franck@0 36
franck@0 37 $handlers = $this->display->handler->get_handlers('field');
franck@0 38 $columns = $this->sanitize_columns($this->options['columns']);
franck@0 39
franck@0 40 foreach ($columns as $field => $column) {
franck@0 41 $safe = str_replace(array('][', '_', ' '), '-', $field);
franck@0 42 $id = 'edit-style-options-columns-' . $safe;
franck@0 43 $form['info'][$field]['justification'] = array(
franck@0 44 '#type' => 'select',
franck@0 45 '#default_value' => isset($this->options['info'][$field]['justification']) ? $this->options['info'][$field]['justification'] : 'views_calc_justify_none',
franck@0 46 '#options' => array(
franck@0 47 'views_calc_justify_none' => t('None'),
franck@0 48 'views_calc_justify_left' => t('Left'),
franck@0 49 'views_calc_justify_right' => t('Right'),
franck@0 50 'views_calc_justify_center' => t('Center'),
franck@0 51 ),
franck@0 52 '#process' => array('views_process_dependency'),
franck@0 53 '#dependency' => array($id => array($field)),
franck@0 54 );
franck@0 55 $form['info'][$field]['has_calc'] = array(
franck@0 56 '#type' => 'checkbox',
franck@0 57 '#title' => t('Display calculation'),
franck@0 58 '#default_value' => isset($this->options['info'][$field]['has_calc']) ? $this->options['info'][$field]['has_calc'] : 0,
franck@0 59 '#process' => array('views_process_dependency'),
franck@0 60 '#dependency' => array($id => array($field)),
franck@0 61 );
franck@0 62
franck@0 63 $options = _views_calc_calc_options();
franck@0 64 $form['info'][$field]['calc'] = array(
franck@0 65 '#type' => 'select',
franck@0 66 '#options' => $options,
franck@0 67 '#default_value' => isset($this->options['info'][$field]['calc']) ? $this->options['info'][$field]['calc'] : array(),
franck@0 68 '#process' => array('views_process_dependency'),
franck@0 69 '#dependency' => array('edit-style-options-info-'. $safe .'-has-calc' => array(TRUE)),
franck@0 70 '#multiple' => TRUE,
franck@0 71 );
franck@0 72 }
franck@0 73 }
franck@0 74
franck@0 75 /**
franck@0 76 * TODO
franck@0 77 * figure out what changes are needed so Views field groups will work.
franck@0 78 */
franck@0 79 function pre_render($results) {
franck@0 80 parent::pre_render($results);
franck@0 81
franck@0 82 // If there are no calc fields, do nothing.
franck@0 83 if (!$calc_fields = $this->get_calc_fields()) {
franck@0 84 return;
franck@0 85 }
franck@0 86 // If we're not getting a summary row, do nothing.
franck@0 87 if (!empty($this->view->views_calc_calculation)) {
franck@0 88 return;
franck@0 89 }
franck@0 90
franck@0 91 $this->view->totals = array();
franck@0 92 $this->view->sub_totals = array();
franck@0 93
franck@0 94 // Subtotals and pager totals require a list of the specific
franck@0 95 // values to include.
franck@0 96 $paged = FALSE;
franck@0 97 if (!empty($this->view->pager)
franck@0 98 && !empty($this->view->pager['use_pager'])
franck@0 99 && !empty($this->view->pager['items_per_page'])) {
franck@0 100 $nids = array();
franck@0 101 foreach ($this->view->result as $delta => $value) {
franck@0 102 $nids[] = $value->nid;
franck@0 103 }
franck@0 104 // Add sub_total rows to the results.
franck@0 105 foreach ($calc_fields as $calc => $field) {
franck@0 106 if ($summary_view = views_get_view($this->view->name)) {
franck@0 107 $summary_view->set_display($this->view->current_display);
franck@0 108 $summary_view->set_arguments($this->view->args);
franck@0 109 $summary_view->views_calc_calculation = $calc;
franck@0 110 $summary_view->views_calc_nids = $nids;
franck@0 111 $summary_view->views_calc_sub_total = TRUE;
franck@0 112 $summary_view->is_cacheable = FALSE;
franck@0 113 $summary_view->execute();
franck@0 114 $this->view->sub_totals[] = array_shift($summary_view->result);
franck@0 115 }
franck@0 116 }
franck@0 117 }
franck@0 118
franck@0 119 // Add grand totals to the results.
franck@0 120 foreach ($calc_fields as $calc => $field) {
franck@0 121 if ($summary_view = views_get_view($this->view->name)) {
franck@0 122 $summary_view->set_display($this->view->current_display);
franck@0 123 $summary_view->set_arguments($this->view->args);
franck@0 124 $summary_view->pager['items_per_page'] = 0;
franck@0 125 $summary_view->views_calc_calculation = $calc;
franck@0 126 $summary_view->views_calc_nids = array();
franck@0 127 $summary_view->views_calc_sub_total = FALSE;
franck@0 128 $summary_view->is_cacheable = FALSE;
franck@0 129 $summary_view->execute();
franck@0 130 $this->view->totals[] = array_shift($summary_view->result);
franck@0 131 }
franck@0 132 }
franck@0 133 }
franck@0 134
franck@0 135 function query() {
franck@0 136 parent::query();
franck@0 137
franck@0 138 // If we're not getting a summary row, do nothing.
franck@0 139 if (empty($this->view->views_calc_calculation)) {
franck@0 140 return;
franck@0 141 }
franck@0 142 // If there are no calc fields, do nothing.
franck@0 143 if (!$calc_fields = $this->get_calc_fields()) {
franck@0 144 return;
franck@0 145 }
franck@0 146
franck@0 147 if (!empty($this->view->views_calc_sub_total)) {
franck@0 148 $this->query_sub_total();
franck@0 149 }
franck@0 150 else {
franck@0 151 $this->query_total();
franck@0 152 }
franck@0 153 }
franck@0 154
franck@0 155 /**
franck@0 156 *
franck@0 157 */
franck@0 158 function query_sub_total() {
franck@0 159 // Create summary rows.
franck@0 160 $calc_fields = $this->get_calc_fields();
franck@0 161 $calc = $this->view->views_calc_calculation;
franck@0 162 $fields = $calc_fields[$calc];
franck@0 163
franck@0 164 // Empty out any fields that have been added to the query,
franck@0 165 // we don't need them for the summary totals.
franck@0 166 $this->view->query->fields = array();
franck@0 167 foreach ($this->view->field as $field) {
franck@0 168 $query_field = substr($field->field, 0, 3) == 'cid' ? $field->definition['calc'] : $field->table .'.'. $field->field;
franck@0 169 $query_alias = $field->field_alias;
franck@0 170 if (in_array($field->field, $fields)) {
franck@0 171 // Calculated fields.
franck@0 172 $this->view->query->add_field(NULL, "$calc($query_field)", $query_alias);
franck@0 173 $this->view->query->add_table($field->table, NULL, NULL, $field->table);
franck@0 174 }
franck@0 175 else {
franck@0 176 // Empty fields that have no calculations.
franck@0 177 $this->view->query->add_field(NULL, "MAX('')", $query_alias);
franck@0 178 }
franck@0 179 // Add a dummy field for the groupby.
franck@0 180 $this->view->query->add_field(NULL, "MAX('". $calc ."')", "TOTAL_". $calc);
franck@0 181 }
franck@0 182 // TODO This won't work right with relationships, need a fix here.
franck@0 183 if (!empty($this->view->views_calc_nids)) {
franck@0 184 $this->view->query->add_where(NULL, "node.nid IN (%s)", implode(',', $this->view->views_calc_nids));
franck@0 185 }
franck@0 186 }
franck@0 187
franck@0 188 /**
franck@0 189 * The grand total can be computed using GROUPBY without regard
franck@0 190 * to pager values.
franck@0 191 */
franck@0 192 function query_total() {
franck@0 193 // Create summary rows.
franck@0 194 $calc_fields = $this->get_calc_fields();
franck@0 195 $calc = $this->view->views_calc_calculation;
franck@0 196 $fields = $calc_fields[$calc];
franck@0 197
franck@0 198 // Empty out any fields that have been added to the query,
franck@0 199 // we don't need them for the summary totals.
franck@0 200 $this->view->query->fields = array();
franck@0 201 // Clear out any sorting and grouping, it can create unexpected results
franck@0 202 // when Views adds aggregation values for the sorts.
franck@0 203 $this->view->query->orderby = array();
franck@0 204 $this->view->query->groupby = array();
franck@0 205
franck@0 206 foreach ($this->view->field as $field) {
franck@0 207 $query_field = substr($field->field, 0, 3) == 'cid' ? $field->definition['calc'] : $field->table .'.'. $field->field;
franck@0 208 $query_alias = $field->field_alias;
franck@0 209 $this->view->query->add_table($field->table, NULL, NULL, $field->table);
franck@0 210 if (!empty($fields) && in_array($field->field, $fields)) {
franck@0 211 // Calculated fields.
franck@0 212 $this->view->query->add_field(NULL, "$calc($query_field)", $query_alias);
franck@0 213 }
franck@0 214 else {
franck@0 215 // Empty fields that have no calculations.
franck@0 216 $this->view->query->add_field(NULL, "MAX('')", $query_alias);
franck@0 217 }
franck@0 218 // Add a dummy field for the groupby.
franck@0 219 $this->view->query->add_field(NULL, "MAX('". $calc ."')", "TOTAL_". $calc);
franck@0 220 }
franck@0 221 }
franck@0 222
franck@0 223 function get_calc_fields() {
franck@0 224 $options = $this->view->style_plugin->options;
franck@0 225 $handler = $this->view->style_plugin;
franck@0 226 $fields = $this->view->field;
franck@0 227 $columns = $handler->sanitize_columns($options['columns'], $fields);
franck@0 228 $calcs = array_keys(_views_calc_calc_options());
franck@0 229
franck@0 230 $calc_fields = array();
franck@0 231 foreach ($columns as $field => $column) {
franck@0 232 if ($field == $column && empty($fields[$field]->options['exclude'])) {
franck@0 233 if ($options['info'][$field]['has_calc']) {
franck@0 234 foreach ($calcs as $calc) {
franck@0 235 if (isset($this->options['info'][$field]['calc'][$calc])) {
franck@0 236 $calc_fields[$calc][] = $field;
franck@0 237 }
franck@0 238 }
franck@0 239 }
franck@0 240 }
franck@0 241 }
franck@0 242 return $calc_fields;
franck@0 243 }
franck@0 244 }