mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #3828 from dhensby/pulls/byids-arraylist
API `byIDs` added to `ArrayList`
This commit is contained in:
commit
da8f4a7eb6
@ -56,7 +56,7 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function exists() {
|
public function exists() {
|
||||||
return (bool) count($this);
|
return !empty($this->items);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -484,6 +484,79 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta
|
|||||||
* // aziz with the age 21 or 43 and bob with the Age 21 or 43
|
* // aziz with the age 21 or 43 and bob with the Age 21 or 43
|
||||||
*/
|
*/
|
||||||
public function filter() {
|
public function filter() {
|
||||||
|
|
||||||
|
$keepUs = call_user_func_array(array($this, 'normaliseFilterArgs'), func_get_args());
|
||||||
|
|
||||||
|
$itemsToKeep = array();
|
||||||
|
foreach($this->items as $item){
|
||||||
|
$keepItem = true;
|
||||||
|
foreach ($keepUs as $column => $value) {
|
||||||
|
if ((is_array($value) && !in_array($this->extractValue($item, $column), $value))
|
||||||
|
|| (!is_array($value) && $this->extractValue($item, $column) != $value)
|
||||||
|
) {
|
||||||
|
$keepItem = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($keepItem) {
|
||||||
|
$itemsToKeep[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = clone $this;
|
||||||
|
$list->items = $itemsToKeep;
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a copy of this list which contains items matching any of these charactaristics.
|
||||||
|
*
|
||||||
|
* @example // only bob in the list
|
||||||
|
* $list = $list->filterAny('Name', 'bob');
|
||||||
|
* @example // azis or bob in the list
|
||||||
|
* $list = $list->filterAny('Name', array('aziz', 'bob');
|
||||||
|
* @example // bob or anyone aged 21 in the list
|
||||||
|
* $list = $list->filterAny(array('Name'=>'bob, 'Age'=>21));
|
||||||
|
* @example // bob or anyone aged 21 or 43 in the list
|
||||||
|
* $list = $list->filterAny(array('Name'=>'bob, 'Age'=>array(21, 43)));
|
||||||
|
* @example // all bobs, phils or anyone aged 21 or 43 in the list
|
||||||
|
* $list = $list->filterAny(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43)));
|
||||||
|
*
|
||||||
|
* @param string|array See {@link filter()}
|
||||||
|
* @return DataList
|
||||||
|
*/
|
||||||
|
public function filterAny() {
|
||||||
|
$keepUs = call_user_func_array(array($this, 'normaliseFilterArgs'), func_get_args());
|
||||||
|
|
||||||
|
$itemsToKeep = array();
|
||||||
|
|
||||||
|
foreach ($this->items as $item) {
|
||||||
|
foreach ($keepUs as $column => $value) {
|
||||||
|
$extractedValue = $this->extractValue($item, $column);
|
||||||
|
$matches = is_array($value) ? in_array($extractedValue, $value) : $extractedValue == $value;
|
||||||
|
if ($matches) {
|
||||||
|
$itemsToKeep[] = $item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = clone $this;
|
||||||
|
$list->items = array_unique($itemsToKeep, SORT_REGULAR);
|
||||||
|
return $list;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take the "standard" arguments that the filter/exclude functions take and return a single array with
|
||||||
|
* 'colum' => 'value'
|
||||||
|
*
|
||||||
|
* @param $column array|string The column name to filter OR an assosicative array of column => value
|
||||||
|
* @param $value array|string|null The values to filter the $column against
|
||||||
|
*
|
||||||
|
* @return array The normalised keyed array
|
||||||
|
*/
|
||||||
|
protected function normaliseFilterArgs($column, $value = null) {
|
||||||
if(count(func_get_args())>2){
|
if(count(func_get_args())>2){
|
||||||
throw new InvalidArgumentException('filter takes one array or two arguments');
|
throw new InvalidArgumentException('filter takes one array or two arguments');
|
||||||
}
|
}
|
||||||
@ -503,24 +576,18 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$itemsToKeep = array();
|
return $keepUs;
|
||||||
foreach($this->items as $item){
|
}
|
||||||
$keepItem = true;
|
|
||||||
foreach($keepUs as $column => $value ) {
|
|
||||||
if(is_array($value) && !in_array($this->extractValue($item, $column), $value)) {
|
|
||||||
$keepItem = false;
|
|
||||||
} elseif(!is_array($value) && $this->extractValue($item, $column) != $value) {
|
|
||||||
$keepItem = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if($keepItem) {
|
|
||||||
$itemsToKeep[] = $item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$list = clone $this;
|
/**
|
||||||
$list->items = $itemsToKeep;
|
* Filter this list to only contain the given Primary IDs
|
||||||
return $list;
|
*
|
||||||
|
* @param array $ids Array of integers, will be automatically cast/escaped.
|
||||||
|
* @return ArrayList
|
||||||
|
*/
|
||||||
|
public function byIDs($ids) {
|
||||||
|
$ids = array_map('intval', $ids); // sanitize
|
||||||
|
return $this->filter('ID', $ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function byID($id) {
|
public function byID($id) {
|
||||||
@ -570,25 +637,8 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta
|
|||||||
* // bob age 21 or 43, phil age 21 or 43 would be excluded
|
* // bob age 21 or 43, phil age 21 or 43 would be excluded
|
||||||
*/
|
*/
|
||||||
public function exclude() {
|
public function exclude() {
|
||||||
if(count(func_get_args())>2){
|
|
||||||
throw new InvalidArgumentException('exclude() takes one array or two arguments');
|
|
||||||
}
|
|
||||||
|
|
||||||
if(count(func_get_args()) == 1 && !is_array(func_get_arg(0))){
|
|
||||||
throw new InvalidArgumentException('exclude() takes one array or two arguments');
|
|
||||||
}
|
|
||||||
|
|
||||||
$removeUs = array();
|
|
||||||
if(count(func_get_args())==2){
|
|
||||||
$removeUs[func_get_arg(0)] = func_get_arg(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(count(func_get_args())==1 && is_array(func_get_arg(0))){
|
|
||||||
foreach(func_get_arg(0) as $column => $excludeValue) {
|
|
||||||
$removeUs[$column] = $excludeValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
$removeUs = call_user_func_array(array($this, 'normaliseFilterArgs'), func_get_args());
|
||||||
|
|
||||||
$hitsRequiredToRemove = count($removeUs);
|
$hitsRequiredToRemove = count($removeUs);
|
||||||
$matches = array();
|
$matches = array();
|
||||||
|
@ -147,6 +147,32 @@ abstract class SS_ListDecorator extends ViewableData implements SS_List, SS_Sort
|
|||||||
return call_user_func_array(array($this->list, 'filter'), $args);
|
return call_user_func_array(array($this->list, 'filter'), $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a copy of this list which contains items matching any of these charactaristics.
|
||||||
|
*
|
||||||
|
* @example // only bob in the list
|
||||||
|
* $list = $list->filterAny('Name', 'bob');
|
||||||
|
* // SQL: WHERE "Name" = 'bob'
|
||||||
|
* @example // azis or bob in the list
|
||||||
|
* $list = $list->filterAny('Name', array('aziz', 'bob');
|
||||||
|
* // SQL: WHERE ("Name" IN ('aziz','bob'))
|
||||||
|
* @example // bob or anyone aged 21 in the list
|
||||||
|
* $list = $list->filterAny(array('Name'=>'bob, 'Age'=>21));
|
||||||
|
* // SQL: WHERE ("Name" = 'bob' OR "Age" = '21')
|
||||||
|
* @example // bob or anyone aged 21 or 43 in the list
|
||||||
|
* $list = $list->filterAny(array('Name'=>'bob, 'Age'=>array(21, 43)));
|
||||||
|
* // SQL: WHERE ("Name" = 'bob' OR ("Age" IN ('21', '43'))
|
||||||
|
* @example // all bobs, phils or anyone aged 21 or 43 in the list
|
||||||
|
* $list = $list->filterAny(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43)));
|
||||||
|
* // SQL: WHERE (("Name" IN ('bob', 'phil')) OR ("Age" IN ('21', '43'))
|
||||||
|
*
|
||||||
|
* @param string|array See {@link filter()}
|
||||||
|
* @return DataList
|
||||||
|
*/
|
||||||
|
public function filterAny() {
|
||||||
|
return call_user_func_array(array($this->list, __FUNCTION__), func_get_args());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note that, in the current implementation, the filtered list will be an ArrayList, but this may change in a
|
* Note that, in the current implementation, the filtered list will be an ArrayList, but this may change in a
|
||||||
* future implementation.
|
* future implementation.
|
||||||
@ -174,6 +200,26 @@ abstract class SS_ListDecorator extends ViewableData implements SS_List, SS_Sort
|
|||||||
return $this->list->limit($limit, $offset);
|
return $this->list->limit($limit, $offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the first item with the given ID
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function byID($id) {
|
||||||
|
return $this->list->byID($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter this list to only contain the given Primary IDs
|
||||||
|
*
|
||||||
|
* @param array $ids Array of integers
|
||||||
|
* @return SS_List
|
||||||
|
*/
|
||||||
|
public function byIDs($ids) {
|
||||||
|
return $this->list->byIDs($ids);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exclude the list to not contain items with these charactaristics
|
* Exclude the list to not contain items with these charactaristics
|
||||||
*
|
*
|
||||||
|
@ -301,7 +301,7 @@ class UnsavedRelationList extends ArrayList {
|
|||||||
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function byIDs() {
|
public function byIDs($ids) {
|
||||||
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
throw new LogicException(__FUNCTION__ . " can't be called on an UnsavedRelationList.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,6 +564,72 @@ class ArrayListTest extends SapphireTest {
|
|||||||
$this->assertEquals($expected, $list->toArray(), 'List should only contain Steve and Steve and Clair');
|
$this->assertEquals($expected, $list->toArray(), 'List should only contain Steve and Steve and Clair');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testFilterAny() {
|
||||||
|
|
||||||
|
$list = new ArrayList(array(
|
||||||
|
$steve = array('Name' => 'Steve', 'ID' => 1, 'Age' => 21),
|
||||||
|
$bob = array('Name' => 'Bob', 'ID' => 2, 'Age' => 18),
|
||||||
|
$clair = array('Name' => 'Clair', 'ID' => 3, 'Age' => 21),
|
||||||
|
$phil = array('Name' => 'Phil', 'ID' => 4, 'Age' => 21),
|
||||||
|
$oscar = array('Name' => 'Oscar', 'ID' => 5, 'Age' => 52),
|
||||||
|
$mike = array('Name' => 'Mike', 'ID' => 6, 'Age' => 43),
|
||||||
|
));
|
||||||
|
|
||||||
|
// only bob in the list
|
||||||
|
//$list = $list->filterAny('Name', 'bob');
|
||||||
|
$filteredList = $list->filterAny('Name', 'Bob')->toArray();
|
||||||
|
$this->assertCount(1, $filteredList);
|
||||||
|
$this->assertContains($bob, $filteredList);
|
||||||
|
|
||||||
|
// azis or bob in the list
|
||||||
|
//$list = $list->filterAny('Name', array('aziz', 'bob');
|
||||||
|
$filteredList = $list->filterAny('Name', array('Aziz', 'Bob'))->toArray();
|
||||||
|
$this->assertCount(1, $filteredList);
|
||||||
|
$this->assertContains($bob, $filteredList);
|
||||||
|
|
||||||
|
$filteredList = $list->filterAny('Name', array('Steve', 'Bob'))->toArray();
|
||||||
|
$this->assertCount(2, $filteredList);
|
||||||
|
$this->assertContains($steve, $filteredList);
|
||||||
|
$this->assertContains($bob, $filteredList);
|
||||||
|
|
||||||
|
// bob or anyone aged 21 in the list
|
||||||
|
//$list = $list->filterAny(array('Name'=>'bob, 'Age'=>21));
|
||||||
|
$filteredList = $list->filterAny(array('Name' => 'Bob', 'Age' => 21))->toArray();
|
||||||
|
$this->assertCount(4, $filteredList);
|
||||||
|
$this->assertContains($bob, $filteredList);
|
||||||
|
$this->assertContains($steve, $filteredList);
|
||||||
|
$this->assertContains($clair, $filteredList);
|
||||||
|
$this->assertContains($phil, $filteredList);
|
||||||
|
|
||||||
|
// bob or anyone aged 21 or 43 in the list
|
||||||
|
// $list = $list->filterAny(array('Name'=>'bob, 'Age'=>array(21, 43)));
|
||||||
|
$filteredList = $list->filterAny(array('Name' => 'Bob', 'Age' => array(21, 43)))->toArray();
|
||||||
|
$this->assertCount(5, $filteredList);
|
||||||
|
$this->assertContains($bob, $filteredList);
|
||||||
|
$this->assertContains($steve, $filteredList);
|
||||||
|
$this->assertContains($clair, $filteredList);
|
||||||
|
$this->assertContains($mike, $filteredList);
|
||||||
|
$this->assertContains($phil, $filteredList);
|
||||||
|
|
||||||
|
// all bobs, phils or anyone aged 21 or 43 in the list
|
||||||
|
//$list = $list->filterAny(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43)));
|
||||||
|
$filteredList = $list->filterAny(array('Name' => array('Bob', 'Phil'), 'Age' => array(21, 43)))->toArray();
|
||||||
|
$this->assertCount(5, $filteredList);
|
||||||
|
$this->assertContains($bob, $filteredList);
|
||||||
|
$this->assertContains($steve, $filteredList);
|
||||||
|
$this->assertContains($clair, $filteredList);
|
||||||
|
$this->assertContains($mike, $filteredList);
|
||||||
|
$this->assertContains($phil, $filteredList);
|
||||||
|
|
||||||
|
$filteredList = $list->filterAny(array('Name' => array('Bob', 'Nobody'), 'Age' => array(21, 43)))->toArray();
|
||||||
|
$this->assertCount(5, $filteredList);
|
||||||
|
$this->assertContains($bob, $filteredList);
|
||||||
|
$this->assertContains($steve, $filteredList);
|
||||||
|
$this->assertContains($clair, $filteredList);
|
||||||
|
$this->assertContains($mike, $filteredList);
|
||||||
|
$this->assertContains($phil, $filteredList);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* $list = $list->filterByCallback(function($item, $list) { return $item->Age == 21; })
|
* $list = $list->filterByCallback(function($item, $list) { return $item->Age == 21; })
|
||||||
*/
|
*/
|
||||||
@ -786,6 +852,21 @@ class ArrayListTest extends SapphireTest {
|
|||||||
$this->assertNull($element);
|
$this->assertNull($element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testByIDs() {
|
||||||
|
$list = new ArrayList(array(
|
||||||
|
array('ID' => 1, 'Name' => 'Steve'),
|
||||||
|
array('ID' => 2, 'Name' => 'Bob'),
|
||||||
|
array('ID' => 3, 'Name' => 'John')
|
||||||
|
));
|
||||||
|
$knownIDs = $list->column('ID');
|
||||||
|
$removedID = array_pop($knownIDs);
|
||||||
|
$filteredItems = $list->byIDs($knownIDs);
|
||||||
|
foreach ($filteredItems as $item) {
|
||||||
|
$this->assertContains($item->ID, $knownIDs);
|
||||||
|
$this->assertNotEquals($removedID, $item->ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function testByIDEmpty() {
|
public function testByIDEmpty() {
|
||||||
$list = new ArrayList();
|
$list = new ArrayList();
|
||||||
|
|
||||||
|
@ -407,6 +407,16 @@ class DataListTest extends SapphireTest {
|
|||||||
$this->assertNotContains('WHERE ("DataObjectTest_SubTeam"."ID" = ?)', $query);
|
$this->assertNotContains('WHERE ("DataObjectTest_SubTeam"."ID" = ?)', $query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testByIDs() {
|
||||||
|
$knownIDs = $this->allFixtureIDs('DataObjectTest_Player');
|
||||||
|
$removedID = array_pop($knownIDs);
|
||||||
|
$filteredPlayers = DataObjectTest_Player::get()->byIDs($knownIDs);
|
||||||
|
foreach ($filteredPlayers as $player) {
|
||||||
|
$this->assertContains($player->ID, $knownIDs);
|
||||||
|
$this->assertNotEquals($removedID, $player->ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test DataList->removeByID()
|
* Test DataList->removeByID()
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user