Mercurial > defr > drupal > views_calc
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 } |
