Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Illuminate/Collections/Enumerable.php
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,11 @@ public function filter(callable $callback = null);
* Apply the callback if the value is truthy.
*
* @param bool $value
* @param callable $callback
* @param callable|null $callback
* @param callable|null $default
* @return static|mixed
*/
public function when($value, callable $callback, callable $default = null);
public function when($value, callable $callback = null, callable $default = null);

/**
* Apply the callback if the collection is empty.
Expand Down
27 changes: 12 additions & 15 deletions src/Illuminate/Collections/HigherOrderWhenProxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@

namespace Illuminate\Support;

/**
* @mixin \Illuminate\Support\Enumerable
*/
class HigherOrderWhenProxy
{
/**
* The collection being operated on.
* The target being conditionally operated on.
*
* @var \Illuminate\Support\Enumerable
* @var mixed
*/
protected $collection;
protected $target;

/**
* The condition for proxying.
Expand All @@ -24,31 +21,31 @@ class HigherOrderWhenProxy
/**
* Create a new proxy instance.
*
* @param \Illuminate\Support\Enumerable $collection
* @param mixed $target
* @param bool $condition
* @return void
*/
public function __construct(Enumerable $collection, $condition)
public function __construct($target, $condition)
{
$this->target = $target;
$this->condition = $condition;
$this->collection = $collection;
}

/**
* Proxy accessing an attribute onto the collection.
* Proxy accessing an attribute onto the target.
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
return $this->condition
? $this->collection->{$key}
: $this->collection;
? $this->target->{$key}
: $this->target;
}

/**
* Proxy a method call onto the collection.
* Proxy a method call on the target.
*
* @param string $method
* @param array $parameters
Expand All @@ -57,7 +54,7 @@ public function __get($key)
public function __call($method, $parameters)
{
return $this->condition
? $this->collection->{$method}(...$parameters)
: $this->collection;
? $this->target->{$method}(...$parameters)
: $this->target;
}
}
39 changes: 2 additions & 37 deletions src/Illuminate/Collections/Traits/EnumeratesValues.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use Illuminate\Support\Collection;
use Illuminate\Support\Enumerable;
use Illuminate\Support\HigherOrderCollectionProxy;
use Illuminate\Support\HigherOrderWhenProxy;
use JsonSerializable;
use Symfony\Component\VarDumper\VarDumper;
use Traversable;
Expand Down Expand Up @@ -45,6 +44,8 @@
*/
trait EnumeratesValues
{
use Conditionable;

/**
* The methods that can be proxied.
*
Expand Down Expand Up @@ -453,29 +454,6 @@ public function sum($callback = null)
}, 0);
}

/**
* Apply the callback if the value is truthy.
*
* @param bool|mixed $value
* @param callable|null $callback
* @param callable|null $default
* @return static|mixed
*/
public function when($value, callable $callback = null, callable $default = null)
{
if (! $callback) {
return new HigherOrderWhenProxy($this, $value);
}

if ($value) {
return $callback($this, $value);
} elseif ($default) {
return $default($this, $value);
}

return $this;
}

/**
* Apply the callback if the collection is empty.
*
Expand All @@ -500,19 +478,6 @@ public function whenNotEmpty(callable $callback, callable $default = null)
return $this->when($this->isNotEmpty(), $callback, $default);
}

/**
* Apply the callback if the value is falsy.
*
* @param bool $value
* @param callable $callback
* @param callable|null $default
* @return static|mixed
*/
public function unless($value, callable $callback, callable $default = null)
{
return $this->when(! $value, $callback, $default);
}

/**
* Apply the callback unless the collection is empty.
*
Expand Down
18 changes: 14 additions & 4 deletions src/Illuminate/Support/Traits/Conditionable.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@

namespace Illuminate\Support\Traits;

use Illuminate\Support\HigherOrderWhenProxy;

trait Conditionable
{
/**
* Apply the callback if the given "value" is truthy.
*
* @param mixed $value
* @param callable $callback
* @param callable|null $callback
* @param callable|null $default
*
* @return mixed
*/
public function when($value, $callback, $default = null)
public function when($value, callable $callback = null, callable $default = null)
{
if (! $callback) {
return new HigherOrderWhenProxy($this, $value);
}

if ($value) {
return $callback($this, $value) ?: $this;
} elseif ($default) {
Expand All @@ -28,13 +34,17 @@ public function when($value, $callback, $default = null)
* Apply the callback if the given "value" is falsy.
*
* @param mixed $value
* @param callable $callback
* @param callable|null $callback
* @param callable|null $default
*
* @return mixed
*/
public function unless($value, $callback, $default = null)
public function unless($value, callable $callback = null, callable $default = null)
{
if (! $callback) {
return new HigherOrderWhenProxy($this, ! $value);
}

if (! $value) {
return $callback($this, $value) ?: $this;
} elseif ($default) {
Expand Down
28 changes: 26 additions & 2 deletions tests/Support/SupportCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4298,8 +4298,8 @@ public function testWhenEmpty($collection)
{
$data = new $collection(['michael', 'tom']);

$data = $data->whenEmpty(function ($collection) {
return $data->concat(['adam']);
$data = $data->whenEmpty(function () {
throw new Exception('whenEmpty() should not trigger on a collection with items');
});

$this->assertSame(['michael', 'tom'], $data->toArray());
Expand Down Expand Up @@ -4367,6 +4367,30 @@ public function testWhenNotEmptyDefault($collection)
$this->assertSame(['michael', 'tom', 'adam'], $data->toArray());
}

/**
* @dataProvider collectionClassProvider
*/
public function testHigherOrderWhenAndUnless($collection)
{
$data = new $collection(['michael', 'tom']);

$data = $data->when(true)->concat(['chris']);

$this->assertSame(['michael', 'tom', 'chris'], $data->toArray());

$data = $data->when(false)->concat(['adam']);

$this->assertSame(['michael', 'tom', 'chris'], $data->toArray());

$data = $data->unless(false)->concat(['adam']);

$this->assertSame(['michael', 'tom', 'chris', 'adam'], $data->toArray());

$data = $data->unless(true)->concat(['bogdan']);

$this->assertSame(['michael', 'tom', 'chris', 'adam'], $data->toArray());
}

/**
* @dataProvider collectionClassProvider
*/
Expand Down
109 changes: 109 additions & 0 deletions tests/Support/SupportConditionableTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

namespace Illuminate\Tests\Support;

use Exception;
use Illuminate\Support\Traits\Conditionable;
use PHPUnit\Framework\TestCase;

class SupportConditionableTest extends TestCase
{
public function testWhenConditionCallback()
{
$object = (new CustomConditionableObject())
->when(2, function ($object, $condition) {
$object->on();
$this->assertEquals(2, $condition);
}, function () {
throw new Exception('when() should not trigger default callback on a truthy value');
});

$this->assertTrue($object->enabled);
}

public function testWhenDefaultCallback()
{
$object = (new CustomConditionableObject())
->when(null, function () {
throw new Exception('when() should not trigger on a falsy value');
}, function ($object, $condition) {
$object->on();
$this->assertNull($condition);
});

$this->assertTrue($object->enabled);
}

public function testUnlessConditionCallback()
{
$object = (new CustomConditionableObject())
->unless(null, function ($object, $condition) {
$object->on();
$this->assertNull($condition);
}, function () {
throw new Exception('unless() should not trigger default callback on a falsy value');
});

$this->assertTrue($object->enabled);
}

public function testUnlessDefaultCallback()
{
$object = (new CustomConditionableObject())
->unless(2, function () {
throw new Exception('unless() should not trigger on a truthy value');
}, function ($object, $condition) {
$object->on();
$this->assertEquals(2, $condition);
});

$this->assertTrue($object->enabled);
}

public function testWhenProxy()
{
$object = (new CustomConditionableObject())->when(true)->on();

$this->assertInstanceOf(CustomConditionableObject::class, $object);
$this->assertTrue($object->enabled);

$object = (new CustomConditionableObject())->when(false)->on();

$this->assertInstanceOf(CustomConditionableObject::class, $object);
$this->assertFalse($object->enabled);
}

public function testUnlessProxy()
{
$object = (new CustomConditionableObject())->unless(false)->on();

$this->assertInstanceOf(CustomConditionableObject::class, $object);
$this->assertTrue($object->enabled);

$object = (new CustomConditionableObject())->unless(true)->on();

$this->assertInstanceOf(CustomConditionableObject::class, $object);
$this->assertFalse($object->enabled);
}
}

class CustomConditionableObject
{
use Conditionable;

public $enabled = false;

public function on()
{
$this->enabled = true;

return $this;
}

public function off()
{
$this->enabled = false;

return $this;
}
}