forena-8.x-1.x-dev/src/FrxPlugin/Template/FrxCrosstab.php
src/FrxPlugin/Template/FrxCrosstab.php
<?php namespace Drupal\forena\Template; use Drupal\forena\FrxAPI; /** * Crosstab Report Template * * @FrxTemplate(id="FrxCrosstab", name="Cross Tab Data") * */ class FrxCrosstab extends TemplateBase { use FrxAPI; public $templateName = 'Crosstab'; private $headers = array(); private $dim_columns = array(); private $group_columns = array(); private $dim_headers = array(); private $group_headers = array(); private $weight; /** * Crosstab configuration form. */ public function configForm($config) { // Load header informationi from parent config. $form = parent::configForm($config); $this->weight_sort($config['crosstab_columns']); $types = array('heading' => t('Heading'), 'crosstab' => t('Crosstab'), 'value' => 'Value', 'ignore' => t('Ignore')); $form['crosstab_columns'] = array('#theme' => 'forena_element_draggable', '#draggable_id' => 'FrxCrosstab-columns'); foreach ($config['crosstab_columns'] as $key => $col) { $ctl = array(); $ctl['label'] = array( '#type' => 'textfield', '#size' => 30, '#title' => t('Label'), '#default_value' => $col['label'], ); $ctl['contents'] = array( '#type' => 'textfield', '#size' => '30', '#title' => t('Data'), '#default_value' => $col['contents'], ); $ctl['type'] = array( '#type' => 'radios', '#title' => t('Type'), '#default_value' => $col['type'], '#options' => $types, '#ajax' => $this->configAjax() ); $ctl['weight'] = array( "#type" => 'weight', '#title' => t('Weight'), '#delta' => 50, '#default_value' => $col['weight'], ); $form['crosstab_columns'][$key] = $ctl; } return $form; } public function generate() { $config['class'] = get_class($this); $block = @$config['block']; $id = @$config['id']; if ($block) { $id = $this->idFromBlock($block); $config['id'] = $id . '_block'; } $config['class'] = @$config['class'] ? $config['class'] . ' FrxCrosstab' : 'FrxCrosstab'; $div = $this->blockDiv($config); // PUt on the header $this->removeChildren($div); if (isset($config['header']['value'])) $this->addFragment($div, $config['header']['value']); // Decide to inlcude columns $found_columns = $this->columns($xml); if (!$found_columns) { $found_columns = $this->columns($xml, '/*'); $attrs = array(); } $numeric_columns = $this->numeric_columns; $new_columns = @$config['crosstab_columns'] ? FALSE : TRUE; foreach ($found_columns as $column => $label) { $token = '{' . $column . '}'; if ($new_columns) { $type = isset($numeric_columns[$column]) ? 'value' : 'heading'; } else { $type = 'ignore'; } if (!isset($config['crosstab_columns'][$column])) { $this->addColumn($type, '{' . $column . '}', $column, $config); } } // Generate the grouping row $group = ''; $dim = array(); foreach($config['crosstab_columns'] as $col) { if ($col['type'] == 'heading') $group .= $col['contents']; if ($col['type'] == 'crosstab') $dim = $col['contents']; } $r_id = $id . '-renderer'; $table_frx['renderer'] = 'FrxCrosstab'; $table_frx['group'] = $group; $table_frx['dim'] = $dim; $attrs[$id] = $r_id; //$attrs = array('foreach' => '*'); $table = $this->setFirstNode($div, 4, 'table', NULL, $attrs, $table_frx); $thead = $this->setFirstNode($table, 6, 'thead'); $throw = $this->setFirstNode($thead, 8, 'tr'); $tbody = $this->setFirstNode($table, 6, 'tbody'); $tdrow = $this->setFirstNode($tbody, 8, 'tr', NULL, array('id' => $id),$attrs); if ($config['crosstab_columns']) foreach ($config['crosstab_columns'] as $key => $col) if ($col['type']!=='ignore') { if ($col['type']=='heading') { $tag = 'th'; } else { $tag = 'td'; } if ($col['type'] != 'crosstab') { $this->addNode($throw, 10, $tag, $col['label']); $this->addNode($tdrow, 10, $tag, $col['contents']); } } if (isset($config['footer']['value'])) $this->addFragment($div, $config['footer']['value']); } /** * Default configuration validator. Simply validates header and footer attributes. * @param array $config * configuration * @return array * errors in configuration. */ public function configValidate(&$config) { $errors = $this->validateTextFormats($config, array('header', 'footer')); $dims = 0; if (@$config['crosstab_columns']) foreach ($config['crosstab_columns'] as $col) { if (@$col['type']=='value') { $dims++; } } if ($dims > 1) $errors[] = t('Too many value columns. Please select only one'); return $errors; } private function addColumn($type, $token, $label, &$config) { $key = trim($token, '{}'); $this->weight++; $config['crosstab_columns'][$key] = array( 'contents' => $token, 'label' => $label, 'type' => $type, 'weight' => $this->weight, ); } /** * Extract table configuration from the HTML * @see FrxRenderer::scrapeConfig() */ public function scrapeConfig(\SimpleXMLElement $xml) { $this->weight = 0; $config=array(); $nodes = $this->reportDocNode->xpath('//table'); if ($nodes) { $table = $nodes[0]; $attrs = $this->mergedAttributes($table); } $config['group'] = $group = $attrs['group']; $config['dim'] = $dim = $attrs['dim']; $this->extractTemplateHTML($this->reportDocDomNode, $config, array('table')); $head_ths = $this->extractXPathInnerHTML('*//thead/tr/th', $this->reportDocDomNode, FALSE); $head_tds = $this->extractXPathInnerHTML('*//thead/tr/td', $this->reportDocDomNode, FALSE); $body_ths = $this->extractXPathInnerHTML('*//tbody/tr/th', $this->reportDocDomNode, FALSE); $body_tds = $this->extractXPathInnerHTML('*//tbody/tr/td', $this->reportDocDomNode, FALSE); $heading_cols = array_combine($head_ths, $body_ths); $data_cols = array_combine($head_tds, $body_tds); // Get the named headers foreach($heading_cols as $label=>$token) { $this->addColumn('heading', $token, $label, $config); } // Get the data cells if ($dim) { $dims = (array)$dim; foreach($dims as $dim) { $this->addColumn('crosstab', $dim, trim($dim, '{}'), $config); } } foreach($data_cols as $label=>$token) { $this->addColumn('value', $token, $label, $config); } return $config; } }