Merge pull request #2522 from tractorcow/pulls/3.2-gridstate-api-fix

API GridState_Data values can have default values specified during retrieval.
This commit is contained in:
Ingo Schommer 2013-10-24 04:26:16 -07:00
commit 723c4e3f4e
8 changed files with 85 additions and 68 deletions

View File

@ -345,6 +345,23 @@ transfered between page requests by being inserted as a hidden field in the form
A GridFieldComponent sets and gets data from the GridState. A GridFieldComponent sets and gets data from the GridState.
Data within this object can be nested, allowing for organisation of information in a logical fashion. Additionally,
default values can be specified for any data field by invoking that field as a method, passing the default value
as the first parameter. If no default is specified then a nested `GridState_Data` is returned, which may be chained
to subsequently nest data values.
Example:
:::php
public function getManipulatedData(GridField $gridField, SS_List $dataList) {
// Accesses the GridState, returns a nested GridState_Data, and retrieve a single field with a default of null
$objectID = $gridField->State->MyComponent->RecordID(null);
if($objectID) $dataList = $dataList->filter('ParentID', $objectID);
return $dataList;
}
## Permissions ## Permissions
Since GridField is mostly used in the CMS, the controller managing a GridField instance Since GridField is mostly used in the CMS, the controller managing a GridField instance

View File

