mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #2595 from kinglozzer/gridfield-sort-relation
NEW: GridField can sort on relation columns
This commit is contained in:
commit
053258b984
@ -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);
|
||||
}
|
||||
}
|
||||
|
115
tests/forms/gridfield/GridFieldSortableHeaderTest.php
Normal file
115
tests/forms/gridfield/GridFieldSortableHeaderTest.php
Normal 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'
|
||||
);
|
||||
|
||||
}
|
39
tests/forms/gridfield/GridFieldSortableHeaderTest.yml
Normal file
39
tests/forms/gridfield/GridFieldSortableHeaderTest.yml
Normal 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
|
Loading…
Reference in New Issue
Block a user