Merge pull request #2595 from kinglozzer/gridfield-sort-relation

NEW: GridField can sort on relation columns
This commit is contained in:
Ingo Schommer 2013-11-22 11:14:12 -08:00
commit 053258b984
3 changed files with 228 additions and 2 deletions

View File

@ -87,6 +87,7 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
$state = $gridField->State->GridFieldSortableHeader;
$columns = $gridField->getColumns();
$currentColumn = 0;
$list = $gridField->getList();
foreach($columns as $columnField) {
$currentColumn++;
@ -96,7 +97,31 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
if(isset($this->fieldSorting[$columnField]) && $this->fieldSorting[$columnField]) {
$columnField = $this->fieldSorting[$columnField];
}
if($title && $gridField->getList()->canSortBy($columnField)) {
$allowSort = ($title && $list->canSortBy($columnField));
if(strpos($columnField, '.') !== false) {
// we have a relation column with dot notation
$parts = explode('.', $columnField);
$tmpItem = singleton($list->dataClass());
for($idx = 0; $idx < sizeof($parts); $idx++) {
$methodName = $parts[$idx];
if($tmpItem instanceof DataObject && $tmpItem->hasField($methodName)) {
// If we've found a field, we can sort on it
$allowSort = true;
} else if ($tmpItem instanceof SS_List) {
// It's impossible to sort on a HasManyList/ManyManyList
throw new Exception(__CLASS__ . ' is unable to sort on has_many/many_many relations,'
. ' please only specify has_one relations');
} else {
// Else, the part is a relation name, so get the object/list from it
$tmpItem = $tmpItem->$methodName();
}
}
}
if($allowSort) {
$dir = 'asc';
if($state->SortColumn == $columnField && $state->SortDirection == 'asc') {
$dir = 'desc';
@ -161,6 +186,14 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
}
}
/**
* Returns the manipulated (sorted) DataList. Field names will simply add an 'ORDER BY'
* clause, relation names will add appropriate joins to the DataQuery first.
*
* @param GridField
* @param SS_List
* @return SS_List
*/
public function getManipulatedData(GridField $gridField, SS_List $dataList) {
if(!$this->checkDataType($dataList)) return $dataList;
@ -168,6 +201,45 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
if ($state->SortColumn == "") {
return $dataList;
}
return $dataList->sort($state->SortColumn, $state->SortDirection);
$column = $state->SortColumn;
// if we have a relation column with dot notation
if(strpos($column, '.') !== false) {
$lastAlias = $dataList->dataClass();
$tmpItem = singleton($lastAlias);
$parts = explode('.', $state->SortColumn);
for($idx = 0; $idx < sizeof($parts); $idx++) {
$methodName = $parts[$idx];
// If we're not on the last item, we're looking at a relation
if($idx !== sizeof($parts) - 1) {
// Traverse to the relational list
$tmpItem = $tmpItem->$methodName();
// Add a left join to the query
$dataList = $dataList->leftJoin(
$tmpItem->class,
'"' . $methodName . '"."ID" = "' . $lastAlias . '"."' . $methodName . 'ID"',
$methodName
);
// Store the last 'alias' name as it'll be used for the next
// join, or the 'sort' column
$lastAlias = $methodName;
} else {
// Change relation.relation.fieldname to alias.fieldname
$column = $lastAlias . '.' . $methodName;
}
}
}
// We need to manually create our ORDER BY "Foo"."Bar" string for relations,
// as ->sort() won't do it by itself. Blame PostgreSQL for making this necessary
$pieces = explode('.', $column);
$column = '"' . implode('"."', $pieces) . '"';
return $dataList->sort($column, $state->SortDirection);
}
}

View File

@ -0,0 +1,115 @@
<?php
/**
* @package framework
* @subpackage tests
*/
class GridFieldSortableHeaderTest extends SapphireTest {
protected static $fixture_file = 'GridFieldSortableHeaderTest.yml';
protected $extraDataObjects = array(
'GridFieldSortableHeaderTest_Team',
'GridFieldSortableHeaderTest_Cheerleader',
'GridFieldSortableHeaderTest_CheerleaderHat'
);
public function testGetManipulatedData() {
$list = new DataList('GridFieldSortableHeaderTest_Team');
$config = new GridFieldConfig_RecordEditor();
$gridField = new GridField('testfield', 'testfield', $list, $config);
// Test normal sorting
$state = $gridField->State->GridFieldSortableHeader;
$state->SortColumn = 'City';
$state->SortDirection = 'asc';
$compontent = $gridField->getConfig()->getComponentByType('GridFieldSortableHeader');
$listA = $compontent->getManipulatedData($gridField, $list);
$state->SortDirection = 'desc';
$listB = $compontent->getManipulatedData($gridField, $list);
$this->assertEquals(
array('Auckland', 'Cologne', 'Melbourne', 'Wellington'),
$listA->column('City')
);
$this->assertEquals(
array('Wellington', 'Melbourne', 'Cologne', 'Auckland'),
$listB->column('City')
);
// Test one relation 'deep'
$state->SortColumn = 'Cheerleader.Name';
$state->SortDirection = 'asc';
$relationListA = $compontent->getManipulatedData($gridField, $list);
$state->SortDirection = 'desc';
$relationListB = $compontent->getManipulatedData($gridField, $list);
$this->assertEquals(
array('Wellington', 'Melbourne', 'Cologne', 'Auckland'),
$relationListA->column('City')
);
$this->assertEquals(
array('Auckland', 'Cologne', 'Melbourne', 'Wellington'),
$relationListB->column('City')
);
// Test two relations 'deep'
$state->SortColumn = 'Cheerleader.Hat.Colour';
$state->SortDirection = 'asc';
$relationListC = $compontent->getManipulatedData($gridField, $list);
$state->SortDirection = 'desc';
$relationListD = $compontent->getManipulatedData($gridField, $list);
$this->assertEquals(
array('Cologne', 'Auckland', 'Wellington', 'Melbourne'),
$relationListC->column('City')
);
$this->assertEquals(
array('Melbourne', 'Wellington', 'Auckland', 'Cologne'),
$relationListD->column('City')
);
}
}
class GridFieldSortableHeaderTest_Team extends DataObject implements TestOnly {
private static $db = array(
'Name' => 'Varchar',
'City' => 'Varchar'
);
private static $has_one = array(
'Cheerleader' => 'GridFieldSortableHeaderTest_Cheerleader'
);
}
class GridFieldSortableHeaderTest_Cheerleader extends DataObject implements TestOnly {
private static $db = array(
'Name' => 'Varchar'
);
private static $has_one = array(
'Team' => 'GridFieldSortableHeaderTest_Team',
'Hat' => 'GridFieldSortableHeaderTest_CheerleaderHat'
);
}
class GridFieldSortableHeaderTest_CheerleaderHat extends DataObject implements TestOnly {
private static $db = array(
'Colour' => 'Varchar'
);
private static $has_one = array(
'Cheerleader' => 'GridFieldSortableHeaderTest_Cheerleader'
);
}

View File

@ -0,0 +1,39 @@
GridFieldSortableHeaderTest_CheerleaderHat:
hat1:
Colour: Blue
hat2:
Colour: Red
hat3:
Colour: Green
hat4:
Colour: Pink
GridFieldSortableHeaderTest_Cheerleader:
cheerleader1:
Name: Heather
Hat: =>GridFieldSortableHeaderTest_CheerleaderHat.hat2
cheerleader2:
Name: Bob
Hat: =>GridFieldSortableHeaderTest_CheerleaderHat.hat4
cheerleader3:
Name: Jenny
Hat: =>GridFieldSortableHeaderTest_CheerleaderHat.hat1
cheerleader4:
Name: Sam
Hat: =>GridFieldSortableHeaderTest_CheerleaderHat.hat3
GridFieldSortableHeaderTest_Team:
team1:
Name: Team 1
City: Cologne
Cheerleader: =>GridFieldSortableHeaderTest_Cheerleader.cheerleader3
team2:
Name: Team 2
City: Wellington
Cheerleader: =>GridFieldSortableHeaderTest_Cheerleader.cheerleader2
team3:
Name: Team 3
City: Auckland
Cheerleader: =>GridFieldSortableHeaderTest_Cheerleader.cheerleader4
team4:
Name: Team 4
City: Melbourne
Cheerleader: =>GridFieldSortableHeaderTest_Cheerleader.cheerleader1