![]() |
Xataface Summary Module 0.1
Summary Reports for Xataface Apps
|
00001 <?php 00002 /* 00003 * Xataface Summary Module 00004 * 00005 * Copyright (C) 2011 Steve Hannah <shannah@sfu.ca> 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Library General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Library General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Library General Public 00018 * License along with this library; if not, write to the 00019 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 00020 * Boston, MA 02110-1301, USA. 00021 */ 00022 00061 class actions_summary_page { 00062 00067 private $table; 00068 00073 private $groupFuncs; 00074 00079 private $mod; 00080 00085 private $selectedSummaryCols; 00086 00091 private $groupBy; 00092 00093 00097 function handle($params){ 00098 00099 $app = Dataface_Application::getInstance(); 00100 $query = $app->getQuery(); 00101 $mod = Dataface_ModuleTool::getInstance()->loadModule('modules_summary'); 00102 $this->mod = $mod; 00103 00104 // Now work on our dependencies 00105 $mt = Dataface_ModuleTool::getInstance(); 00106 00107 // We require the XataJax module 00108 // The XataJax module activates and embeds the Javascript and CSS tools 00109 $mt->loadModule('modules_XataJax', 'modules/XataJax/XataJax.php'); 00110 00111 $jt = Dataface_JavascriptTool::getInstance(); 00112 $jt->addPath(dirname(__FILE__).'/../js', $mod->getBaseURL().'/js'); 00113 00114 $ct = Dataface_CSSTool::getInstance(); 00115 $ct->addPath(dirname(__FILE__).'/../css', $mod->getBaseURL().'/css'); 00116 00117 // Add our javascript 00118 $jt->import('xataface/modules/summary/summary-page.js'); 00119 00120 00121 $table = Dataface_Table::loadTable($query['-table']); 00122 $this->table = $table; 00123 00124 // Let's get all of the table columns 00125 $fields = $table->fields(false, true, false); 00126 $summaryFields = $mod->getSummaryFields($table); 00127 00128 00129 $groupableFields = array(); 00130 $summarizableFields = array(); 00131 $temp = array(); 00132 00133 foreach ($summaryFields as $k=>$v){ 00134 $perms = $table->getPermissions(array('field'=>$k)); 00135 if ( @$perms['summary view']){ 00136 $temp[$k] = $v; 00137 } 00138 00139 } 00140 $summaryFields = $temp; 00141 00142 00143 foreach ($fields as $k=>$v){ 00144 $perms = $table->getPermissions(array('field'=>$k)); 00145 if ( @$perms['summary group'] and @$perms['summary view'] ){ 00146 $groupableFields[$k]=$v; 00147 } 00148 if ( @$perms['summary view'] ){ 00149 $summarizableFields[$k] = $v; 00150 00151 } 00152 } 00153 00154 $groupFuncs = array( 00155 'min'=>array( 00156 'label'=>'Min', 00157 'description'=>'Show minimum value in set.', 00158 'param'=>'min(%s)', 00159 'types'=>array( 00160 'all' 00161 ) 00162 ), 00163 'max'=>array( 00164 'label'=>'Max', 00165 'description'=>'Show the maximum value in set.', 00166 'param'=>'max(%s)', 00167 'types'=>array( 00168 'all' 00169 ) 00170 ), 00171 'avg'=>array( 00172 'label'=>'Avg', 00173 'description'=>'Show the average value of this column in the set.', 00174 'param'=>'avg(%s)', 00175 'types'=>array( 00176 'all' 00177 ) 00178 ), 00179 'sum'=>array( 00180 'label'=>'Sum', 00181 'description'=>'Show the sum of all rows for this column.', 00182 'param'=>'sum(%s)', 00183 'types'=>array( 00184 'all' 00185 ) 00186 ), 00187 'count'=>array( 00188 'label'=>'Count', 00189 'description'=>'Counts the number of rows in teh set.', 00190 'param'=>'count(%s)', 00191 'types'=>array('all') 00192 00193 ), 00194 'count-distinct',array( 00195 'label'=>'Count (distinct)', 00196 'description'=>'Counts the number of distinct values in this column in the set.', 00197 'param'=>'count(distinct %s)', 00198 'types'=>array('all') 00199 ), 00200 'std'=>array( 00201 'label'=>'Std', 00202 'description'=>'Standard deviation of this column in the set.', 00203 'param'=>'std(%s)', 00204 'types'=>array('all') 00205 ) 00206 ); 00207 00208 $this->groupFuncs =& $groupFuncs; 00209 00210 00211 00212 00213 // Now for the result set 00214 00215 $groupBy = array(); 00216 if ( @$_GET['-group-by'] ){ 00217 $groupBy = explode(',', $_GET['-group-by']); 00218 00219 } 00220 foreach ($groupBy as $key=>$val){ 00221 if ( !isset($groupableFields[$val]) ){ 00222 unset($groupBy[$key]); 00223 } 00224 } 00225 00226 $this->groupBy =& $groupBy; 00227 00228 $selectedSummaryCols = null; 00229 if ( @$_GET['-summary-cols'] ){ 00230 $selectedSummaryCols = explode(',', $_GET['-summary-cols']); 00231 } 00232 if ( !$selectedSummaryCols ){ 00233 $selectedSummaryCols = array_keys($mod->getSummaryFields($table)); 00234 00235 } 00236 $this->selectedSummaryCols =& $selectedSummaryCols; 00237 $graftedSummaryColumnDefs = array(); 00238 00239 if ( $selectedSummaryCols ){ 00240 foreach ($selectedSummaryCols as $key=>$col){ 00241 if ( preg_match('/^([^\)]+)\(([^\)]+)\)$/', $col, $matches) ){ 00242 // THis is a calculated field passed through the GET parameters 00243 // so we need to parse it out and add it as a proper summary field. 00244 $paramField = $matches[2]; 00245 $funcName = $matches[1]; 00246 00247 if ( !isset($groupFuncs[$funcName]) ){ 00248 unset($selectedSummaryCols[$key]); 00249 continue; 00250 } 00251 00252 if ( !isset($summarizableFields[$paramField]) ){ 00253 unset($selectedSummaryCols[$key]); 00254 continue; 00255 } 00256 00257 $fieldDef =& $summarizableFields[$paramField]; 00258 00259 $graftedSummaryColumnDefs[$paramField.'__'.$funcName] = array( 00260 'formula'=> sprintf($groupFuncs[$funcName]['param'], '`'.$paramField.'`'), 00261 'widget'=>array('label'=>$groupFuncs[$funcName]['label'].'('.$fieldDef['widget']['label'].')'), 00262 'name'=>$paramField.'__'.$funcName 00263 ); 00264 unset($selectedSummaryCols[$key]); 00265 $selectedSummaryCols[] = $paramField.'__'.$funcName; 00266 00267 00268 } 00269 } 00270 } 00271 00272 $summaryFieldsRef =& $mod->getSummaryFields($table); 00273 00274 foreach ($graftedSummaryColumnDefs as $key=>$val){ 00275 $summaryFieldsRef[$key] = $val; 00276 } 00277 00278 //print_r($graftedSummaryColumnDefs); 00279 if ( $selectedSummaryCols ){ 00280 $sql = $mod->getSummarySQL($table, $query, $groupBy, $selectedSummaryCols); 00281 //echo $sql;exit; 00282 $res = mysql_query($sql, df_db()); 00283 if ( !$res ){ 00284 throw new Exception(mysql_error(df_db())); 00285 } 00286 $rows = array(); 00287 while ($row = mysql_fetch_assoc($res) ){ 00288 $rows[] = $row; 00289 } 00290 @mysql_free_result($res); 00291 } else { 00292 $rows = array(); 00293 } 00294 00295 00296 00297 00298 00299 00300 $context = array( 00301 'summaryFields'=>$summaryFields, 00302 'groupableFields'=>$groupableFields, 00303 'summarizableFields'=>$summarizableFields, 00304 'groupFuncs'=> $groupFuncs, 00305 'self'=>$this, 00306 'rows'=>$rows, 00307 'numResults'=>$app->getResultSet()->found(), 00308 'table'=>$table, 00309 00310 'groupBy'=>($groupBy?$groupBy:array()) 00311 ); 00312 00313 df_register_skin('modules_summary', dirname(__FILE__).'/../templates'); 00314 df_display($context, 'xataface/modules/summary/main.html'); 00315 00316 00317 00318 00319 00320 00321 00322 } 00323 00324 00336 function supports($fieldname, $funcname){ 00337 $func = @$this->groupFuncs[$funcname]; 00338 if ( !$func ) return false; 00339 if ( !@$func['types'] ) return false; 00340 if ( !is_array($func['types']) ) return false; 00341 00342 if ( $this->table->exists($fieldname) ){ 00343 if ( in_array('all', $func['types']) ) return true; 00344 if ( ($this->table->isInt($fieldname) or $this->table->isFloat($fieldname)) and in_array('numeric', $func['types']) ){ 00345 return true; 00346 } 00347 } else { 00348 $sf =& $this->mod->getSummaryFields($this->table); 00349 if ( !isset($sf[$fieldname]) ) return false; 00350 if ( in_array('formula', $func['types']) ){ 00351 return true; 00352 } 00353 } 00354 return false; 00355 00356 } 00357 00373 function getSummaryLabel($col){ 00374 $f =& $this->mod->getSummaryField($this->table, $col); 00375 if ( $f and @$f['label'] ) return $f['label']; 00376 if ( $f and @$f['widget'] and @$f['widget']['label'] ) return $f['widget']['label']; 00377 00378 return $col; 00379 } 00380 00381 00391 function getFieldLabel($col){ 00392 $f = $this->table->getField($col); 00393 if ( $f and @$f['widget']['label'] ){ 00394 return $f['widget']['label']; 00395 } 00396 return $col; 00397 } 00398 00410 function isSelectedGroupField($fieldname){ 00411 return in_array($fieldname, $this->groupBy); 00412 } 00413 00426 function isSelectedSummaryField($fieldname, $func=null){ 00427 if ( !is_array($this->selectedSummaryCols) ) return false; 00428 if ( isset($func) ){ 00429 $fieldname .= '__'.$func; 00430 } 00431 return in_array($fieldname, $this->selectedSummaryCols); 00432 } 00433 00444 function get($array, $key){ return $array[$key]; } 00445 00450 function getSelectedSummaryColumns(){ 00451 //print_r($this->selectedSummaryCols); 00452 return $this->selectedSummaryCols; 00453 } 00454 00455 00456 function getCellValue($fieldname, $value){ 00457 if ( $this->table->hasField($fieldname) ){ 00458 $rec = new Dataface_Record($this->table->tablename, array($fieldname=>$value)); 00459 return $rec->display($fieldname); 00460 } else { 00461 return $value; 00462 } 00463 } 00464 00465 function explainQueryParam($label, $value){ 00466 $l = $label; 00467 $v = $value; 00468 $fc = $v{0}; 00469 if ( $fc == '=' ){ 00470 if ( strlen($v)===1 ){ 00471 return $l.' is blank'; 00472 } 00473 return $l.' = "'.substr($v,1).'"'; 00474 } else if ( $fc == '>' and @$v{1} != '='){ 00475 if ( strlen($v)===1 ){ 00476 return $l.' is not blank'; 00477 } 00478 return $l.' > "'.substr($v,1).'"'; 00479 } else if ( $fc == '<' and @$v{1} != '=' ){ 00480 return $l.' < "'.substr($v,1).'"'; 00481 } else if ( $fc == '>' and @$v{1} == '='){ 00482 00483 return $l.' >= "'.substr($v,2).'"'; 00484 } else if ( $fc == '<' and @$v{1} == '=' ){ 00485 return $l.' <= "'.substr($v,2).'"'; 00486 } else if ( $fc == '~' ){ 00487 return $l.' matches pattern "'.substr($v,1).'"'; 00488 } else if ( $parts = explode('..', $v) and count($parts) > 1 ){ 00489 return $l.' is between "'.$parts[0].'" and "'.$parts[1].'"'; 00490 } else if ( $this->table->isInt($k) or $this->table->isFloat($k) ){ 00491 return $l.' = '.$v; 00492 } else { 00493 return $l.' contains "'.$v.'"'; 00494 } 00495 00496 } 00497 00498 function getCurrentFilters(){ 00499 $app = Dataface_Application::getInstance(); 00500 $query = $app->getQuery(); 00501 00502 $filter = array(); 00503 foreach ($query as $k=>$v){ 00504 if ( !isset($v) or $v === '' ) continue; 00505 if ( $this->table->hasField($k) ){ 00506 00507 00508 $fld = $this->table->getField($k); 00509 $l = $fld['widget']['label']; 00510 $filter[$k] = $this->explainQueryParam($l, $v); 00511 00512 00513 } else if ( strpos($k,'/') !== false ){ 00514 // We may have a related field query. 00515 list($rel,$fld) = explode('/', $k); 00516 if ( $this->table->hasRelationship($rel) ){ 00517 $relObj = $this->table->getRelationship($rel); 00518 if ( $relObj->hasField($fld, true) ){ 00519 $fldDef = $relObj->getField($fld); 00520 if ( PEAR::isError($fldDef) ) continue; 00521 $l = $fldDef['widget']['label']; 00522 $filter[$k] = $relObj->getLabel().' contains a related record with '.$this->explainQueryParam($l, $v); 00523 00524 } 00525 } 00526 00527 } 00528 } 00529 return $filter; 00530 } 00531 }