Added before and after methods to Collection (#6869)

Co-authored-by: 李铭昕 <715557344@qq.com>
This commit is contained in:
Deeka Wong 2024-06-13 14:23:42 +08:00 committed by GitHub
parent 7613acee40
commit 91625d8466
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 245 additions and 0 deletions

View File

@ -1,5 +1,9 @@
# v3.1.27 - TBD
## Added
- [#6869](https://github.com/hyperf/hyperf/pull/6869) Added `before` and `after` methods to `Collection`.
# v3.1.26 - 2024-06-13
## Fixed

View File

@ -924,6 +924,52 @@ class Collection implements Enumerable, ArrayAccess
return false;
}
/**
* Get the item before the given item.
*
* @param (callable(TValue,TKey): bool)|TValue $value
* @return null|TValue
*/
public function before(mixed $value, bool $strict = false): mixed
{
$key = $this->search($value, $strict);
if ($key === false) {
return null;
}
$position = $this->keys()->search($key);
if ($position === 0) {
return null;
}
return $this->get($this->keys()->get($position - 1));
}
/**
* Get the item after the given item.
*
* @param (callable(TValue,TKey): bool)|TValue $value
* @return null|TValue
*/
public function after(mixed $value, bool $strict = false): mixed
{
$key = $this->search($value, $strict);
if ($key === false) {
return null;
}
$position = $this->keys()->search($key);
if ($position === $this->keys()->count() - 1) {
return null;
}
return $this->get($this->keys()->get($position + 1));
}
/**
* Get and remove the first item from the collection.
*

View File

@ -845,6 +845,22 @@ interface Enumerable extends Arrayable, Countable, IteratorAggregate, Jsonable,
*/
public function search($value, bool $strict = false);
/**
* Get the item before the given item.
*
* @param (callable(TValue,TKey): bool)|TValue $value
* @return null|TValue
*/
public function before(mixed $value, bool $strict = false): mixed;
/**
* Get the item after the given item.
*
* @param (callable(TValue,TKey): bool)|TValue $value
* @return null|TValue
*/
public function after(mixed $value, bool $strict = false): mixed;
/**
* Shuffle the items in the collection.
*

View File

@ -1069,6 +1069,64 @@ class LazyCollection implements Enumerable
return false;
}
/**
* Get the item before the given item.
*
* @param (callable(TValue,TKey): bool)|TValue $value
* @return null|TValue
*/
public function before(mixed $value, bool $strict = false): mixed
{
$previous = null;
/** @var (callable(TValue,TKey): bool) $predicate */
$predicate = $this->useAsCallable($value)
? $value
: function ($item) use ($value, $strict) {
return $strict ? $item === $value : $item == $value;
};
foreach ($this as $key => $item) {
if ($predicate($item, $key)) {
return $previous;
}
$previous = $item;
}
return null;
}
/**
* Get the item after the given item.
*
* @param (callable(TValue,TKey): bool)|TValue $value
* @return null|TValue
*/
public function after(mixed $value, bool $strict = false): mixed
{
$found = false;
/** @var (callable(TValue,TKey): bool) $predicate */
$predicate = $this->useAsCallable($value)
? $value
: function ($item) use ($value, $strict) {
return $strict ? $item === $value : $item == $value;
};
foreach ($this as $key => $item) {
if ($found) {
return $item;
}
if ($predicate($item, $key)) {
$found = true;
}
}
return null;
}
/**
* Shuffle the items in the collection.
*

View File

@ -979,4 +979,125 @@ class CollectionTest extends TestCase
$this->assertSame('foo', $data->get('email'));
$this->assertSame('male', $data->get('gender'));
}
#[DataProvider('collectionClassProvider')]
public function testBeforeReturnsItemBeforeTheGivenItem($collection)
{
$c = new $collection([1, 2, 3, 4, 5, 2, 5, 'name' => 'taylor', 'framework' => 'laravel']);
$this->assertEquals(1, $c->before(2));
$this->assertEquals(1, $c->before('2'));
$this->assertEquals(5, $c->before('taylor'));
$this->assertSame('taylor', $c->before('laravel'));
$this->assertEquals(4, $c->before(function ($value) {
return $value > 4;
}));
$this->assertEquals(5, $c->before(function ($value) {
return ! is_numeric($value);
}));
}
#[DataProvider('collectionClassProvider')]
public function testBeforeInStrictMode($collection)
{
$c = new $collection([false, 0, 1, [], '']);
$this->assertNull($c->before('false', true));
$this->assertNull($c->before('1', true));
$this->assertNull($c->before(false, true));
$this->assertEquals(false, $c->before(0, true));
$this->assertEquals(0, $c->before(1, true));
$this->assertEquals(1, $c->before([], true));
$this->assertEquals([], $c->before('', true));
}
#[DataProvider('collectionClassProvider')]
public function testBeforeReturnsNullWhenItemIsNotFound($collection)
{
$c = new $collection([1, 2, 3, 4, 5, 'foo' => 'bar']);
$this->assertNull($c->before(6));
$this->assertNull($c->before('foo'));
$this->assertNull($c->before(function ($value) {
return $value < 1 && is_numeric($value);
}));
$this->assertNull($c->before(function ($value) {
return $value === 'nope';
}));
}
#[DataProvider('collectionClassProvider')]
public function testBeforeReturnsNullWhenItemOnTheFirstitem($collection)
{
$c = new $collection([1, 2, 3, 4, 5, 'foo' => 'bar']);
$this->assertNull($c->before(1));
$this->assertNull($c->before(function ($value) {
return $value < 2 && is_numeric($value);
}));
$c = new $collection(['foo' => 'bar', 1, 2, 3, 4, 5]);
$this->assertNull($c->before('bar'));
}
#[DataProvider('collectionClassProvider')]
public function testAfterReturnsItemAfterTheGivenItem($collection)
{
$c = new $collection([1, 2, 3, 4, 2, 5, 'name' => 'taylor', 'framework' => 'laravel']);
$this->assertEquals(2, $c->after(1));
$this->assertEquals(3, $c->after(2));
$this->assertEquals(4, $c->after(3));
$this->assertEquals(2, $c->after(4));
$this->assertEquals('taylor', $c->after(5));
$this->assertEquals('laravel', $c->after('taylor'));
$this->assertEquals(4, $c->after(function ($value) {
return $value > 2;
}));
$this->assertEquals('laravel', $c->after(function ($value) {
return ! is_numeric($value);
}));
}
#[DataProvider('collectionClassProvider')]
public function testAfterInStrictMode($collection)
{
$c = new $collection([false, 0, 1, [], '']);
$this->assertNull($c->after('false', true));
$this->assertNull($c->after('1', true));
$this->assertNull($c->after('', true));
$this->assertEquals(0, $c->after(false, true));
$this->assertEquals([], $c->after(1, true));
$this->assertEquals('', $c->after([], true));
}
#[DataProvider('collectionClassProvider')]
public function testAfterReturnsNullWhenItemIsNotFound($collection)
{
$c = new $collection([1, 2, 3, 4, 5, 'foo' => 'bar']);
$this->assertNull($c->after(6));
$this->assertNull($c->after('foo'));
$this->assertNull($c->after(function ($value) {
return $value < 1 && is_numeric($value);
}));
$this->assertNull($c->after(function ($value) {
return $value === 'nope';
}));
}
#[DataProvider('collectionClassProvider')]
public function testAfterReturnsNullWhenItemOnTheLastItem($collection)
{
$c = new $collection([1, 2, 3, 4, 5, 'foo' => 'bar']);
$this->assertNull($c->after('bar'));
$this->assertNull($c->after(function ($value) {
return $value > 4 && ! is_numeric($value);
}));
$c = new $collection(['foo' => 'bar', 1, 2, 3, 4, 5]);
$this->assertNull($c->after(5));
}
}