franck@0: 0); franck@0: return $options; franck@0: } franck@0: franck@0: /** franck@0: * Render the given style. franck@0: */ franck@0: function options_form(&$form, &$form_state) { franck@0: parent::options_form($form, $form_state); franck@0: $form['#theme'] = 'views_calc_ui_table'; franck@0: franck@0: $form['detailed_values'] = array( franck@0: '#title' => t('Show details'), franck@0: '#type' => 'select', franck@0: '#options' => array(0 => t('Yes'), 1 => t('No')), franck@0: '#default_value' => $this->options['detailed_values'], franck@0: '#description' => t("Select 'Yes' to show detailed values followed by column calculations, 'No' to surpress details and show only calculated column totals."), franck@0: ); franck@0: franck@0: $handlers = $this->display->handler->get_handlers('field'); franck@0: $columns = $this->sanitize_columns($this->options['columns']); franck@0: franck@0: foreach ($columns as $field => $column) { franck@0: $safe = str_replace(array('][', '_', ' '), '-', $field); franck@0: $id = 'edit-style-options-columns-' . $safe; franck@0: $form['info'][$field]['justification'] = array( franck@0: '#type' => 'select', franck@0: '#default_value' => isset($this->options['info'][$field]['justification']) ? $this->options['info'][$field]['justification'] : 'views_calc_justify_none', franck@0: '#options' => array( franck@0: 'views_calc_justify_none' => t('None'), franck@0: 'views_calc_justify_left' => t('Left'), franck@0: 'views_calc_justify_right' => t('Right'), franck@0: 'views_calc_justify_center' => t('Center'), franck@0: ), franck@0: '#process' => array('views_process_dependency'), franck@0: '#dependency' => array($id => array($field)), franck@0: ); franck@0: $form['info'][$field]['has_calc'] = array( franck@0: '#type' => 'checkbox', franck@0: '#title' => t('Display calculation'), franck@0: '#default_value' => isset($this->options['info'][$field]['has_calc']) ? $this->options['info'][$field]['has_calc'] : 0, franck@0: '#process' => array('views_process_dependency'), franck@0: '#dependency' => array($id => array($field)), franck@0: ); franck@0: franck@0: $options = _views_calc_calc_options(); franck@0: $form['info'][$field]['calc'] = array( franck@0: '#type' => 'select', franck@0: '#options' => $options, franck@0: '#default_value' => isset($this->options['info'][$field]['calc']) ? $this->options['info'][$field]['calc'] : array(), franck@0: '#process' => array('views_process_dependency'), franck@0: '#dependency' => array('edit-style-options-info-'. $safe .'-has-calc' => array(TRUE)), franck@0: '#multiple' => TRUE, franck@0: ); franck@0: } franck@0: } franck@0: franck@0: /** franck@0: * TODO franck@0: * figure out what changes are needed so Views field groups will work. franck@0: */ franck@0: function pre_render($results) { franck@0: parent::pre_render($results); franck@0: franck@0: // If there are no calc fields, do nothing. franck@0: if (!$calc_fields = $this->get_calc_fields()) { franck@0: return; franck@0: } franck@0: // If we're not getting a summary row, do nothing. franck@0: if (!empty($this->view->views_calc_calculation)) { franck@0: return; franck@0: } franck@0: franck@0: $this->view->totals = array(); franck@0: $this->view->sub_totals = array(); franck@0: franck@0: // Subtotals and pager totals require a list of the specific franck@0: // values to include. franck@0: $paged = FALSE; franck@0: if (!empty($this->view->pager) franck@0: && !empty($this->view->pager['use_pager']) franck@0: && !empty($this->view->pager['items_per_page'])) { franck@0: $nids = array(); franck@0: foreach ($this->view->result as $delta => $value) { franck@0: $nids[] = $value->nid; franck@0: } franck@0: // Add sub_total rows to the results. franck@0: foreach ($calc_fields as $calc => $field) { franck@0: if ($summary_view = views_get_view($this->view->name)) { franck@0: $summary_view->set_display($this->view->current_display); franck@0: $summary_view->set_arguments($this->view->args); franck@0: $summary_view->views_calc_calculation = $calc; franck@0: $summary_view->views_calc_nids = $nids; franck@0: $summary_view->views_calc_sub_total = TRUE; franck@0: $summary_view->is_cacheable = FALSE; franck@0: $summary_view->execute(); franck@0: $this->view->sub_totals[] = array_shift($summary_view->result); franck@0: } franck@0: } franck@0: } franck@0: franck@0: // Add grand totals to the results. franck@0: foreach ($calc_fields as $calc => $field) { franck@0: if ($summary_view = views_get_view($this->view->name)) { franck@0: $summary_view->set_display($this->view->current_display); franck@0: $summary_view->set_arguments($this->view->args); franck@0: $summary_view->pager['items_per_page'] = 0; franck@0: $summary_view->views_calc_calculation = $calc; franck@0: $summary_view->views_calc_nids = array(); franck@0: $summary_view->views_calc_sub_total = FALSE; franck@0: $summary_view->is_cacheable = FALSE; franck@0: $summary_view->execute(); franck@0: $this->view->totals[] = array_shift($summary_view->result); franck@0: } franck@0: } franck@0: } franck@0: franck@0: function query() { franck@0: parent::query(); franck@0: franck@0: // If we're not getting a summary row, do nothing. franck@0: if (empty($this->view->views_calc_calculation)) { franck@0: return; franck@0: } franck@0: // If there are no calc fields, do nothing. franck@0: if (!$calc_fields = $this->get_calc_fields()) { franck@0: return; franck@0: } franck@0: franck@0: if (!empty($this->view->views_calc_sub_total)) { franck@0: $this->query_sub_total(); franck@0: } franck@0: else { franck@0: $this->query_total(); franck@0: } franck@0: } franck@0: franck@0: /** franck@0: * franck@0: */ franck@0: function query_sub_total() { franck@0: // Create summary rows. franck@0: $calc_fields = $this->get_calc_fields(); franck@0: $calc = $this->view->views_calc_calculation; franck@0: $fields = $calc_fields[$calc]; franck@0: franck@0: // Empty out any fields that have been added to the query, franck@0: // we don't need them for the summary totals. franck@0: $this->view->query->fields = array(); franck@0: foreach ($this->view->field as $field) { franck@0: $query_field = substr($field->field, 0, 3) == 'cid' ? $field->definition['calc'] : $field->table .'.'. $field->field; franck@0: $query_alias = $field->field_alias; franck@0: if (in_array($field->field, $fields)) { franck@0: // Calculated fields. franck@0: $this->view->query->add_field(NULL, "$calc($query_field)", $query_alias); franck@0: $this->view->query->add_table($field->table, NULL, NULL, $field->table); franck@0: } franck@0: else { franck@0: // Empty fields that have no calculations. franck@0: $this->view->query->add_field(NULL, "MAX('')", $query_alias); franck@0: } franck@0: // Add a dummy field for the groupby. franck@0: $this->view->query->add_field(NULL, "MAX('". $calc ."')", "TOTAL_". $calc); franck@0: } franck@0: // TODO This won't work right with relationships, need a fix here. franck@0: if (!empty($this->view->views_calc_nids)) { franck@0: $this->view->query->add_where(NULL, "node.nid IN (%s)", implode(',', $this->view->views_calc_nids)); franck@0: } franck@0: } franck@0: franck@0: /** franck@0: * The grand total can be computed using GROUPBY without regard franck@0: * to pager values. franck@0: */ franck@0: function query_total() { franck@0: // Create summary rows. franck@0: $calc_fields = $this->get_calc_fields(); franck@0: $calc = $this->view->views_calc_calculation; franck@0: $fields = $calc_fields[$calc]; franck@0: franck@0: // Empty out any fields that have been added to the query, franck@0: // we don't need them for the summary totals. franck@0: $this->view->query->fields = array(); franck@0: // Clear out any sorting and grouping, it can create unexpected results franck@0: // when Views adds aggregation values for the sorts. franck@0: $this->view->query->orderby = array(); franck@0: $this->view->query->groupby = array(); franck@0: franck@0: foreach ($this->view->field as $field) { franck@0: $query_field = substr($field->field, 0, 3) == 'cid' ? $field->definition['calc'] : $field->table .'.'. $field->field; franck@0: $query_alias = $field->field_alias; franck@0: $this->view->query->add_table($field->table, NULL, NULL, $field->table); franck@0: if (!empty($fields) && in_array($field->field, $fields)) { franck@0: // Calculated fields. franck@0: $this->view->query->add_field(NULL, "$calc($query_field)", $query_alias); franck@0: } franck@0: else { franck@0: // Empty fields that have no calculations. franck@0: $this->view->query->add_field(NULL, "MAX('')", $query_alias); franck@0: } franck@0: // Add a dummy field for the groupby. franck@0: $this->view->query->add_field(NULL, "MAX('". $calc ."')", "TOTAL_". $calc); franck@0: } franck@0: } franck@0: franck@0: function get_calc_fields() { franck@0: $options = $this->view->style_plugin->options; franck@0: $handler = $this->view->style_plugin; franck@0: $fields = $this->view->field; franck@0: $columns = $handler->sanitize_columns($options['columns'], $fields); franck@0: $calcs = array_keys(_views_calc_calc_options()); franck@0: franck@0: $calc_fields = array(); franck@0: foreach ($columns as $field => $column) { franck@0: if ($field == $column && empty($fields[$field]->options['exclude'])) { franck@0: if ($options['info'][$field]['has_calc']) { franck@0: foreach ($calcs as $calc) { franck@0: if (isset($this->options['info'][$field]['calc'][$calc])) { franck@0: $calc_fields[$calc][] = $field; franck@0: } franck@0: } franck@0: } franck@0: } franck@0: } franck@0: return $calc_fields; franck@0: } franck@0: }