Skip to content

Commit c8ddf0e

Browse files
authored
Added IfElse strategy. (#6)
Added IfElse strategy. Changed IfExists strategy to extend IfElse. Changed Either strategy to extend IfExists.
2 parents 7051ba4 + 5c9f760 commit c8ddf0e

File tree

7 files changed

+183
-47
lines changed

7 files changed

+183
-47
lines changed

README.md

+35
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Contents
3131
1. [Either](#either)
3232
1. [Filter](#filter)
3333
1. [Flatten](#flatten)
34+
1. [IfElse](#ifelse)
3435
1. [IfExists](#ifexists)
3536
1. [Join](#join)
3637
1. [Merge](#merge)
@@ -294,6 +295,7 @@ The following strategies ship with Mapper and provide a suite of commonly used f
294295
- [Either](#either) – Either uses the primary strategy, if it returns non-null, otherwise delegates to a fallback expression.
295296
- [Filter](#filter) – Filters null values or values rejected by the specified callback.
296297
- [Flatten](#flatten) – Moves all nested values to the top level.
298+
- [IfElse](#ifelse) – Delegates to one expression or another depending on whether the specified condition strictly evaluates to true.
297299
- [IfExists](#ifexists) – Delegates to one expression or another depending on whether the specified condition maps to null.
298300
- [Join](#join) – Joins sub-string expressions together with a glue string.
299301
- [Merge](#merge) – Merges two data sets together giving precedence to the latter if keys collide.
@@ -577,6 +579,39 @@ $data = [
577579

578580
> [1, 2, 3, 3, 4, 5]
579581
582+
### IfElse
583+
584+
Delegates to one expression or another depending on whether the specified condition strictly evaluates to true.
585+
586+
If the condition does not return a boolean, `InvalidConditionException` is thrown.
587+
588+
#### Signature
589+
590+
```php
591+
IfElse(callable $condition, Strategy|Mapping|array|mixed $if, Strategy|Mapping|array|mixed $else = null)
592+
```
593+
594+
1. `$condition` – Condition.
595+
2. `$if` – Expression used when condition evaluates to true.
596+
3. `$else` – Expression used when condition evaluates to false.
597+
598+
#### Example
599+
600+
```php
601+
(new Mapper)->map(
602+
['foo' => 'foo'],
603+
new IfElse(
604+
function ($data) {
605+
return $data['foo'] !== 'bar';
606+
},
607+
true,
608+
false
609+
)
610+
);
611+
```
612+
613+
> true
614+
580615
### IfExists
581616

582617
Delegates to one expression or another depending on whether the specified condition maps to null.

src/InvalidConditionException.php

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
namespace ScriptFUSION\Mapper;
3+
4+
/**
5+
* The exception that is thrown when an invalid condition is specified.
6+
*/
7+
class InvalidConditionException extends \RuntimeException
8+
{
9+
// Intentionally empty.
10+
}

src/Strategy/Either.php

+2-15
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,14 @@
66
/**
77
* Either uses the primary strategy, if it returns non-null, otherwise delegates to a fallback expression.
88
*/
9-
class Either extends Decorator
9+
class Either extends IfExists
1010
{
11-
private $expression;
12-
1311
/**
1412
* @param Strategy $strategy
1513
* @param Strategy|Mapping|array|mixed $expression
1614
*/
1715
public function __construct(Strategy $strategy, $expression)
1816
{
19-
parent::__construct($strategy);
20-
21-
$this->expression = $expression;
22-
}
23-
24-
public function __invoke($data, $context = null)
25-
{
26-
if (($result = parent::__invoke($data, $context)) !== null) {
27-
return $result;
28-
}
29-
30-
return $this->delegate($this->expression, $data, $context);
17+
parent::__construct($strategy, $strategy, $expression);
3118
}
3219
}

src/Strategy/IfElse.php

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
namespace ScriptFUSION\Mapper\Strategy;
3+
4+
use ScriptFUSION\Mapper\InvalidConditionException;
5+
use ScriptFUSION\Mapper\Mapping;
6+
7+
/**
8+
* Delegates to one expression or another depending on whether the specified condition strictly evaluates to true.
9+
*/
10+
class IfElse extends Delegate
11+
{
12+
/** @var callable */
13+
private $condition;
14+
15+
/** @var Strategy|Mapping|array|mixed */
16+
private $else;
17+
18+
/**
19+
* Initializes this instance with the specified condition, the specified
20+
* expression to be resolved when condition is true and, optionally, the
21+
* specified expression to be resolved when condition is false.
22+
*
23+
* @param callable $condition Condition.
24+
* @param Strategy|Mapping|array|mixed $if Primary expression.
25+
* @param Strategy|Mapping|array|mixed|null $else Optional. Fallback expression.
26+
*/
27+
public function __construct(callable $condition, $if, $else = null)
28+
{
29+
parent::__construct($if);
30+
31+
$this->condition = $condition;
32+
$this->else = $else;
33+
}
34+
35+
/**
36+
* Resolves the stored expression when the stored condition strictly
37+
* evaluates to true, otherwise resolve the stored fallback expression.
38+
*
39+
* @param mixed $data
40+
* @param mixed $context
41+
*
42+
* @throws InvalidConditionException
43+
*
44+
* @return mixed
45+
*/
46+
public function __invoke($data, $context = null)
47+
{
48+
$result = call_user_func($this->condition, $data, $context);
49+
50+
if (!is_bool($result)) {
51+
throw new InvalidConditionException('Invalid return from condition: must be of type boolean.');
52+
}
53+
54+
if ($result === true) {
55+
return parent::__invoke($data, $context);
56+
}
57+
58+
return $this->delegate($this->else, $data, $context);
59+
}
60+
}

src/Strategy/IfExists.php

+8-32
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,8 @@
66
/**
77
* Delegates to one expression or another depending on whether the specified condition maps to null.
88
*/
9-
class IfExists extends Decorator
9+
class IfExists extends IfElse
1010
{
11-
/** @var Strategy|Mapping|array|mixed */
12-
private $if;
13-
14-
/** @var Strategy|Mapping|array|mixed */
15-
private $else;
16-
1711
/**
1812
* Initializes this instance with the specified condition, the specified
1913
* strategy or mapping to be resolved when condition is non-null and,
@@ -26,30 +20,12 @@ class IfExists extends Decorator
2620
*/
2721
public function __construct(Strategy $condition, $if, $else = null)
2822
{
29-
parent::__construct($condition);
30-
31-
$this->if = $if;
32-
$this->else = $else;
33-
}
34-
35-
/**
36-
* Resolves the stored strategy or mapping when the stored condition
37-
* resolves to a non-null value, otherwise returns the stored default
38-
* value.
39-
*
40-
* @param mixed $data
41-
* @param mixed $context
42-
*
43-
* @return mixed
44-
*/
45-
public function __invoke($data, $context = null)
46-
{
47-
if (parent::__invoke($data, $context) !== null) {
48-
return $this->delegate($this->if, $data, $context);
49-
}
50-
51-
if ($this->else !== null) {
52-
return $this->delegate($this->else, $data, $context);
53-
}
23+
parent::__construct(
24+
function ($data, $context) use ($condition) {
25+
return $this->delegate($condition, $data, $context) !== null;
26+
},
27+
$if,
28+
$else
29+
);
5430
}
5531
}

test/Functional/DocumentationTest.php

+17
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use ScriptFUSION\Mapper\Strategy\Either;
1313
use ScriptFUSION\Mapper\Strategy\Filter;
1414
use ScriptFUSION\Mapper\Strategy\Flatten;
15+
use ScriptFUSION\Mapper\Strategy\IfElse;
1516
use ScriptFUSION\Mapper\Strategy\IfExists;
1617
use ScriptFUSION\Mapper\Strategy\Join;
1718
use ScriptFUSION\Mapper\Strategy\Merge;
@@ -221,6 +222,22 @@ public function testFlatten()
221222
self::assertSame([1, 2, 3, 3, 4, 5], (new Mapper)->map($data, (new Flatten(new Copy('foo')))->ignoreKeys()));
222223
}
223224

225+
public function testIfElse()
226+
{
227+
self::assertTrue(
228+
(new Mapper)->map(
229+
['foo' => 'foo'],
230+
new IfElse(
231+
function ($data) {
232+
return $data['foo'] !== 'bar';
233+
},
234+
true,
235+
false
236+
)
237+
)
238+
);
239+
}
240+
224241
public function testIfExists()
225242
{
226243
$data = ['foo' => 'foo'];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
namespace ScriptFUSIONTest\Integration\Mapper\Strategy;
3+
4+
use ScriptFUSION\Mapper\InvalidConditionException;
5+
use ScriptFUSION\Mapper\Mapper;
6+
use ScriptFUSION\Mapper\Strategy\IfElse;
7+
8+
final class IfElseTest extends \PHPUnit_Framework_TestCase
9+
{
10+
private $condition;
11+
12+
public function setUp()
13+
{
14+
$this->condition = function ($data) {
15+
return array_key_exists('baz', $data) && $data['baz'] === 'qux';
16+
};
17+
}
18+
19+
public function testIfElse()
20+
{
21+
$ifElse = (new IfElse($this->condition, 'foo', 'bar'))->setMapper(new Mapper);
22+
23+
self::assertSame('foo', $ifElse(['baz' => 'qux']));
24+
self::assertSame('bar', $ifElse(['baz' => 'quux']));
25+
self::assertSame('bar', $ifElse([]));
26+
}
27+
28+
public function testOnlyIf()
29+
{
30+
$ifElse = (new IfElse($this->condition, 'foo'))->setMapper(new Mapper);
31+
32+
self::assertSame('foo', $ifElse(['baz' => 'qux']));
33+
self::assertNull($ifElse(['baz' => 'quux']));
34+
self::assertNull($ifElse([]));
35+
}
36+
37+
public function testStrictness()
38+
{
39+
$this->setExpectedException(InvalidConditionException::class);
40+
41+
$ifElse = (new IfElse(
42+
function () {
43+
return 1;
44+
},
45+
'foo',
46+
'bar'
47+
))->setMapper(new Mapper);
48+
49+
$ifElse([]);
50+
}
51+
}

0 commit comments

Comments
 (0)