2011-09-29 01:16:15 +02:00
|
|
|
<?php
|
|
|
|
/**
|
2011-10-27 05:11:26 +02:00
|
|
|
* The GridFieldPresenter is responsible for rendering and attach user behaviour
|
|
|
|
* to a GridField.
|
|
|
|
*
|
|
|
|
* You can create a GridFieldPresenter and inject that into a GridField to
|
|
|
|
* customise look and feel of GridField.
|
|
|
|
*
|
|
|
|
* It also have the possibility to let extensions to modify the look and feel of
|
|
|
|
* the GridField if you dont want to make a fully blown GridFieldPresenter.
|
|
|
|
*
|
|
|
|
* In the following example we configure the GridField to sort the DataList in
|
|
|
|
* the GridField by Title. This will override the sorting on the DataList.
|
|
|
|
*
|
|
|
|
* <code>
|
|
|
|
* $presenter = new GridFieldPresenter();
|
|
|
|
* $presenter->sort('Title', 'desc');
|
|
|
|
* $gridField = new GridField('ExampleGrid', 'Example grid', new DataList('Page'),null, $presenter);
|
|
|
|
* </code>
|
|
|
|
*
|
|
|
|
* Another example is to change the template for the rendering
|
|
|
|
*
|
|
|
|
* <code>
|
|
|
|
* $presenter = new GridFieldPresenter();
|
|
|
|
* $presenter->setTemplate('MyNiftyGridTemplate');
|
|
|
|
* $gridField = new GridField('ExampleGrid', 'Example grid', new DataList('Page'),null, $presenter);
|
|
|
|
* </code>
|
|
|
|
*
|
|
|
|
* There is also a possibility to add extensions to the GridPresenter. An
|
|
|
|
* example is the DataGridPagination that decorates the GridField with
|
|
|
|
* pagination. Look in the GridFieldPresenter::Items() and the filterList extend
|
|
|
|
* and GridFieldPresenter::Footers()
|
|
|
|
*
|
|
|
|
* <code>
|
|
|
|
* GridFieldPresenter::add_extension('GridFieldPaginator_Extension');
|
|
|
|
* $presenter = new GridFieldPresenter();
|
|
|
|
* // This is actually calling GridFieldPaginator_Extension::paginationLimit()
|
|
|
|
* $presenter->paginationLimit(3);
|
|
|
|
* $gridField = new GridField('ExampleGrid', 'Example grid', new DataList('Page'),null, $presenter);
|
|
|
|
* </code>
|
|
|
|
*
|
2011-09-30 00:59:44 +02:00
|
|
|
* @see GridField
|
2011-10-27 05:11:26 +02:00
|
|
|
* @see GridFieldPaginator
|
2011-09-30 00:59:44 +02:00
|
|
|
* @package sapphire
|
2011-09-29 01:16:15 +02:00
|
|
|
*/
|
2011-09-30 00:59:44 +02:00
|
|
|
class GridFieldPresenter extends ViewableData {
|
2011-09-29 01:16:15 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Template override
|
|
|
|
*
|
|
|
|
* @var string $template
|
|
|
|
*/
|
2011-09-30 00:59:44 +02:00
|
|
|
protected $template = 'GridFieldPresenter';
|
2011-09-29 01:16:15 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Class name for each item/row
|
|
|
|
*
|
|
|
|
* @var string $itemClass
|
|
|
|
*/
|
2011-09-30 00:59:44 +02:00
|
|
|
protected $itemClass = 'GridFieldPresenter_Item';
|
2011-09-29 01:16:15 +02:00
|
|
|
|
|
|
|
/**
|
2011-09-30 00:59:44 +02:00
|
|
|
* @var GridField
|
2011-09-29 01:16:15 +02:00
|
|
|
*/
|
2011-09-30 00:59:44 +02:00
|
|
|
protected $GridField = null;
|
2011-09-29 01:16:15 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
public $fieldCasting = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
public $fieldFormatting = array();
|
|
|
|
|
|
|
|
/**
|
2011-09-30 00:59:44 +02:00
|
|
|
* List of columns and direction that the {@link GridFieldPresenter} is
|
|
|
|
* sorted in.
|
2011-09-29 01:16:15 +02:00
|
|
|
*
|
2011-09-30 00:59:44 +02:00
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $sorting = array();
|
|
|
|
|
|
|
|
/**
|
2011-09-29 01:16:15 +02:00
|
|
|
* @param string $template
|
|
|
|
*/
|
2011-10-27 05:11:26 +02:00
|
|
|
public function setTemplate($template){
|
2011-09-29 01:16:15 +02:00
|
|
|
$this->template = $template;
|
|
|
|
}
|
|
|
|
|
2011-10-27 05:11:26 +02:00
|
|
|
/**
|
|
|
|
* The name of the Field
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function Name() {
|
|
|
|
return $this->getGridField()->Name();
|
|
|
|
}
|
|
|
|
|
2011-09-29 01:16:15 +02:00
|
|
|
/**
|
2011-09-30 00:59:44 +02:00
|
|
|
* @param GridField $GridField
|
|
|
|
*/
|
|
|
|
public function setGridField(GridField $grid){
|
|
|
|
$this->GridField = $grid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return GridField
|
2011-09-29 01:16:15 +02:00
|
|
|
*/
|
2011-09-30 00:59:44 +02:00
|
|
|
public function getGridField(){
|
|
|
|
return $this->GridField;
|
2011-09-29 01:16:15 +02:00
|
|
|
}
|
|
|
|
|
2011-10-27 05:11:26 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param type $extension
|
|
|
|
*/
|
|
|
|
public static function add_extension($extension) {
|
|
|
|
parent::add_extension(__CLASS__, $extension);
|
|
|
|
}
|
|
|
|
|
2011-09-29 01:16:15 +02:00
|
|
|
/**
|
2011-09-30 00:59:44 +02:00
|
|
|
* Sort the grid by columns
|
2011-09-29 01:16:15 +02:00
|
|
|
*
|
2011-09-30 00:59:44 +02:00
|
|
|
* @param string $column
|
|
|
|
* @param string $direction
|
2011-09-29 01:16:15 +02:00
|
|
|
*/
|
2011-09-30 00:59:44 +02:00
|
|
|
public function sort($column, $direction = 'asc') {
|
|
|
|
$this->sorting[$column] = $direction;
|
|
|
|
|
|
|
|
return $this;
|
2011-09-29 01:16:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-09-30 00:59:44 +02:00
|
|
|
* Return an {@link ArrayList} of {@link GridField_Item} objects, suitable for display in the template.
|
2011-09-29 01:16:15 +02:00
|
|
|
*
|
|
|
|
* @return ArrayList
|
|
|
|
*/
|
2011-09-29 23:59:52 +02:00
|
|
|
public function Items() {
|
2011-10-27 05:11:26 +02:00
|
|
|
$items = new ArrayList();
|
2011-09-30 00:59:44 +02:00
|
|
|
|
|
|
|
if($this->sorting) {
|
2011-10-27 05:11:26 +02:00
|
|
|
$this->setSortingOnList($this->sorting);
|
2011-09-30 00:59:44 +02:00
|
|
|
}
|
2011-10-27 05:11:26 +02:00
|
|
|
//empty for now
|
|
|
|
$list = $this->getGridField()->getList();
|
|
|
|
|
|
|
|
$parameters = new stdClass();
|
|
|
|
$parameters->Controller = Controller::curr();
|
|
|
|
$parameters->Request = Controller::curr()->getRequest();
|
2011-09-30 00:59:44 +02:00
|
|
|
|
2011-10-27 05:11:26 +02:00
|
|
|
$this->extend('filterList', $list, $parameters);
|
|
|
|
|
|
|
|
if($list) {
|
|
|
|
$numberOfRows = $list->count();
|
2011-09-29 23:59:52 +02:00
|
|
|
$counter = 0;
|
2011-10-27 05:11:26 +02:00
|
|
|
foreach($list as $item) {
|
|
|
|
$itemPresenter = new $this->itemClass($item, $this);
|
|
|
|
$itemPresenter->iteratorProperties($counter++, $numberOfRows);
|
2011-09-30 00:59:44 +02:00
|
|
|
$items->push($itemPresenter);
|
2011-09-29 01:16:15 +02:00
|
|
|
}
|
|
|
|
}
|
2011-09-30 00:59:44 +02:00
|
|
|
return $items;
|
2011-09-29 01:16:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the headers or column names for this grid
|
|
|
|
*
|
|
|
|
* The returning array will have the format of
|
2011-09-30 00:59:44 +02:00
|
|
|
*
|
|
|
|
* <code>
|
|
|
|
* array(
|
|
|
|
* 'FirstName' => 'First name',
|
|
|
|
* 'Description' => 'A nice description'
|
|
|
|
* )
|
|
|
|
* </code>
|
2011-09-29 01:16:15 +02:00
|
|
|
*
|
|
|
|
* @return ArrayList
|
2011-09-29 02:47:56 +02:00
|
|
|
* @throws Exception
|
2011-09-29 01:16:15 +02:00
|
|
|
*/
|
|
|
|
public function Headers() {
|
2011-10-27 05:11:26 +02:00
|
|
|
if(!$this->getList()) {
|
2011-09-30 00:59:44 +02:00
|
|
|
throw new Exception(sprintf(
|
|
|
|
'%s needs an data source to be able to render the form', get_class($this->getGridField())
|
|
|
|
));
|
2011-09-29 01:16:15 +02:00
|
|
|
}
|
2011-10-27 05:11:26 +02:00
|
|
|
return $this->summaryFieldsToList($this->FieldList());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @return ArrayList
|
|
|
|
*/
|
|
|
|
public function Footers() {
|
|
|
|
$arrayList = new ArrayList();
|
|
|
|
$footers = $this->extend('Footer');
|
|
|
|
foreach($footers as $footer) {
|
|
|
|
$arrayList->push($footer);
|
|
|
|
}
|
|
|
|
return $arrayList;
|
2011-09-29 01:16:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-09-29 02:47:56 +02:00
|
|
|
* @return SS_List
|
2011-09-29 01:16:15 +02:00
|
|
|
*/
|
2011-10-27 05:11:26 +02:00
|
|
|
public function getList() {
|
|
|
|
return $this->getGridField()->getList();
|
2011-09-29 02:47:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string - name of model
|
|
|
|
*/
|
|
|
|
protected function getModelClass() {
|
2011-09-30 00:59:44 +02:00
|
|
|
return $this->getGridField()->getModelClass();
|
2011-09-29 02:47:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-09-30 00:59:44 +02:00
|
|
|
* Add the combined sorting on the datasource
|
|
|
|
*
|
2011-10-27 05:11:26 +02:00
|
|
|
* If the sorting isn't set in the datasource, only the latest sort
|
|
|
|
* will be executed.
|
2011-09-29 02:47:56 +02:00
|
|
|
*
|
2011-09-30 00:59:44 +02:00
|
|
|
* @param array $sortColumns
|
|
|
|
*/
|
2011-10-27 05:11:26 +02:00
|
|
|
protected function setSortingOnList(array $sortColumns) {
|
2011-09-30 00:59:44 +02:00
|
|
|
$resultColumns = array();
|
|
|
|
|
|
|
|
foreach($sortColumns as $column => $sortOrder) {
|
|
|
|
$resultColumns[] = sprintf("%s %s", $column ,$sortOrder);
|
|
|
|
}
|
|
|
|
|
|
|
|
$sort = implode(', ', $resultColumns);
|
2011-10-27 05:11:26 +02:00
|
|
|
$this->getList()->sort($sort);
|
2011-09-30 00:59:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-09-29 02:47:56 +02:00
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function FieldList() {
|
|
|
|
return singleton($this->getModelClass())->summaryFields();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Translate the summaryFields from a model into a format that is understood
|
|
|
|
* by the Form renderer
|
|
|
|
*
|
|
|
|
* @param array $summaryFields
|
2011-09-30 00:59:44 +02:00
|
|
|
*
|
2011-09-29 02:47:56 +02:00
|
|
|
* @return ArrayList
|
|
|
|
*/
|
|
|
|
protected function summaryFieldsToList($summaryFields) {
|
2011-09-30 00:59:44 +02:00
|
|
|
$headers = new ArrayList();
|
|
|
|
|
|
|
|
if(is_array($summaryFields)) {
|
2011-09-29 23:59:52 +02:00
|
|
|
$counter = 0;
|
2011-09-30 00:59:44 +02:00
|
|
|
|
|
|
|
foreach ($summaryFields as $name => $title) {
|
|
|
|
$data = array(
|
|
|
|
'Name' => $name,
|
|
|
|
'Title' => $title,
|
|
|
|
'IsSortable' => true,
|
|
|
|
'IsSorted' => false,
|
|
|
|
'SortedDirection' => 'asc'
|
2011-09-29 23:59:52 +02:00
|
|
|
);
|
2011-09-30 00:59:44 +02:00
|
|
|
|
|
|
|
if(array_key_exists($name, $this->sorting)) {
|
|
|
|
$data['IsSorted'] = true;
|
|
|
|
$data['SortedDirection'] = $this->sorting[$name];
|
|
|
|
}
|
|
|
|
|
|
|
|
$result = new ArrayData($data);
|
|
|
|
$result->iteratorProperties($counter++, count($summaryFields));
|
|
|
|
|
|
|
|
$headers->push($result);
|
2011-09-29 01:16:15 +02:00
|
|
|
}
|
|
|
|
}
|
2011-09-30 00:59:44 +02:00
|
|
|
|
|
|
|
return $headers;
|
2011-09-29 02:47:56 +02:00
|
|
|
}
|
2011-09-29 01:16:15 +02:00
|
|
|
|
|
|
|
/**
|
2011-09-30 00:59:44 +02:00
|
|
|
* @param array $casting
|
2011-09-29 01:16:15 +02:00
|
|
|
*/
|
|
|
|
function setFieldCasting($casting) {
|
|
|
|
$this->fieldCasting = $casting;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param type $formatting
|
|
|
|
*/
|
|
|
|
function setFieldFormatting($formatting) {
|
|
|
|
$this->fieldFormatting = $formatting;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string - html
|
|
|
|
*/
|
|
|
|
function render(){
|
|
|
|
return $this->renderWith(array($this->template));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-09-30 00:59:44 +02:00
|
|
|
* A single record in a GridField.
|
|
|
|
*
|
|
|
|
* @package sapphire
|
|
|
|
* @see GridField
|
2011-09-29 01:16:15 +02:00
|
|
|
*/
|
2011-09-30 00:59:44 +02:00
|
|
|
class GridFieldPresenter_Item extends ViewableData {
|
2011-09-29 01:16:15 +02:00
|
|
|
|
|
|
|
/**
|
2011-09-30 00:59:44 +02:00
|
|
|
* @var Object The underlying record, usually an element of
|
|
|
|
* {@link GridField->datasource()}.
|
2011-09-29 01:16:15 +02:00
|
|
|
*/
|
|
|
|
protected $item;
|
|
|
|
|
|
|
|
/**
|
2011-09-30 00:59:44 +02:00
|
|
|
* @var GridFieldPresenter
|
2011-09-29 01:16:15 +02:00
|
|
|
*/
|
|
|
|
protected $parent;
|
|
|
|
|
|
|
|
/**
|
2011-09-30 00:59:44 +02:00
|
|
|
* @param Object $item
|
|
|
|
* @param GridFieldPresenter $parent
|
2011-09-29 01:16:15 +02:00
|
|
|
*/
|
|
|
|
public function __construct($item, $parent) {
|
|
|
|
$this->failover = $this->item = $item;
|
|
|
|
$this->parent = $parent;
|
2011-09-30 00:59:44 +02:00
|
|
|
|
2011-09-29 01:16:15 +02:00
|
|
|
parent::__construct();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
public function ID() {
|
|
|
|
return $this->item->ID;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return type
|
|
|
|
*/
|
|
|
|
public function Parent() {
|
|
|
|
return $this->parent;
|
|
|
|
}
|
2011-09-29 23:59:52 +02:00
|
|
|
|
2011-09-29 01:16:15 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param bool $xmlSafe
|
2011-09-30 00:59:44 +02:00
|
|
|
*
|
2011-09-29 01:16:15 +02:00
|
|
|
* @return ArrayList
|
|
|
|
*/
|
|
|
|
public function Fields($xmlSafe = true) {
|
2011-09-29 02:47:56 +02:00
|
|
|
$list = $this->parent->FieldList();
|
2011-09-29 23:59:52 +02:00
|
|
|
$counter = 0;
|
2011-09-30 00:59:44 +02:00
|
|
|
|
2011-09-29 01:16:15 +02:00
|
|
|
foreach($list as $fieldName => $fieldTitle) {
|
|
|
|
$value = "";
|
|
|
|
|
|
|
|
// TODO Delegates that to DataList
|
|
|
|
// This supports simple FieldName syntax
|
|
|
|
if(strpos($fieldName,'.') === false) {
|
|
|
|
$value = ($this->item->XML_val($fieldName) && $xmlSafe) ? $this->item->XML_val($fieldName) : $this->item->RAW_val($fieldName);
|
2011-09-30 00:59:44 +02:00
|
|
|
|
2011-09-29 01:16:15 +02:00
|
|
|
// This support the syntax fieldName = Relation.RelatedField
|
|
|
|
} else {
|
|
|
|
$fieldNameParts = explode('.', $fieldName) ;
|
|
|
|
$tmpItem = $this->item;
|
2011-09-30 00:59:44 +02:00
|
|
|
|
2011-09-29 01:16:15 +02:00
|
|
|
for($j=0;$j<sizeof($fieldNameParts);$j++) {
|
|
|
|
$relationMethod = $fieldNameParts[$j];
|
|
|
|
$idField = $relationMethod . 'ID';
|
|
|
|
if($j == sizeof($fieldNameParts)-1) {
|
|
|
|
if($tmpItem) $value = $tmpItem->$relationMethod;
|
|
|
|
} else {
|
|
|
|
if($tmpItem) $tmpItem = $tmpItem->$relationMethod();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// casting
|
|
|
|
if(array_key_exists($fieldName, $this->parent->fieldCasting)) {
|
|
|
|
$value = $this->parent->getCastedValue($value, $this->parent->fieldCasting[$fieldName]);
|
|
|
|
} elseif(is_object($value) && method_exists($value, 'Nice')) {
|
|
|
|
$value = $value->Nice();
|
|
|
|
}
|
|
|
|
|
|
|
|
// formatting
|
|
|
|
$item = $this->item;
|
|
|
|
if(array_key_exists($fieldName, $this->parent->fieldFormatting)) {
|
|
|
|
$format = str_replace('$value', "__VAL__", $this->parent->fieldFormatting[$fieldName]);
|
|
|
|
$format = preg_replace('/\$([A-Za-z0-9-_]+)/','$item->$1', $format);
|
|
|
|
$format = str_replace('__VAL__', '$value', $format);
|
|
|
|
eval('$value = "' . $format . '";');
|
|
|
|
}
|
|
|
|
|
|
|
|
//escape
|
2011-09-30 00:59:44 +02:00
|
|
|
if($escape = $this->parent->getGridField()->fieldEscape){
|
2011-09-29 01:16:15 +02:00
|
|
|
foreach($escape as $search => $replace){
|
|
|
|
$value = str_replace($search, $replace, $value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 23:59:52 +02:00
|
|
|
$arrayData = new ArrayData(array(
|
2011-09-29 01:16:15 +02:00
|
|
|
"Name" => $fieldName,
|
|
|
|
"Title" => $fieldTitle,
|
|
|
|
"Value" => $value
|
|
|
|
));
|
2011-09-29 23:59:52 +02:00
|
|
|
$arrayData->iteratorProperties($counter++, count($list));
|
|
|
|
$fields[] = $arrayData;
|
2011-09-29 01:16:15 +02:00
|
|
|
}
|
2011-09-30 00:59:44 +02:00
|
|
|
|
2011-09-29 01:16:15 +02:00
|
|
|
return new ArrayList($fields);
|
|
|
|
}
|
|
|
|
}
|