Skip to content

Commit cf780b2

Browse files
author
Mark Challoner
committed
Add IfElse and Exists strategies. Refactor Either strategy to extend IfElse. Deprecate IfExists strategy.
1 parent 7051ba4 commit cf780b2

File tree

7 files changed

+269
-17
lines changed

7 files changed

+269
-17
lines changed

README.md

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ Contents
2929
1. [Collection](#collection)
3030
1. [Context](#context)
3131
1. [Either](#either)
32+
1. [Exists](#exists)
3233
1. [Filter](#filter)
3334
1. [Flatten](#flatten)
34-
1. [IfExists](#ifexists)
35+
1. [IfElse](#ifelse)
36+
1. [IfExists](#ifexists) (deprecated)
3537
1. [Join](#join)
3638
1. [Merge](#merge)
3739
1. [TakeFirst](#takefirst)
@@ -291,10 +293,12 @@ The following strategies ship with Mapper and provide a suite of commonly used f
291293
- [Callback](#callback) – Augments data using the specified callback.
292294
- [Collection](#collection) – Maps a collection of data by applying a transformation to each datum.
293295
- [Context](#context) – Replaces the context for the specified expression.
296+
- [Exists](#exists) – Returns true or false if the resolved value of the strategy or the path exists.
294297
- [Either](#either) – Either uses the primary strategy, if it returns non-null, otherwise delegates to a fallback expression.
295298
- [Filter](#filter) – Filters null values or values rejected by the specified callback.
296299
- [Flatten](#flatten) – Moves all nested values to the top level.
297-
- [IfExists](#ifexists) – Delegates to one expression or another depending on whether the specified condition maps to null.
300+
- [IfElse](#ifelse) – Delegates to one expression or another depending on whether the specified condition loosely evaluates to true.
301+
- [IfExists](#ifexists) (deprecated) – Delegates to one expression or another depending on whether the specified condition maps to null.
298302
- [Join](#join) – Joins sub-string expressions together with a glue string.
299303
- [Merge](#merge) – Merges two data sets together giving precedence to the latter if keys collide.
300304
- [TakeFirst](#takefirst) – Takes the first value from a collection one or more times.
@@ -511,6 +515,34 @@ Either(Strategy $strategy, Strategy|Mapping|array|mixed $expression)
511515

512516
> 'bar'
513517
518+
### Exists
519+
520+
Returns true or false if the resolved value of the strategy or the path exists.
521+
522+
#### Signature
523+
524+
```php
525+
Exists(Strategy|array|mixed $strategyOrPath)
526+
```
527+
528+
1. `$strategyOrPath` – Strategy, array of path components or string of `->`-delimited components.
529+
530+
#### Example
531+
532+
```php
533+
$data = ['foo' => 'bar']
534+
535+
(new Mapper)->map($data, new Exists('foo'));
536+
```
537+
538+
> true
539+
540+
```php
541+
(new Mapper)->map($data, new Exists('bar'));
542+
```
543+
544+
> false
545+
514546
### Filter
515547

516548
Filters null values or values rejected by the specified callback.
@@ -577,10 +609,42 @@ $data = [
577609

578610
> [1, 2, 3, 3, 4, 5]
579611
612+
### IfElse
613+
614+
Delegates to one expression or another depending on whether the specified condition loosely evaluates to true.
615+
616+
#### Signature
617+
618+
```php
619+
IfElse(Strategy $condition, Strategy|Mapping|array|mixed $if, Strategy|Mapping|array|mixed $else = null)
620+
```
621+
622+
1. `$condition` – Condition.
623+
2. `$if` – Expression used when condition loosely evaluates to true.
624+
3. `$else` – Expression used when condition loosely evaluates to false.
625+
626+
#### Example
627+
628+
```php
629+
$data = ['foo' => 'bar'];
630+
631+
(new Mapper)->map($data, new IfElse(new Exists('foo'), true, false));
632+
```
633+
634+
> true
635+
636+
```php
637+
(new Mapper)->map($data, new IfElse(new Exists('bar'), true, false));
638+
```
639+
640+
> false
641+
580642
### IfExists
581643

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

646+
Deprecated. Use IfElse and Exists strategies instead.
647+
584648
#### Signature
585649

586650
```php

src/Strategy/Either.php

Lines changed: 2 additions & 15 deletions
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 IfElse
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(new Exists($strategy), $strategy, $expression);
3118
}
3219
}

src/Strategy/Exists.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
namespace ScriptFUSION\Mapper\Strategy;
3+
4+
/**
5+
* Returns true or false if the resolved value of the strategy or the path exists.
6+
*/
7+
class Exists extends Delegate
8+
{
9+
/**
10+
* Initializes this instance with the specified strategy or path.
11+
*
12+
* @param Strategy|array|string $strategyOrPath Strategy, array of path components or string of `->`-delimited components.
13+
*/
14+
public function __construct($strategyOrPath)
15+
{
16+
parent::__construct($strategyOrPath instanceof Strategy ? $strategyOrPath : new Copy($strategyOrPath));
17+
}
18+
19+
/**
20+
* Return true when the strategy resolves to a non-null value, otherwise false.
21+
*
22+
* @param mixed $data
23+
* @param mixed $context
24+
*
25+
* @return mixed
26+
*/
27+
public function __invoke($data, $context = null)
28+
{
29+
return parent::__invoke($data, $context) !== null;
30+
}
31+
}

src/Strategy/IfElse.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
namespace ScriptFUSION\Mapper\Strategy;
3+
4+
use ScriptFUSION\Mapper\Mapping;
5+
6+
/**
7+
* Delegates to one expression or another depending on whether the specified condition loosely evaluates to true.
8+
*/
9+
class IfElse extends Delegate
10+
{
11+
/** @var Strategy|Mapping|array|mixed */
12+
private $if;
13+
14+
/** @var Strategy|Mapping|array|mixed */
15+
private $else;
16+
17+
/**
18+
* Initializes this instance with the specified condition, the specified
19+
* strategy or mapping to be resolved when condition is non-null and,
20+
* optionally, the specified strategy or mapping to be resolved when
21+
* condition is null.
22+
*
23+
* @param Strategy|Mapping|array|mixed $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($condition, $if, $else = null)
28+
{
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)) {
48+
return $this->delegate($this->if, $data, $context);
49+
}
50+
51+
if ($this->else !== null) {
52+
return $this->delegate($this->else, $data, $context);
53+
}
54+
}
55+
}

src/Strategy/IfExists.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
/**
77
* Delegates to one expression or another depending on whether the specified condition maps to null.
8+
*
9+
* @deprecated Use IfElse and Exists strategies instead.
810
*/
911
class IfExists extends Decorator
1012
{
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
namespace ScriptFUSIONTest\Integration\Mapper\Strategy;
3+
4+
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
5+
use ScriptFUSION\Mapper\Mapper;
6+
use ScriptFUSION\Mapper\Strategy\Exists;
7+
use ScriptFUSION\Mapper\Strategy\IfElse;
8+
use ScriptFUSION\Mapper\Strategy\IfExists;
9+
use ScriptFUSION\Mapper\Strategy\Strategy;
10+
11+
final class ExistsTest extends \PHPUnit_Framework_TestCase
12+
{
13+
use MockeryPHPUnitIntegration;
14+
15+
public function testPathString()
16+
{
17+
$exists = (new Exists('0->1'))->setMapper(new Mapper);
18+
19+
self::assertFalse($exists([]));
20+
self::assertFalse($exists(['a']));
21+
self::assertFalse($exists([['a']]));
22+
self::assertTrue($exists([['a','b']]));
23+
}
24+
25+
public function testPathArray()
26+
{
27+
$exists = (new Exists(['0', '1']))->setMapper(new Mapper);
28+
29+
self::assertFalse($exists([]));
30+
self::assertFalse($exists(['a']));
31+
self::assertFalse($exists([['a']]));
32+
self::assertTrue($exists([['a','b']]));
33+
}
34+
35+
public function testPathStrategy()
36+
{
37+
$exists = (new Exists(
38+
\Mockery::mock(Strategy::class)
39+
->shouldReceive('__invoke')
40+
->andReturn(true, false, null)
41+
->getMock()
42+
))->setMapper(new Mapper);
43+
44+
self::assertTrue($exists([]));
45+
self::assertTrue($exists([]));
46+
self::assertFalse($exists([]));
47+
}
48+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
namespace ScriptFUSIONTest\Integration\Mapper\Strategy;
3+
4+
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
5+
use ScriptFUSION\Mapper\Mapper;
6+
use ScriptFUSION\Mapper\Strategy\Exists;
7+
use ScriptFUSION\Mapper\Strategy\IfElse;
8+
use ScriptFUSION\Mapper\Strategy\Strategy;
9+
10+
final class IfElseTest extends \PHPUnit_Framework_TestCase
11+
{
12+
use MockeryPHPUnitIntegration;
13+
14+
public function testIfElse()
15+
{
16+
$ifExists = (
17+
new IfElse(
18+
\Mockery::mock(Strategy::class)
19+
->shouldReceive('__invoke')
20+
->andReturn(true, false, null)
21+
->getMock(),
22+
'foo',
23+
'bar'
24+
)
25+
)->setMapper(new Mapper);
26+
27+
self::assertSame('foo', $ifExists([]));
28+
self::assertSame('bar', $ifExists([]));
29+
self::assertSame('bar', $ifExists([]));
30+
}
31+
32+
public function testIfExistsElse()
33+
{
34+
$ifExists = (
35+
new IfElse(
36+
new Exists('0->1'),
37+
'foo',
38+
'bar'
39+
)
40+
)->setMapper(new Mapper);
41+
42+
self::assertSame('foo', $ifExists([['a', 'b']]));
43+
self::assertSame('bar', $ifExists([['a']]));
44+
self::assertSame('bar', $ifExists(['a']));
45+
self::assertSame('bar', $ifExists([]));
46+
}
47+
48+
public function testOnlyIf()
49+
{
50+
$ifElse = (
51+
new IfElse(
52+
\Mockery::mock(Strategy::class)
53+
->shouldReceive('__invoke')
54+
->andReturn(true, false, null)
55+
->getMock(),
56+
'foo'
57+
)
58+
)->setMapper(new Mapper);
59+
60+
self::assertSame('foo', $ifElse([]));
61+
self::assertNull($ifElse([]));
62+
self::assertNull($ifElse([]));
63+
}
64+
65+
}

0 commit comments

Comments
 (0)