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.
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
Since GridField is mostly used in the CMS, the controller managing a GridField instance

View File

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

View File

@ -93,20 +93,13 @@ class GridFieldAddExistingAutocompleter
* @return string - HTML
*/
public function getHTMLFragments($gridField) {
$searchState = $gridField->State->GridFieldSearchRelation;
$dataClass = $gridField->getList()->dataClass();
$forTemplate = new ArrayData(array());
$forTemplate->Fields = new ArrayList();
$searchFields = ($this->getSearchFields())
? $this->getSearchFields()
: $this->scaffoldSearchFields($dataClass);
$searchField = new TextField('gridfield_relationsearch', _t('GridField.RelationSearch', "Relation search"));
$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('placeholder', $this->getPlaceholderText($dataClass));
$searchField->addExtraClass('relation-search no-change-track');
@ -120,7 +113,7 @@ class GridFieldAddExistingAutocompleter
$addAction->setAttribute('data-icon', 'chain--plus');
// 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);
}
@ -139,17 +132,16 @@ class GridFieldAddExistingAutocompleter
* @return array
*/
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 string $actionName
* @param string $arguments
* @param string $data
* @return string
* @param string $actionName Action identifier, see {@link getActions()}.
* @param array $arguments Arguments relevant for this
* @param array $data All form data
*/
public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
switch($actionName) {
@ -157,10 +149,6 @@ class GridFieldAddExistingAutocompleter
if(isset($data['relationID']) && $data['relationID']){
$gridField->State->GridFieldAddRelation = $data['relationID'];
}
$gridField->State->GridFieldSearchRelation = '';
break;
case 'find' && isset($data['autosuggest_search']):
$gridField->State->GridFieldSearchRelation = $data['autosuggest_search'];
break;
}
}
@ -173,15 +161,13 @@ class GridFieldAddExistingAutocompleter
* @return SS_List
*/
public function getManipulatedData(GridField $gridField, SS_List $dataList) {
if(!$gridField->State->GridFieldAddRelation) {
$objectID = $gridField->State->GridFieldAddRelation(null);
if(empty($objectID)) {
return $dataList;
}
$objectID = Convert::raw2sql($gridField->State->GridFieldAddRelation);
if($objectID) {
$object = DataObject::get_by_id($dataList->dataclass(), $objectID);
if($object) {
$dataList->add($object);
}
$object = DataObject::get_by_id($dataList->dataclass(), $objectID);
if($object) {
$dataList->add($object);
}
$gridField->State->GridFieldAddRelation = null;
return $dataList;
@ -375,33 +361,4 @@ class GridFieldAddExistingAutocompleter
public function setResultsLimit($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) {
if(!$this->checkDataType($dataList)) return $dataList;
$state = $gridField->State->GridFieldFilterHeader;
if(!isset($state->Columns)) {
$columns = $gridField->State->GridFieldFilterHeader->Columns(null);
if(empty($columns)) {
return $dataList;
}
}
$filterArguments = $state->Columns->toArray();
$filterArguments = $columns->toArray();
$dataListClone = clone($dataList);
foreach($filterArguments as $columnName => $value ) {
if($dataList->canFilterBy($columnName) && $value) {

View File

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

View File

@ -98,7 +98,7 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
}
if($title && $gridField->getList()->canSortBy($columnField)) {
$dir = 'asc';
if($state->SortColumn == $columnField && $state->SortDirection == 'asc') {
if($state->SortColumn(null) == $columnField && $state->SortDirection('asc') == 'asc') {
$dir = 'desc';
}
@ -107,10 +107,10 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
"sort$dir", array('SortColumn' => $columnField)
)->addExtraClass('ss-gridfield-sort');
if($state->SortColumn == $columnField){
if($state->SortColumn(null) == $columnField){
$field->addExtraClass('ss-gridfield-sorted');
if($state->SortDirection == 'asc')
if($state->SortDirection('asc') == 'asc')
$field->addExtraClass('ss-gridfield-sorted-asc');
else
$field->addExtraClass('ss-gridfield-sorted-desc');
@ -165,9 +165,10 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
if(!$this->checkDataType($dataList)) return $dataList;
$state = $gridField->State->GridFieldSortableHeader;
if ($state->SortColumn == "") {
$sortColumn = $state->SortColumn();
if (empty($sortcolumn)) {
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() {
if(!$this->data) {
@ -136,8 +136,25 @@ class GridState_Data {
}
public function __get($name) {
if(!isset($this->data[$name])) {
$this->data[$name] = new GridState_Data();
return $this->getData($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])) {
$this->data[$name] = new GridState_Data($this->data[$name]);
}

View File

@ -106,6 +106,30 @@ class GridFieldTest extends SapphireTest {
$this->assertTrue($obj->getState() instanceof GridState_Data);
$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