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@1
|
106 $this->view->sub_totals[] = $this->do_calculation($calc, TRUE, $nids); |
franck@0
|
107 } |
franck@0
|
108 } |
franck@0
|
109 |
franck@0
|
110 // Add grand totals to the results. |
franck@0
|
111 foreach ($calc_fields as $calc => $field) { |
franck@1
|
112 $this->view->totals[] = $this->do_calculation($calc, FALSE); |
franck@0
|
113 } |
franck@0
|
114 } |
franck@0
|
115 |
franck@1
|
116 function do_calculation($calc, $sub_total, $nids = array()) { |
franck@1
|
117 if ($summary_view = views_get_view($this->view->name)) { |
franck@1
|
118 $summary_view->set_display($this->view->current_display); |
franck@1
|
119 $summary_view->set_arguments($this->view->args); |
franck@1
|
120 $summary_view->pager['items_per_page'] = 0; |
franck@1
|
121 $summary_view->views_calc_calculation = $calc; |
franck@1
|
122 $summary_view->views_calc_nids = $nids; |
franck@1
|
123 $summary_view->views_calc_sub_total = $sub_total; |
franck@1
|
124 $summary_view->is_cacheable = FALSE; |
franck@1
|
125 $summary_view->execute(); |
franck@1
|
126 return array_shift($summary_view->result); |
franck@1
|
127 } |
franck@1
|
128 return ''; |
franck@1
|
129 } |
franck@1
|
130 |
franck@0
|
131 function query() { |
franck@0
|
132 parent::query(); |
franck@0
|
133 |
franck@0
|
134 // If we're not getting a summary row, do nothing. |
franck@0
|
135 if (empty($this->view->views_calc_calculation)) { |
franck@0
|
136 return; |
franck@0
|
137 } |
franck@0
|
138 // If there are no calc fields, do nothing. |
franck@0
|
139 if (!$calc_fields = $this->get_calc_fields()) { |
franck@0
|
140 return; |
franck@0
|
141 } |
franck@0
|
142 |
franck@0
|
143 if (!empty($this->view->views_calc_sub_total)) { |
franck@0
|
144 $this->query_sub_total(); |
franck@0
|
145 } |
franck@0
|
146 else { |
franck@0
|
147 $this->query_total(); |
franck@0
|
148 } |
franck@0
|
149 } |
franck@0
|
150 |
franck@0
|
151 /** |
franck@0
|
152 * |
franck@0
|
153 */ |
franck@0
|
154 function query_sub_total() { |
franck@0
|
155 // Create summary rows. |
franck@0
|
156 $calc_fields = $this->get_calc_fields(); |
franck@0
|
157 $calc = $this->view->views_calc_calculation; |
franck@0
|
158 $fields = $calc_fields[$calc]; |
franck@0
|
159 |
franck@0
|
160 // Empty out any fields that have been added to the query, |
franck@0
|
161 // we don't need them for the summary totals. |
franck@0
|
162 $this->view->query->fields = array(); |
franck@1
|
163 // Clear out any sorting and grouping, it can create unexpected results |
franck@1
|
164 // when Views adds aggregation values for the sorts. |
franck@1
|
165 $this->view->query->orderby = array(); |
franck@1
|
166 $this->view->query->groupby = array(); |
franck@1
|
167 |
franck@0
|
168 foreach ($this->view->field as $field) { |
franck@0
|
169 $query_field = substr($field->field, 0, 3) == 'cid' ? $field->definition['calc'] : $field->table .'.'. $field->field; |
franck@0
|
170 $query_alias = $field->field_alias; |
franck@0
|
171 if (in_array($field->field, $fields)) { |
franck@0
|
172 // Calculated fields. |
franck@0
|
173 $this->view->query->add_field(NULL, "$calc($query_field)", $query_alias); |
franck@0
|
174 $this->view->query->add_table($field->table, NULL, NULL, $field->table); |
franck@0
|
175 } |
franck@0
|
176 else { |
franck@0
|
177 // Empty fields that have no calculations. |
franck@0
|
178 $this->view->query->add_field(NULL, "MAX('')", $query_alias); |
franck@0
|
179 } |
franck@0
|
180 // Add a dummy field for the groupby. |
franck@0
|
181 $this->view->query->add_field(NULL, "MAX('". $calc ."')", "TOTAL_". $calc); |
franck@0
|
182 } |
franck@0
|
183 // TODO This won't work right with relationships, need a fix here. |
franck@0
|
184 if (!empty($this->view->views_calc_nids)) { |
franck@0
|
185 $this->view->query->add_where(NULL, "node.nid IN (%s)", implode(',', $this->view->views_calc_nids)); |
franck@0
|
186 } |
franck@0
|
187 } |
franck@0
|
188 |
franck@0
|
189 /** |
franck@0
|
190 * The grand total can be computed using GROUPBY without regard |
franck@0
|
191 * to pager values. |
franck@0
|
192 */ |
franck@0
|
193 function query_total() { |
franck@0
|
194 // Create summary rows. |
franck@0
|
195 $calc_fields = $this->get_calc_fields(); |
franck@0
|
196 $calc = $this->view->views_calc_calculation; |
franck@0
|
197 $fields = $calc_fields[$calc]; |
franck@0
|
198 |
franck@0
|
199 // Empty out any fields that have been added to the query, |
franck@0
|
200 // we don't need them for the summary totals. |
franck@0
|
201 $this->view->query->fields = array(); |
franck@0
|
202 // Clear out any sorting and grouping, it can create unexpected results |
franck@0
|
203 // when Views adds aggregation values for the sorts. |
franck@0
|
204 $this->view->query->orderby = array(); |
franck@0
|
205 $this->view->query->groupby = array(); |
franck@0
|
206 |
franck@0
|
207 foreach ($this->view->field as $field) { |
franck@0
|
208 $query_field = substr($field->field, 0, 3) == 'cid' ? $field->definition['calc'] : $field->table .'.'. $field->field; |
franck@0
|
209 $query_alias = $field->field_alias; |
franck@0
|
210 $this->view->query->add_table($field->table, NULL, NULL, $field->table); |
franck@0
|
211 if (!empty($fields) && in_array($field->field, $fields)) { |
franck@0
|
212 // Calculated fields. |
franck@0
|
213 $this->view->query->add_field(NULL, "$calc($query_field)", $query_alias); |
franck@0
|
214 } |
franck@0
|
215 else { |
franck@0
|
216 // Empty fields that have no calculations. |
franck@0
|
217 $this->view->query->add_field(NULL, "MAX('')", $query_alias); |
franck@0
|
218 } |
franck@0
|
219 // Add a dummy field for the groupby. |
franck@0
|
220 $this->view->query->add_field(NULL, "MAX('". $calc ."')", "TOTAL_". $calc); |
franck@0
|
221 } |
franck@0
|
222 } |
franck@0
|
223 |
franck@0
|
224 function get_calc_fields() { |
franck@0
|
225 $options = $this->view->style_plugin->options; |
franck@0
|
226 $handler = $this->view->style_plugin; |
franck@0
|
227 $fields = $this->view->field; |
franck@0
|
228 $columns = $handler->sanitize_columns($options['columns'], $fields); |
franck@0
|
229 $calcs = array_keys(_views_calc_calc_options()); |
franck@0
|
230 |
franck@0
|
231 $calc_fields = array(); |
franck@0
|
232 foreach ($columns as $field => $column) { |
franck@0
|
233 if ($field == $column && empty($fields[$field]->options['exclude'])) { |
franck@0
|
234 if ($options['info'][$field]['has_calc']) { |
franck@0
|
235 foreach ($calcs as $calc) { |
franck@0
|
236 if (isset($this->options['info'][$field]['calc'][$calc])) { |
franck@0
|
237 $calc_fields[$calc][] = $field; |
franck@0
|
238 } |
franck@0
|
239 } |
franck@0
|
240 } |
franck@0
|
241 } |
franck@0
|
242 } |
franck@0
|
243 return $calc_fields; |
franck@0
|
244 } |
franck@1
|
245 |
franck@1
|
246 function render_grouping($records, $grouping_field = '') { |
franck@1
|
247 $sets = parent::render_grouping($records, $grouping_field); |
franck@1
|
248 // If we have more than one set, we'll try recalculate results |
franck@1
|
249 // baded on the nodes in the group. |
franck@1
|
250 $calc_fields = $this->get_calc_fields(); |
franck@1
|
251 if (count($sets) > 1 && $calc_fields) { |
franck@1
|
252 $this->group_totals = array(); |
franck@1
|
253 foreach($sets as $value => $set) { |
franck@1
|
254 $nids = array(); |
franck@1
|
255 foreach($set as $k => $v) { |
franck@1
|
256 $nids[] = $v->nid; |
franck@1
|
257 } |
franck@1
|
258 foreach($calc_fields as $calc => $field) { |
franck@1
|
259 $this->view->group_totals[$value][] = $this->do_calculation($calc, TRUE, $nids); |
franck@1
|
260 } |
franck@1
|
261 } |
franck@1
|
262 } |
franck@1
|
263 return $sets; |
franck@1
|
264 } |
franck@1
|
265 } |