comparison views_calc.module @ 3:5635080385bd tip

Merge patch with 1.x-dev
author Franck Deroche <franck@defr.org>
date Fri, 07 Aug 2009 15:20:12 +0200
parents b0a976e17cc7
children
comparison
equal deleted inserted replaced
1:cedf71edacf5 3:5635080385bd
1 <?php 1 <?php
2
3 /** 2 /**
4 * @file 3 * @file
5 * This module will allow you to add calculated fields to views tables 4 * This module will allow you to add calculated fields to views tables
6 * and compute (SUM, COUNT, AVG, etc) columns of numeric data in a views table. 5 * and compute (SUM, COUNT, AVG, etc) columns of numeric data in a views table.
7 */ 6 */
112 'access arguments' => array('create views calc'), 111 'access arguments' => array('create views calc'),
113 ); 112 );
114 $items['admin/settings/views_calc/settings'] = array( 113 $items['admin/settings/views_calc/settings'] = array(
115 'title' => t('Settings'), 114 'title' => t('Settings'),
116 'type' => MENU_LOCAL_TASK, 115 'type' => MENU_LOCAL_TASK,
117 'weight' => 10, 116 'weight' => 6,
118 'priority' => 1, 117 'priority' => 1,
119 'page callback' => 'drupal_get_form', 118 'page callback' => 'drupal_get_form',
120 'page arguments' => array('views_calc_settings_form'), 119 'page arguments' => array('views_calc_settings_form'),
121 'access arguments' => array('administer views calc'), 120 'access arguments' => array('administer views calc'),
122 ); 121 );
122 $items['admin/settings/views_calc/export'] = array(
123 'title' => 'Export fields',
124 'page callback' => 'drupal_get_form',
125 'page arguments' => array('views_calc_export_form'),
126 'access arguments' => array('create views calc'),
127 'type' => MENU_LOCAL_TASK,
128 'weight' => 7,
129 );
130 $items['admin/settings/views_calc/import'] = array(
131 'title' => 'Import fields',
132 'page callback' => 'drupal_get_form',
133 'page arguments' => array('views_calc_import_form'),
134 'access arguments' => array('create views calc'),
135 'type' => MENU_LOCAL_TASK,
136 'weight' => 8,
137 );
138
123 return $items; 139 return $items;
124 } 140 }
125 141
126 /** 142 /**
127 * Implementation of hook_settings() 143 * Implementation of hook_settings()
150 /** 166 /**
151 * Views Calc Fields tab on views list. 167 * Views Calc Fields tab on views list.
152 */ 168 */
153 function views_calc_fields_form() { 169 function views_calc_fields_form() {
154 $i = 0; 170 $i = 0;
155 $substitutions = _views_calc_substitutions(); 171 $substitutions = array();
156 $reverse = array_flip($substitutions); 172 $help = t('<p>The specific fields that are available in any view depend on the base table used for that view.</p>');
173 require_once(drupal_get_path('module', 'views') .'/includes/admin.inc');
174 $base_tables = views_fetch_base_tables();
175 foreach ($base_tables as $base => $data) {
176 $base_subs = _views_calc_substitutions($base);
177 $substitutions += $base_subs;
178 $fieldset = array(
179 '#title' => t('Base table: !name', array('!name' => t($data['title']))),
180 '#value' => theme('item_list', $base_subs),
181 '#collapsible' => TRUE,
182 '#collapsed' => TRUE,
183 );
184 $help .= theme('fieldset', $fieldset);
185 }
157 186
158 // display current views calcs fields 187 // display current views calcs fields
159 $fields = _views_calc_fields(); 188 $fields = _views_calc_fields();
160 while ($field = db_fetch_array($fields)) { 189 while ($field = db_fetch_array($fields)) {
161 $form[] = views_calc_field_form_item($i, $field, $substitutions); 190 $form[] = views_calc_field_form_item($i, $field, $substitutions);
165 for ($x = $i + 1; $x < $i + 2; $x++) { 194 for ($x = $i + 1; $x < $i + 2; $x++) {
166 $field = array(); 195 $field = array();
167 $form[] = views_calc_field_form_item($i, $field, $substitutions); 196 $form[] = views_calc_field_form_item($i, $field, $substitutions);
168 } 197 }
169 $form['#prefix'] = '<div class="views-calc-field-settings">'; 198 $form['#prefix'] = '<div class="views-calc-field-settings">';
170 $form['#suffix'] = '</div><div class="views-calc-field-names"><strong>Field Substitutions</strong><div class="form-item">'. theme('item_list', _views_calc_substitutions()) .'</div></div>'; 199 $form['#suffix'] = '</div><div class="views-calc-field-names"><strong>Field Substitutions</strong><div class="form-item">'. $help .'</div></div>';
171 $form['submit'] = array( 200 $form['submit'] = array(
172 '#type' => 'submit', 201 '#type' => 'submit',
173 '#value' => t('Save'), 202 '#value' => t('Save'),
174 ); 203 );
175 return $form; 204 return $form;
179 * A form element for an individual calculated field. 208 * A form element for an individual calculated field.
180 */ 209 */
181 function views_calc_field_form_item($i, $field, $substitutions) { 210 function views_calc_field_form_item($i, $field, $substitutions) {
182 if (empty($field)) { 211 if (empty($field)) {
183 $field = array('cid' => 0, 'label' => '', 'tablelist' => '', 'calc' => '', 'format' => '', 'custom' => ''); 212 $field = array('cid' => 0, 'label' => '', 'tablelist' => '', 'calc' => '', 'format' => '', 'custom' => '');
213 }
214 require_once(drupal_get_path('module', 'views') .'/includes/admin.inc');
215 $options = array();
216 $base_tables = views_fetch_base_tables();
217 foreach ($base_tables as $base => $data) {
218 $options[$base] = t($data['title']);
184 } 219 }
185 $form['group'][$i] = array( 220 $form['group'][$i] = array(
186 '#type' => 'fieldset', 221 '#type' => 'fieldset',
187 '#tree' => TRUE, 222 '#tree' => TRUE,
188 '#title' => t('Field: ') . !empty($field['label']) ? $field['label'] : t('New'), 223 '#title' => t('Field: ') . !empty($field['label']) ? $field['label'] : t('New'),
195 ); 230 );
196 $form['group'][$i]['tablelist'] = array( 231 $form['group'][$i]['tablelist'] = array(
197 '#type' => 'hidden', 232 '#type' => 'hidden',
198 '#value' => $field['tablelist'], 233 '#value' => $field['tablelist'],
199 ); 234 );
235 $form['group'][$i]['base'] = array(
236 '#type' => 'select',
237 '#title' => t('Base table'),
238 '#options' => $options,
239 '#default_value' => !empty($field['base']) && array_key_exists($field['base'], $options) ? $field['base'] : 'node',
240 '#description' => t('The base table for this field.'),
241 );
200 $form['group'][$i]['label'] = array( 242 $form['group'][$i]['label'] = array(
201 '#type' => 'textfield', 243 '#type' => 'textfield',
202 '#title' => t('Label'), 244 '#title' => t('Label'),
203 '#field_prefix' => 'ViewsCalc: ', 245 '#field_prefix' => 'ViewsCalc: ',
204 '#default_value' => str_replace('ViewsCalc: ', '', $field['label']), 246 '#default_value' => str_replace('ViewsCalc: ', '', $field['label']),
206 ); 248 );
207 $form['group'][$i]['calc'] = array( 249 $form['group'][$i]['calc'] = array(
208 '#type' => 'textarea', 250 '#type' => 'textarea',
209 '#title' => t('Calculation'), 251 '#title' => t('Calculation'),
210 '#default_value' => strtr($field['calc'], $substitutions), 252 '#default_value' => strtr($field['calc'], $substitutions),
211 '#description' => t('<p>The query operation to be performed, using numbers, field substitutions, and '. implode(' ', _views_calc_operators()) .'.</p>'), 253 '#description' => t("<p>The query operation to be performed, using numbers, field substitutions, and ". implode(' ', _views_calc_operators()) .". Leave spaces between parentheses and field names, i.e. 'CONCAT( %field1, ' ', %field2 )'. <strong>". t('Note that all fields must be from the base table selected above! You cannot combine fields from different base tables.') ."</strong></p>"),
212 ); 254 );
213 $form['group'][$i]['format'] = array( 255 $form['group'][$i]['format'] = array(
214 '#type' => 'select', 256 '#type' => 'select',
215 '#title' => t('Format'), 257 '#title' => t('Format'),
216 '#default_value' => $field['format'], 258 '#default_value' => $field['format'],
233 $form_values = $form_state['values']; 275 $form_values = $form_state['values'];
234 $edit = $form_values; 276 $edit = $form_values;
235 foreach ($edit as $delta => $item) { 277 foreach ($edit as $delta => $item) {
236 if ($item['calc'] == '' || !is_numeric($delta)) { 278 if ($item['calc'] == '' || !is_numeric($delta)) {
237 // remove blank fields, don't save them 279 // remove blank fields, don't save them
238 unset($form_values[$delta]); 280 continue;
239 } else { 281 }
282 else {
240 // Remove all valid values from calc, if anything is left over, it is invalid. 283 // Remove all valid values from calc, if anything is left over, it is invalid.
241 284
242 // First, remove all field names. 285 // First, remove all field names.
243 $repl = array(); 286 $repl = array();
244 $patterns = array(); 287 $patterns = array();
245 foreach (_views_calc_substitutions() as $key => $value) { 288 $base = $item['base'];
289 foreach (_views_calc_substitutions($base) as $key => $value) {
246 $key = trim($value); 290 $key = trim($value);
247 $count = strlen($value); 291 $count = strlen($value);
248 $replace = preg_quote($value); 292 $replace = preg_quote($value);
249 $patterns[] = "`(^|[^\\\\\\\\])". $replace ."`"; 293 $patterns[] = "`(^|[^\\\\\\\\])". $replace ."`";
250 $repl[] = '${1}'; 294 $repl[] = '${1}';
251 } 295 }
252 $remaining = trim(preg_replace($patterns, $repl, $item['calc'])); 296 $remaining = trim(preg_replace($patterns, $repl, $item['calc']));
297
253 // Next, remove functions and numbers. 298 // Next, remove functions and numbers.
254 $repl = array(); 299 $repl = array();
255 $patterns = array(); 300 $patterns = array();
256 foreach (_views_calc_replacements() as $value) { 301 foreach (_views_calc_replacements() as $value) {
257 $patterns[] = "`(^|[^\\\\\\\\])". preg_quote(trim($value)) ."`"; 302 $patterns[] = "`(^|[^\\\\\\\\])". preg_quote(trim($value)) ."`";
267 312
268 /** 313 /**
269 * Save the views calc field settings 314 * Save the views calc field settings
270 */ 315 */
271 function views_calc_fields_form_submit($form, &$form_state) { 316 function views_calc_fields_form_submit($form, &$form_state) {
272 $form_values = $form_state['values']; 317 $edit = $form_state['values'];
273 $edit = $form_values; 318 $form_values = array();
274 foreach ($edit as $delta => $value) { 319 foreach ($edit as $delta => $value) {
275 if ($value['calc'] == '' || !is_numeric($delta)) { 320 // If this is some form item we don't care about, skip it.
321 if (!is_array($value) || !is_numeric($delta)) {
322 continue;
323 }
324 $value['calc'] = trim($value['calc']);
325 if (empty($value['calc'])) {
276 // remove blank fields, don't save them 326 // remove blank fields, don't save them
277 unset($form_values[$delta]); 327 if (!empty($value['cid'])) {
328 db_query("DELETE FROM {views_calc_fields} WHERE cid=%d", $value['cid']);
329 }
278 330
279 } 331 }
280 else { 332 else {
281 $tables = array(); 333 $tables = array();
282 $form_values[$delta]['label'] = $value['label']; 334 $form_values[$delta]['label'] = $value['label'];
283 $form_values[$delta]['format'] = $value['format']; 335 $form_values[$delta]['format'] = $value['format'];
284 $form_values[$delta]['custom'] = $value['custom']; 336 $form_values[$delta]['custom'] = $value['custom'];
285 $form_values[$delta]['calc'] = $value['calc']; 337 $form_values[$delta]['calc'] = $value['calc'];
338 $form_values[$delta]['base'] = $value['base'];
286 339
287 // Substitute field names back into the calculation. 340 // Substitute field names back into the calculation.
288 $matches = array(); 341 $matches = array();
289 foreach (_views_calc_substitutions() as $key => $value) { 342 $base = $value['base'];
343 foreach (_views_calc_substitutions($base) as $key => $value) {
290 $label_patterns[] = "`(^|[^\\\\\\\\])". preg_quote($value) ."`"; 344 $label_patterns[] = "`(^|[^\\\\\\\\])". preg_quote($value) ."`";
291 $value_patterns[] = "`(^|[^\\\\\\\\])". preg_quote($key) ."`"; 345 $value_patterns[] = "`(^|[^\\\\\\\\])". preg_quote($key) ."`";
292 $repl[] = '${1}'. $key; 346 $repl[] = '${1}'. $key;
293 } 347 }
294 $form_values[$delta]['calc'] = preg_replace($label_patterns, $repl, $form_values[$delta]['calc']); 348 $form_values[$delta]['calc'] = preg_replace($label_patterns, $repl, $form_values[$delta]['calc']);
296 // Extract the fields and table names from the calculation. 350 // Extract the fields and table names from the calculation.
297 $tables = array(); 351 $tables = array();
298 $fields = array(); 352 $fields = array();
299 foreach ($value_patterns as $pattern) { 353 foreach ($value_patterns as $pattern) {
300 if (preg_match($pattern, $form_values[$delta]['calc'], $results)) { 354 if (preg_match($pattern, $form_values[$delta]['calc'], $results)) {
301 $fields[] = trim($results[0]); 355 $fields[trim($results[0])] = trim($results[0]);
302 $tmp = explode('.', trim($results[0])); 356 $tmp = explode('.', trim($results[0]));
303 if (trim($tmp[0])) { 357 if (trim($tmp[0])) {
304 $tables[trim($tmp[0])] = trim($tmp[0]); 358 $tables[trim($tmp[0])] = trim($tmp[0]);
305 } 359 }
306 } 360 }
307 } 361 }
308 $form_values[$delta]['tablelist'] = implode(',', $tables); 362 $form_values[$delta]['tablelist'] = implode(',', $tables);
309 $form_values[$delta]['fieldlist'] = implode(',', $fields); 363 $form_values[$delta]['fieldlist'] = implode(',', $fields);
310 } 364 }
311 } 365 }
312 foreach ($form_values as $delta => $value) { 366
313 if ($value['cid'] == 0) { 367 foreach ((array) $form_values as $delta => $value) {
368 if (empty($value['cid'])) {
314 drupal_write_record('views_calc_fields', $value); 369 drupal_write_record('views_calc_fields', $value);
315 } 370 }
316 else { 371 else {
317 drupal_write_record('views_calc_fields', $value, array('cid')); 372 drupal_write_record('views_calc_fields', $value, array('cid'));
318 } 373 }
364 function _views_calc_replacements() { 419 function _views_calc_replacements() {
365 $operators = array_filter(_views_calc_operators(), 'trim'); 420 $operators = array_filter(_views_calc_operators(), 'trim');
366 $numbers = range(0, 9); 421 $numbers = range(0, 9);
367 return array_merge($operators, $numbers); 422 return array_merge($operators, $numbers);
368 } 423 }
424
425
426 /**
427 * Field export form.
428 */
429 function views_calc_export_form() {
430
431 $fields = _views_calc_fields();
432 $string = '';
433 while ($field = db_fetch_array($fields)) {
434 $base = $field['base'];
435 $substitutions = _views_calc_substitutions($base);
436 $field['calc'] = strtr($field['calc'], $substitutions);
437 $string .= "\$fields[] = ". var_export((array) $field, TRUE) .";\n";
438 }
439
440 $form['#prefix'] = t('This form will export Views Calc custom fields.');
441 $form['macro'] = array(
442 '#type' => 'textarea',
443 '#rows' => 20,
444 '#title' => t('Export data'),
445 '#default_value' => $string,
446 '#description' => t('This is an export of the custom Views Calc fields. Paste this text into a Views Calc import box to import these fields into another installation. This will only work if the other installation uses the same base tables required by these fields.'),
447 );
448 return $form;
449 }
450
451 /**
452 * Field import form.
453 */
454 function views_calc_import_form(&$form_state, $type_name = '') {
455 $form['#prefix'] = t('This form will import Views Calc custom fields.');
456 $form['macro'] = array(
457 '#type' => 'textarea',
458 '#rows' => 20,
459 '#title' => t('Import data'),
460 '#required' => TRUE,
461 '#description' => t('Paste the text created by a Views Calc export into this field.'),
462 );
463 $form['submit'] = array(
464 '#type' => 'submit',
465 '#value' => t('Import'),
466 );
467 // Read in a file if there is one and set it as the default macro value.
468 if (isset($_REQUEST['macro_file']) && $file = file_get_contents($_REQUEST['macro_file'])) {
469 $form['macro']['#default_value'] = $file;
470 if (isset($_REQUEST['type_name'])) {
471 $form['type_name']['#default_value'] = $_REQUEST['type_name'];
472 }
473 $form['#prefix'] .= '<p class="error">'. t('A file has been pre-loaded for import.') .'</p>';
474 }
475 $form['#redirect'] = 'admin/settings/views_calc';
476 return $form;
477 }
478
479 /**
480 * Submit handler for import form.
481 */
482 function views_calc_import_form_submit($form, &$form_state) {
483 $form_values = $form_state['values'];
484 $fields = NULL;
485
486 // Use '@' to suppress errors about undefined constants in the macro.
487 @eval($form_values['macro']);
488
489 if (empty($fields) || !is_array($fields)) {
490 return;
491 }
492
493 foreach ($fields as $delta => $field) {
494 // Don't over-write existing fields, create new ones.
495 $fields[$delta]['cid'] = NULL;
496 }
497
498 // Run the values thru drupal_execute() so they are properly validated.
499 $form_state = array('values' => $fields);
500 drupal_execute('views_calc_fields_form', $form_state);
501
502 }