@ -17,6 +17,7 @@
* *
* @package framework * @package framework
* @subpackage fields-gridfield * @subpackage fields-gridfield
* @property GridState_Data $State The gridstate of this object
*/ */
class GridField extends FormField { class GridField extends FormField {

View File

@ -93,20 +93,13 @@ class GridFieldAddExistingAutocompleter
* @return string - HTML * @return string - HTML
*/ */
public function getHTMLFragments($gridField) { public function getHTMLFragments($gridField) {
$searchState = $gridField->State->GridFieldSearchRelation;
$dataClass = $gridField->getList()->dataClass(); $dataClass = $gridField->getList()->dataClass();
$forTemplate = new ArrayData(array()); $forTemplate = new ArrayData(array());
$forTemplate->Fields = new ArrayList(); $forTemplate->Fields = new ArrayList();
$searchFields = ($this->getSearchFields()) $searchField = new TextField('gridfield_relationsearch', _t('GridField.RelationSearch', "Relation search"));
? $this->getSearchFields()
: $this->scaffoldSearchFields($dataClass);
$value = $this->findSingleEntry($gridField, $searchFields, $searchState, $dataClass);
$searchField = new TextField('gridfield_relationsearch',
_t('GridField.RelationSearch', "Relation search"), $value);
$searchField->setAttribute('data-search-url', Controller::join_links($gridField->Link('search'))); $searchField->setAttribute('data-search-url', Controller::join_links($gridField->Link('search')));
$searchField->setAttribute('placeholder', $this->getPlaceholderText($dataClass)); $searchField->setAttribute('placeholder', $this->getPlaceholderText($dataClass));
$searchField->addExtraClass('relation-search no-change-track'); $searchField->addExtraClass('relation-search no-change-track');
@ -120,7 +113,7 @@ class GridFieldAddExistingAutocompleter
$addAction->setAttribute('data-icon', 'chain--plus'); $addAction->setAttribute('data-icon', 'chain--plus');
// If an object is not found, disable the action // If an object is not found, disable the action
if(!is_int($gridField->State->GridFieldAddRelation)) { if(!is_int($gridField->State->GridFieldAddRelation(null))) {
$addAction->setReadonly(true); $addAction->setReadonly(true);
} }
@ -139,17 +132,16 @@ class GridFieldAddExistingAutocompleter
* @return array * @return array
*/ */
public function getActions($gridField) { public function getActions($gridField) {
return array('addto', 'find'); return array('addto');
} }
/** /**
* Manipulate the state to either add a new relation, or doing a small search * Manipulate the state to add a new relation
* *
* @param GridField $gridField * @param GridField $gridField
* @param string $actionName * @param string $actionName Action identifier, see {@link getActions()}.
* @param string $arguments * @param array $arguments Arguments relevant for this
* @param string $data * @param array $data All form data
* @return string
*/ */
public function handleAction(GridField $gridField, $actionName, $arguments, $data) { public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
switch($actionName) { switch($actionName) {
@ -157,10 +149,6 @@ class GridFieldAddExistingAutocompleter
if(isset($data['relationID']) && $data['relationID']){ if(isset($data['relationID']) && $data['relationID']){
$gridField->State->GridFieldAddRelation = $data['relationID']; $gridField->State->GridFieldAddRelation = $data['relationID'];
} }
$gridField->State->GridFieldSearchRelation = '';
break;
case 'find' && isset($data['autosuggest_search']):
$gridField->State->GridFieldSearchRelation = $data['autosuggest_search'];
break; break;
} }
} }
@ -173,15 +161,13 @@ class GridFieldAddExistingAutocompleter
* @return SS_List * @return SS_List
*/ */
public function getManipulatedData(GridField $gridField, SS_List $dataList) { public function getManipulatedData(GridField $gridField, SS_List $dataList) {
if(!$gridField->State->GridFieldAddRelation) { $objectID = $gridField->State->GridFieldAddRelation(null);
if(empty($objectID)) {
return $dataList; return $dataList;
} }
$objectID = Convert::raw2sql($gridField->State->GridFieldAddRelation); $object = DataObject::get_by_id($dataList->dataclass(), $objectID);
if($objectID) { if($object) {
$object = DataObject::get_by_id($dataList->dataclass(), $objectID); $dataList->add($object);
if($object) {
$dataList->add($object);
}
} }
$gridField->State->GridFieldAddRelation = null; $gridField->State->GridFieldAddRelation = null;
return $dataList; return $dataList;
@ -375,33 +361,4 @@ class GridFieldAddExistingAutocompleter
public function setResultsLimit($limit) { public function setResultsLimit($limit) {
$this->resultsLimit = $limit; $this->resultsLimit = $limit;
} }
/**
* This will provide a StartsWith search that only returns a value if we are
* matching ONE object only. We wouldn't want to attach used any object to
* the list.
*
* @param GridField $gridField
* @param string $field
* @param string $searchTerm
* @param string $dataclass
* @return string
*/
protected function findSingleEntry($gridField, $field, $searchTerm, $dataclass) {
$fullList = DataList::create($dataclass);
$searchTerm = Convert::raw2sql($searchTerm);
if(!$searchTerm) {
return;
}
$existingList = clone $gridField->getList();
$searchResults = $fullList->subtract($existingList->limit(0))->filter($field.':StartsWith', $searchTerm);
// If more than one, skip
if($searchResults->count() != 1) {
return '';
}
$gridField->State->GridFieldAddRelation = $searchResults->first()->ID;
return $searchResults->first()->$field;
}
} }

View File

@ -87,12 +87,12 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan
public function getManipulatedData(GridField $gridField, SS_List $dataList) { public function getManipulatedData(GridField $gridField, SS_List $dataList) {
if(!$this->checkDataType($dataList)) return $dataList; if(!$this->checkDataType($dataList)) return $dataList;
$state = $gridField->State->GridFieldFilterHeader; $columns = $gridField->State->GridFieldFilterHeader->Columns(null);
if(!isset($state->Columns)) { if(empty($columns)) {
return $dataList; return $dataList;
} }
$filterArguments = $state->Columns->toArray(); $filterArguments = $columns->toArray();
$dataListClone = clone($dataList); $dataListClone = clone($dataList);
foreach($filterArguments as $columnName => $value ) { foreach($filterArguments as $columnName => $value ) {
if($dataList->canFilterBy($columnName) && $value) { if($dataList->canFilterBy($columnName) && $value) {

View File

@ -110,7 +110,7 @@ class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipu
$state = $gridField->State->GridFieldPaginator; $state = $gridField->State->GridFieldPaginator;
// Force the state to the initial page if none is set // Force the state to the initial page if none is set
if(empty($state->currentPage)) $state->currentPage = 1; $state->currentPage(1);
return $state; return $state;
} }

View File

@ -98,7 +98,7 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
} }
if($title && $gridField->getList()->canSortBy($columnField)) { if($title && $gridField->getList()->canSortBy($columnField)) {
$dir = 'asc'; $dir = 'asc';
if($state->SortColumn == $columnField && $state->SortDirection == 'asc') { if($state->SortColumn(null) == $columnField && $state->SortDirection('asc') == 'asc') {
$dir = 'desc'; $dir = 'desc';
} }
@ -107,10 +107,10 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
"sort$dir", array('SortColumn' => $columnField) "sort$dir", array('SortColumn' => $columnField)
)->addExtraClass('ss-gridfield-sort'); )->addExtraClass('ss-gridfield-sort');
if($state->SortColumn == $columnField){ if($state->SortColumn(null) == $columnField){
$field->addExtraClass('ss-gridfield-sorted'); $field->addExtraClass('ss-gridfield-sorted');
if($state->SortDirection == 'asc') if($state->SortDirection('asc') == 'asc')
$field->addExtraClass('ss-gridfield-sorted-asc'); $field->addExtraClass('ss-gridfield-sorted-asc');
else else
$field->addExtraClass('ss-gridfield-sorted-desc'); $field->addExtraClass('ss-gridfield-sorted-desc');
@ -165,9 +165,10 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
if(!$this->checkDataType($dataList)) return $dataList; if(!$this->checkDataType($dataList)) return $dataList;
$state = $gridField->State->GridFieldSortableHeader; $state = $gridField->State->GridFieldSortableHeader;
if ($state->SortColumn == "") { $sortColumn = $state->SortColumn();
if (empty($sortcolumn)) {
return $dataList; return $dataList;
} }
return $dataList->sort($state->SortColumn, $state->SortDirection); return $dataList->sort($sortColumn, $state->SortDirection('asc'));
} }
} }

View File

@ -59,7 +59,7 @@ class GridState extends HiddenField {
} }
/** /**
* @var GridState_Data * @return GridState_Data
*/ */
public function getData() { public function getData() {
if(!$this->data) { if(!$this->data) {
@ -136,8 +136,25 @@ class GridState_Data {
} }
public function __get($name) { public function __get($name) {
if(!isset($this->data[$name])) { return $this->getData($name, new GridState_Data());
$this->data[$name] = new GridState_Data(); }
public function __call($name, $arguments) {
// Assume first parameter is default value
$default = empty($arguments) ? new GridState_Data() : $arguments[0];
return $this->getData($name, $default);
}
/**
* Retrieve the value for the given key
*
* @param string $name The name of the value to retrieve
* @param mixed $default Default value to assign if not set
* @return mixed The value associated with this key, or the value specified by $default if not set
*/
public function getData($name, $default = null) {
if(empty($this->data[$name])) {
$this->data[$name] = $default;
} else if(is_array($this->data[$name])) { } else if(is_array($this->data[$name])) {
$this->data[$name] = new GridState_Data($this->data[$name]); $this->data[$name] = new GridState_Data($this->data[$name]);
} }

View File

@ -107,6 +107,30 @@ class GridFieldTest extends SapphireTest {
$this->assertTrue($obj->getState(false) instanceof GridState); $this->assertTrue($obj->getState(false) instanceof GridState);
} }
/**
* Tests usage of nested GridState values
*
* @covers GridState_Data::__get
* @covers GridState_Data::__call
* @covers GridState_Data::getData
*/
public function testGetStateData() {
$obj = new GridField('testfield', 'testfield');
// Check value persistance
$this->assertEquals(15, $obj->State->NoValue(15));
$this->assertEquals(15, $obj->State->NoValue(-1));
$obj->State->NoValue = 10;
$this->assertEquals(10, $obj->State->NoValue);
$this->assertEquals(10, $obj->State->NoValue(20));
// Check nested values
$this->assertInstanceOf('GridState_Data', $obj->State->Nested);
$this->assertInstanceOf('GridState_Data', $obj->State->Nested->DeeperNested());
$this->assertEquals(3, $obj->State->Nested->DataValue(3));
$this->assertEquals(10, $obj->State->Nested->DeeperNested->DataValue(10));
}
/** /**
* @covers GridField::getColumns * @covers GridField::getColumns
*/ */