mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
added filterByCallback() to interface SS_Filterable and all implementing classes
This commit is contained in:
parent
ba1e688729
commit
d9b74874fc
@ -210,6 +210,25 @@ You can also combine both conjunctive ("AND") and disjunctive ("OR") statements.
|
||||
'Age' => 17,
|
||||
));
|
||||
// WHERE ("LastName" = 'Minnée' AND ("FirstName" = 'Sam' OR "Age" = '17'))
|
||||
|
||||
### Filter with PHP / filterByCallback
|
||||
|
||||
It is also possible to filter by a PHP callback, however this will force the
|
||||
data model to fetch all records and loop them in PHP, thus `filter()` or `filterAny()`
|
||||
are to be preferred over `filterByCallback()`.
|
||||
Please note that because `filterByCallback()` has to run in PHP, it will always return
|
||||
an `ArrayList` (even if called on a `DataList`, this however might change in future).
|
||||
The first parameter to the callback is the item, the second parameter is the list itself.
|
||||
The callback will run once for each record, if the callback returns true, this record
|
||||
will be added to the list of returned items.
|
||||
The below example will get all Members that have an expired or not encrypted password.
|
||||
|
||||
:::php
|
||||
$membersWithBadPassword = Member::get()->filterByCallback(function($item, $list) {
|
||||
if ($item->isPasswordExpired() || $item->PasswordEncryption = 'none') {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
### Exclude
|
||||
|
||||
|
@ -476,6 +476,27 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta
|
||||
return $firstElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SS_Filterable::filterByCallback()
|
||||
*
|
||||
* @example $list = $list->filterByCallback(function($item, $list) { return $item->Age == 9; })
|
||||
* @param callable $callback
|
||||
* @return ArrayList
|
||||
*/
|
||||
public function filterByCallback($callback) {
|
||||
if(!is_callable($callback)) {
|
||||
throw new LogicException(sprintf(
|
||||
"SS_Filterable::filterByCallback() passed callback must be callable, '%s' given",
|
||||
gettype($callback)
|
||||
));
|
||||
}
|
||||
$output = ArrayList::create();
|
||||
foreach($this as $item) {
|
||||
if(call_user_func($callback, $item, $this)) $output->push($item);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude the list to not contain items with these charactaristics
|
||||
*
|
||||
|
@ -39,7 +39,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
|
||||
/**
|
||||
* The DataModel from which this DataList comes.
|
||||
*
|
||||
*
|
||||
* @var DataModel
|
||||
*/
|
||||
protected $model;
|
||||
@ -406,21 +406,24 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter this DataList by a callback function.
|
||||
* The function will be passed each record of the DataList in turn, and must return true for the record to be
|
||||
* included. Returns the filtered list.
|
||||
*
|
||||
* Note that, in the current implementation, the filtered list will be an ArrayList, but this may change in a
|
||||
* future implementation.
|
||||
* @see SS_Filterable::filterByCallback()
|
||||
*
|
||||
* @example $list = $list->filterByCallback(function($item, $list) { return $item->Age == 9; })
|
||||
* @param callable $callback
|
||||
* @return ArrayList (this may change in future implementations)
|
||||
*/
|
||||
public function filterByCallback($callback) {
|
||||
if(!is_callable($callback)) {
|
||||
throw new LogicException("DataList::filterByCallback() must be passed something callable.");
|
||||
throw new LogicException(sprintf(
|
||||
"SS_Filterable::filterByCallback() passed callback must be callable, '%s' given",
|
||||
gettype($callback)
|
||||
));
|
||||
}
|
||||
|
||||
$output = new ArrayList;
|
||||
$output = ArrayList::create();
|
||||
foreach($this as $item) {
|
||||
if($callback($item)) $output->push($item);
|
||||
if(call_user_func($callback, $item, $this)) $output->push($item);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ interface SS_Filterable {
|
||||
* // aziz with the age 21 or 43 and bob with the Age 21 or 43
|
||||
*/
|
||||
public function filter();
|
||||
|
||||
|
||||
/**
|
||||
* Return a new instance of this list that excludes any items with these charactaristics
|
||||
*
|
||||
@ -43,5 +43,14 @@ interface SS_Filterable {
|
||||
* // bob age 21 or 43, phil age 21 or 43 would be excluded
|
||||
*/
|
||||
public function exclude();
|
||||
|
||||
|
||||
/**
|
||||
* Return a new instance of this list that excludes any items with these charactaristics
|
||||
* Filter this List by a callback function. The function will be passed each record of the List in turn,
|
||||
* and must return true for the record to be included. Returns the filtered list.
|
||||
*
|
||||
* @example $list = $list->filterByCallback(function($item, $list) { return $item->Age == 9; })
|
||||
* @return SS_Filterable
|
||||
*/
|
||||
public function filterByCallback($callback);
|
||||
}
|
||||
|
@ -147,6 +147,29 @@ abstract class SS_ListDecorator extends ViewableData implements SS_List, SS_Sort
|
||||
return call_user_func_array(array($this->list, 'filter'), $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that, in the current implementation, the filtered list will be an ArrayList, but this may change in a
|
||||
* future implementation.
|
||||
* @see SS_Filterable::filterByCallback()
|
||||
*
|
||||
* @example $list = $list->filterByCallback(function($item, $list) { return $item->Age == 9; })
|
||||
* @param callable $callback
|
||||
* @return ArrayList (this may change in future implementations)
|
||||
*/
|
||||
public function filterByCallback($callback) {
|
||||
if(!is_callable($callback)) {
|
||||
throw new LogicException(sprintf(
|
||||
"SS_Filterable::filterByCallback() passed callback must be callable, '%s' given",
|
||||
gettype($callback)
|
||||
));
|
||||
}
|
||||
$output = ArrayList::create();
|
||||
foreach($this->list as $item) {
|
||||
if(call_user_func($callback, $item, $this->list)) $output->push($item);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function limit($limit, $offset = 0) {
|
||||
return $this->list->limit($limit, $offset);
|
||||
}
|
||||
|
@ -438,6 +438,32 @@ class ArrayListTest extends SapphireTest {
|
||||
$this->assertEquals(3, $list->count());
|
||||
$this->assertEquals($expected, $list->toArray(), 'List should only contain Steve and Steve and Clair');
|
||||
}
|
||||
|
||||
/**
|
||||
* $list = $list->filterByCallback(function($item, $list) { return $item->Age == 21; })
|
||||
*/
|
||||
public function testFilterByCallback() {
|
||||
$list = new ArrayList(array(
|
||||
array('Name' => 'Steve', 'ID' => 1, 'Age' => 21),
|
||||
array('Name' => 'Bob', 'ID' => 2, 'Age' => 18),
|
||||
array('Name' => 'Clair', 'ID' => 2, 'Age' => 21),
|
||||
array('Name' => 'Oscar', 'ID' => 2, 'Age' => 52),
|
||||
array('Name' => 'Mike', 'ID' => 3, 'Age' => 43)
|
||||
));
|
||||
|
||||
$list = $list->filterByCallback(function ($item, $list) {
|
||||
return $item->Age == 21;
|
||||
});
|
||||
|
||||
$expected = array(
|
||||
new ArrayData(array('Name' => 'Steve', 'ID' => 1, 'Age' => 21)),
|
||||
new ArrayData(array('Name' => 'Clair', 'ID' => 2, 'Age' => 21)),
|
||||
);
|
||||
|
||||
$this->assertEquals(2, $list->count());
|
||||
$this->assertEquals($expected, $list->toArray(), 'List should only contain Steve and Clair');
|
||||
$this->assertTrue($list instanceof SS_Filterable, 'The List should be of type SS_Filterable');
|
||||
}
|
||||
|
||||
/**
|
||||
* $list->exclude('Name', 'bob'); // exclude bob from list
|
||||
|
@ -671,6 +671,24 @@ class DataListTest extends SapphireTest {
|
||||
$this->assertEquals(0, $list->exclude('ID', $obj->ID)->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* $list = $list->filterByCallback(function($item, $list) { return $item->Age == 21; })
|
||||
*/
|
||||
public function testFilterByCallback() {
|
||||
$team1ID = $this->idFromFixture('DataObjectTest_Team', 'team1');
|
||||
$list = DataObjectTest_TeamComment::get();
|
||||
$list = $list->filterByCallback(function ($item, $list) use ($team1ID) {
|
||||
return $item->TeamID == $team1ID;
|
||||
});
|
||||
|
||||
$result = $list->column('Name');
|
||||
$expected = array_intersect($result, array('Joe', 'Bob'));
|
||||
|
||||
$this->assertEquals(2, $list->count());
|
||||
$this->assertEquals($expected, $result, 'List should only contain comments from Team 1 (Joe and Bob)');
|
||||
$this->assertTrue($list instanceof SS_Filterable, 'The List should be of type SS_Filterable');
|
||||
}
|
||||
|
||||
/**
|
||||
* $list->exclude('Name', 'bob'); // exclude bob from list
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user