Skip to content

Commit

Permalink
Added IfElse strategy. (#6)
Browse files Browse the repository at this point in the history
Added IfElse strategy.
Changed IfExists strategy to extend IfElse.
Changed Either strategy to extend IfExists.
  • Loading branch information
Bilge authored Mar 10, 2017
2 parents 7051ba4 + 5c9f760 commit c8ddf0e
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 47 deletions.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Contents
1. [Either](#either)
1. [Filter](#filter)
1. [Flatten](#flatten)
1. [IfElse](#ifelse)
1. [IfExists](#ifexists)
1. [Join](#join)
1. [Merge](#merge)
Expand Down Expand Up @@ -294,6 +295,7 @@ The following strategies ship with Mapper and provide a suite of commonly used f
- [Either](#either) – Either uses the primary strategy, if it returns non-null, otherwise delegates to a fallback expression.
- [Filter](#filter) – Filters null values or values rejected by the specified callback.
- [Flatten](#flatten) – Moves all nested values to the top level.
- [IfElse](#ifelse) – Delegates to one expression or another depending on whether the specified condition strictly evaluates to true.
- [IfExists](#ifexists) – Delegates to one expression or another depending on whether the specified condition maps to null.
- [Join](#join) – Joins sub-string expressions together with a glue string.
- [Merge](#merge) – Merges two data sets together giving precedence to the latter if keys collide.
Expand Down Expand Up @@ -577,6 +579,39 @@ $data = [

> [1, 2, 3, 3, 4, 5]
### IfElse

Delegates to one expression or another depending on whether the specified condition strictly evaluates to true.

If the condition does not return a boolean, `InvalidConditionException` is thrown.

#### Signature

```php
IfElse(callable $condition, Strategy|Mapping|array|mixed $if, Strategy|Mapping|array|mixed $else = null)
```

1. `$condition` – Condition.
2. `$if` – Expression used when condition evaluates to true.
3. `$else` – Expression used when condition evaluates to false.

#### Example

```php
(new Mapper)->map(
['foo' => 'foo'],
new IfElse(
function ($data) {
return $data['foo'] !== 'bar';
},
true,
false
)
);
```

> true
### IfExists

Delegates to one expression or another depending on whether the specified condition maps to null.
Expand Down
10 changes: 10 additions & 0 deletions src/InvalidConditionException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
namespace ScriptFUSION\Mapper;

/**
* The exception that is thrown when an invalid condition is specified.
*/
class InvalidConditionException extends \RuntimeException
{
// Intentionally empty.
}
17 changes: 2 additions & 15 deletions src/Strategy/Either.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,14 @@
/**
* Either uses the primary strategy, if it returns non-null, otherwise delegates to a fallback expression.
*/
class Either extends Decorator
class Either extends IfExists
{
private $expression;

/**
* @param Strategy $strategy
* @param Strategy|Mapping|array|mixed $expression
*/
public function __construct(Strategy $strategy, $expression)
{
parent::__construct($strategy);

$this->expression = $expression;
}

public function __invoke($data, $context = null)
{
if (($result = parent::__invoke($data, $context)) !== null) {
return $result;
}

return $this->delegate($this->expression, $data, $context);
parent::__construct($strategy, $strategy, $expression);
}
}
60 changes: 60 additions & 0 deletions src/Strategy/IfElse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php
namespace ScriptFUSION\Mapper\Strategy;

use ScriptFUSION\Mapper\InvalidConditionException;
use ScriptFUSION\Mapper\Mapping;

/**
* Delegates to one expression or another depending on whether the specified condition strictly evaluates to true.
*/
class IfElse extends Delegate
{
/** @var callable */
private $condition;

/** @var Strategy|Mapping|array|mixed */
private $else;

/**
* Initializes this instance with the specified condition, the specified
* expression to be resolved when condition is true and, optionally, the
* specified expression to be resolved when condition is false.
*
* @param callable $condition Condition.
* @param Strategy|Mapping|array|mixed $if Primary expression.
* @param Strategy|Mapping|array|mixed|null $else Optional. Fallback expression.
*/
public function __construct(callable $condition, $if, $else = null)
{
parent::__construct($if);

$this->condition = $condition;
$this->else = $else;
}

/**
* Resolves the stored expression when the stored condition strictly
* evaluates to true, otherwise resolve the stored fallback expression.
*
* @param mixed $data
* @param mixed $context
*
* @throws InvalidConditionException
*
* @return mixed
*/
public function __invoke($data, $context = null)
{
$result = call_user_func($this->condition, $data, $context);

if (!is_bool($result)) {
throw new InvalidConditionException('Invalid return from condition: must be of type boolean.');
}

if ($result === true) {
return parent::__invoke($data, $context);
}

return $this->delegate($this->else, $data, $context);
}
}
40 changes: 8 additions & 32 deletions src/Strategy/IfExists.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,8 @@
/**
* Delegates to one expression or another depending on whether the specified condition maps to null.
*/
class IfExists extends Decorator
class IfExists extends IfElse
{
/** @var Strategy|Mapping|array|mixed */
private $if;

/** @var Strategy|Mapping|array|mixed */
private $else;

/**
* Initializes this instance with the specified condition, the specified
* strategy or mapping to be resolved when condition is non-null and,
Expand All @@ -26,30 +20,12 @@ class IfExists extends Decorator
*/
public function __construct(Strategy $condition, $if, $else = null)
{
parent::__construct($condition);

$this->if = $if;
$this->else = $else;
}

/**
* Resolves the stored strategy or mapping when the stored condition
* resolves to a non-null value, otherwise returns the stored default
* value.
*
* @param mixed $data
* @param mixed $context
*
* @return mixed
*/
public function __invoke($data, $context = null)
{
if (parent::__invoke($data, $context) !== null) {
return $this->delegate($this->if, $data, $context);
}

if ($this->else !== null) {
return $this->delegate($this->else, $data, $context);
}
parent::__construct(
function ($data, $context) use ($condition) {
return $this->delegate($condition, $data, $context) !== null;
},
$if,
$else
);
}
}
17 changes: 17 additions & 0 deletions test/Functional/DocumentationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use ScriptFUSION\Mapper\Strategy\Either;
use ScriptFUSION\Mapper\Strategy\Filter;
use ScriptFUSION\Mapper\Strategy\Flatten;
use ScriptFUSION\Mapper\Strategy\IfElse;
use ScriptFUSION\Mapper\Strategy\IfExists;
use ScriptFUSION\Mapper\Strategy\Join;
use ScriptFUSION\Mapper\Strategy\Merge;
Expand Down Expand Up @@ -221,6 +222,22 @@ public function testFlatten()
self::assertSame([1, 2, 3, 3, 4, 5], (new Mapper)->map($data, (new Flatten(new Copy('foo')))->ignoreKeys()));
}

public function testIfElse()
{
self::assertTrue(
(new Mapper)->map(
['foo' => 'foo'],
new IfElse(
function ($data) {
return $data['foo'] !== 'bar';
},
true,
false
)
)
);
}

public function testIfExists()
{
$data = ['foo' => 'foo'];
Expand Down
51 changes: 51 additions & 0 deletions test/Integration/Mapper/Strategy/IfElseTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
namespace ScriptFUSIONTest\Integration\Mapper\Strategy;

use ScriptFUSION\Mapper\InvalidConditionException;
use ScriptFUSION\Mapper\Mapper;
use ScriptFUSION\Mapper\Strategy\IfElse;

final class IfElseTest extends \PHPUnit_Framework_TestCase
{
private $condition;

public function setUp()
{
$this->condition = function ($data) {
return array_key_exists('baz', $data) && $data['baz'] === 'qux';
};
}

public function testIfElse()
{
$ifElse = (new IfElse($this->condition, 'foo', 'bar'))->setMapper(new Mapper);

self::assertSame('foo', $ifElse(['baz' => 'qux']));
self::assertSame('bar', $ifElse(['baz' => 'quux']));
self::assertSame('bar', $ifElse([]));
}

public function testOnlyIf()
{
$ifElse = (new IfElse($this->condition, 'foo'))->setMapper(new Mapper);

self::assertSame('foo', $ifElse(['baz' => 'qux']));
self::assertNull($ifElse(['baz' => 'quux']));
self::assertNull($ifElse([]));
}

public function testStrictness()
{
$this->setExpectedException(InvalidConditionException::class);

$ifElse = (new IfElse(
function () {
return 1;
},
'foo',
'bar'
))->setMapper(new Mapper);

$ifElse([]);
}
}

0 comments on commit c8ddf0e

Please sign in to comment.