Merge pull request #496 from sminnee/dataquery-aggregate

Dataquery aggregate
This commit is contained in:
Sam Minnée 2012-06-14 17:20:35 -07:00
commit a93dd9459e
6 changed files with 98 additions and 21 deletions

View File

@ -56,6 +56,11 @@ class GridField extends FormField {
* @var array
*/
protected $columnDispatch = null;
/**
* Map of callbacks for custom data fields
*/
protected $customDataFields = array();
protected $name = '';
@ -411,6 +416,30 @@ class GridField extends FormField {
throw new InvalidArgumentException("Bad column '$column'");
}
}
/**
* Add additional calculated data fields to be used on this GridField
* @param array $fields a map of fieldname to callback. The callback will bed passed the record as an argument.
*/
public function addDataFields($fields) {
if($this->customDataFields) $this->customDataFields = array_merge($this->customDataFields, $fields);
else $this->customDataFields = $fields;
}
/**
* Get the value of a named field on the given record.
* Use of this method ensures that any special rules around the data for this gridfield are followed.
*/
public function getDataFieldValue($record, $fieldName) {
// Custom callbacks
if(isset($this->customDataFields[$fieldName])) {
$callback = $this->customDataFields[$fieldName];
return $callback($record);
}
// Default implementation
return $record->relField($fieldName);
}
/**
* Get extra columns attributes used as HTML attributes

View File

@ -118,11 +118,18 @@ class GridFieldDataColumns implements GridField_ColumnProvider {
* @return string HTML for the column. Return NULL to skip.
*/
public function getColumnContent($gridField, $record, $columnName) {
// Find the data column for the given named column
$columns = $this->getDisplayFields($gridField);
$columnInfo = $columns[$columnName];
// Allow callbacks
if(is_array($columnInfo) && isset($columnInfo['callback'])) {
$method = $columnInfo['callback'];
$value = Convert::raw2xml($method($record));
// This supports simple FieldName syntax
if(strpos($columnName, '.') === false) {
$value = $record->XML_val($columnName);
} else {
$value = $this->getValueFromRelation($record, $columnName);
$value = Convert::raw2xml($gridField->getDataFieldValue($record, $columnName));
}
$value = $this->castValue($gridField, $columnName, $value);
@ -154,8 +161,16 @@ class GridFieldDataColumns implements GridField_ColumnProvider {
*/
public function getColumnMetadata($gridField, $column) {
$columns = $this->getDisplayFields($gridField);
$title = null;
if(is_string($columns[$column])) {
$title = $columns[$column];
} else if(is_array($columns[$column]) && isset($columns[$column]['title'])) {
$title = $columns[$column]['title'];
}
return array(
'title' => $columns[$column],
'title' => $title,
);
}
@ -212,7 +227,7 @@ class GridFieldDataColumns implements GridField_ColumnProvider {
$spec = $this->fieldFormatting[$fieldName];
if(is_callable($spec)) {
return $spec($item);
return $spec($value, $item);
} else {
$format = str_replace('$value', "__VAL__", $spec);
$format = preg_replace('/\$([A-Za-z0-9-_]+)/', '$item->$1', $format);

View File

@ -138,7 +138,7 @@ class GridFieldExportButton implements GridField_HTMLProvider, GridField_ActionP
$value = $columnHeader($relObj);
} else {
$value = $item->relField($columnSource);
$value = $gridField->getDataFieldValue($item, $columnSource);
}
$value = str_replace(array("\r", "\n"), "\n", $value);

View File

@ -115,7 +115,7 @@ class GridFieldPrintButton implements GridField_HTMLProvider, GridField_ActionPr
foreach($items as $item) {
$itemRow = new ArrayList();
foreach($printColumns as $field => $label) {
$value = $item->relField($field);
$value = $gridField->getDataFieldValue($item, $field);
$itemRow->push(
new ArrayData(array(
"CellString" => $value,

View File

@ -220,18 +220,26 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
* @return DataList
*/
public function filter() {
$numberFuncArgs = count(func_get_args());
$whereArguments = array();
if($numberFuncArgs == 1 && is_array(func_get_arg(0))) {
$whereArguments = func_get_arg(0);
} elseif($numberFuncArgs == 2) {
$whereArguments[func_get_arg(0)] = func_get_arg(1);
} else {
throw new InvalidArgumentException('Incorrect number of arguments passed to filter()');
// Validate and process arguments
$arguments = func_get_args();
switch(sizeof($arguments)) {
case 1: $filters = $arguments[0]; break;
case 2: $filters = array($arguments[0] => $arguments[1]); break;
default:
throw new InvalidArgumentException('Incorrect number of arguments passed to filter()');
}
$clone = clone $this;
$clone->addFilter($filters);
return $clone;
}
/**
* Modify this DataList, adding a filter
*/
public function addFilter($filterArray) {
$SQL_Statements = array();
foreach($whereArguments as $field => $value) {
foreach($filterArray as $field => $value) {
if(is_array($value)) {
$customQuery = 'IN (\''.implode('\',\'',Convert::raw2sql($value)).'\')';
} else {
@ -256,6 +264,24 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
return $this;
}
/**
* Filter this DataList by a callback function.
* The function will be passed each record of the DataList in turn, and must return true for the record to be included.
* Returns the filtered list.
*
* Note that, in the current implementation, the filtered list will be an ArrayList, but this may change in a future
* implementation.
*/
public function filterByCallback($callback) {
if(!is_callable($callback)) throw new LogicException("DataList::filterByCallback() must be passed something callable.");
$output = new ArrayList;
foreach($this as $item) {
if($callback($item)) $output->push($item);
}
return $output;
}
/**
* Translates a Object relation name to a Database name and apply the relation join to
* the query. Throws an InvalidArgumentException if the $field doesn't correspond to a relation

View File

@ -329,8 +329,8 @@ class DataQuery {
*
* @param String $field Unquoted database column name (will be escaped automatically)
*/
function max($field) {
return $this->getFinalisedQuery()->aggregate(sprintf('MAX("%s")', Convert::raw2sql($field)))->execute()->value();
function max($field) {
return $this->aggregate(sprintf('MAX("%s")', Convert::raw2sql($field)));
}
/**
@ -339,7 +339,7 @@ class DataQuery {
* @param String $field Unquoted database column name (will be escaped automatically)
*/
function min($field) {
return $this->getFinalisedQuery()->aggregate(sprintf('MIN("%s")', Convert::raw2sql($field)))->execute()->value();
return $this->aggregate(sprintf('MIN("%s")', Convert::raw2sql($field)));
}
/**
@ -348,7 +348,7 @@ class DataQuery {
* @param String $field Unquoted database column name (will be escaped automatically)
*/
function avg($field) {
return $this->getFinalisedQuery()->aggregate(sprintf('AVG("%s")', Convert::raw2sql($field)))->execute()->value();
return $this->aggregate(sprintf('AVG("%s")', Convert::raw2sql($field)));
}
/**
@ -357,7 +357,14 @@ class DataQuery {
* @param String $field Unquoted database column name (will be escaped automatically)
*/
function sum($field) {
return $this->getFinalisedQuery()->aggregate(sprintf('SUM("%s")', Convert::raw2sql($field)))->execute()->value();
return $this->aggregate(sprintf('SUM("%s")', Convert::raw2sql($field)));
}
/**
* Runs a raw aggregate expression. Please handle escaping yourself
*/
function aggregate($expression) {
return $this->getFinalisedQuery()->aggregate($expression)->execute()->value();
}
/**