Skip to content

Commit 9792608

Browse files
author
Paul
committed
Added support for stategies and mappings in Copy path.
Also affects CopyContext and Walk paths in the same way. Updated readme and tests. Deprecated Translate because it can now be achieved with just Walk.
1 parent 361843e commit 9792608

File tree

12 files changed

+147
-63
lines changed

12 files changed

+147
-63
lines changed

README.md

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -317,17 +317,17 @@ The following strategies ship with Mapper and provide a suite of commonly used f
317317

318318
### Copy
319319

320-
Copy copies a portion of the input data with support for nested structures.
320+
Copies a portion of the input data according to the specified path. Supports traversing nested arrays.
321321

322-
Copy is probably the most common strategy whether used by itself or injected into other strategies.
322+
`Copy` is probably the most common strategy whether used by itself or injected into other strategies.
323323

324324
#### Signature
325325

326326
```php
327-
Copy(array|string $path)
327+
Copy(Strategy|Mapping|array|mixed $path)
328328
```
329329

330-
1. `$path` – Array of path components or string of `->`-delimited components.
330+
1. `$path` – Array of path components, string of `->`-delimited path components or a strategy or mapping resolving to such an expression.
331331

332332
#### Example
333333

@@ -351,17 +351,35 @@ $data = [
351351

352352
> 123
353353
354+
#### Path resolver example
355+
356+
Since the path can be derived from other strategies we could nest `Copy` instances to look up values referenced by other keys.
357+
358+
```php
359+
(new Mapper)->map(
360+
[
361+
'foo' => 'bar',
362+
'bar' => 'baz',
363+
'baz' => 'qux',
364+
],
365+
new Copy(new Copy(new Copy('foo')))
366+
);
367+
```
368+
369+
> 'qux'
370+
354371
### CopyContext
355372

356373
Copies a portion of context data; works exactly the same way as `Copy` in all other respects.
357374

358375
#### Signature
359376

360377
```php
361-
CopyContext(array|string $path)
378+
CopyContext(Strategy|Mapping|array|mixed $path)
362379
```
363380

364-
1. `$path` – Array of path components or string of `->`-delimited components.
381+
1. `$path` – Array of path components, string of `->`-delimited path components or a strategy or mapping resolving to such an expression.
382+
365383

366384
#### Example
367385

@@ -871,11 +889,11 @@ Walks a nested structure to the specified element in the same manner as [`Copy`]
871889
#### Signature
872890

873891
```php
874-
Walk(Strategy|Mapping|array|mixed $expression, array|string $path)
892+
Walk(Strategy|Mapping|array|mixed $expression, Strategy|Mapping|array|mixed $path)
875893
```
876894

877-
1. `$expression` – Expression.
878-
2. `$path` Array of path components or string of `->`-delimited components.
895+
1. `$expression` – Expression to walk.
896+
2. `$path` – Array of path components, string of `->`-delimited path components or a strategy or mapping resolving to such an expression.
879897

880898
#### Example
881899

src/Mapper.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,24 @@ class Mapper
2525
*/
2626
public function map(array $record, $expression, $context = null, $key = null)
2727
{
28-
/* Strategy. */
28+
// Null or scalar values.
29+
if (null === $expression || is_scalar($expression)) {
30+
return $expression;
31+
}
32+
33+
// Strategy.
2934
if ($expression instanceof Strategy) {
3035
return $this->mapStrategy($record, $expression, $context, $key);
31-
} /* Mapping. */
32-
elseif ($expression instanceof Mapping) {
36+
}
37+
38+
// Mapping.
39+
if ($expression instanceof Mapping) {
3340
return $this->mapMapping($record, $expression, $context, $key);
34-
} /* Mapping fragment. */
35-
elseif (is_array($expression)) {
41+
}
42+
43+
// Mapping fragment.
44+
if (is_array($expression)) {
3645
return $this->mapFragment($record, $expression, $context, $key);
37-
} /* Null or scalar values. */
38-
elseif (null === $expression || is_scalar($expression)) {
39-
return $expression;
4046
}
4147

4248
throw new InvalidExpressionException('Invalid strategy or mapping: "' . get_class($expression) . '".');

src/Strategy/Copy.php

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,10 @@
66
/**
77
* Copies a portion of input data.
88
*/
9-
class Copy implements Strategy
9+
class Copy extends Delegate
1010
{
1111
const PATH_SEPARATOR = '->';
1212

13-
private $path;
14-
15-
/**
16-
* Initializes this instance with the specified path.
17-
*
18-
* @param array|string $path Array of path components or string of `->`-delimited components.
19-
*/
20-
public function __construct($path)
21-
{
22-
$this->path = is_array($path) ? $path : explode(self::PATH_SEPARATOR, $path);
23-
}
24-
2513
/**
2614
* @param mixed $data
2715
* @param mixed $context
@@ -30,8 +18,14 @@ public function __construct($path)
3018
*/
3119
public function __invoke($data, $context = null)
3220
{
33-
if ($this->path && is_array($data)) {
34-
return ArrayWalker::walk($data, $this->path);
21+
if (!is_array($data)) {
22+
return null;
3523
}
24+
25+
if (!is_array($path = parent::__invoke($data, $context))) {
26+
$path = explode(self::PATH_SEPARATOR, $path);
27+
}
28+
29+
return $path ? ArrayWalker::walk($data, $path) : null;
3630
}
3731
}

src/Strategy/CopyContext.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<?php
22
namespace ScriptFUSION\Mapper\Strategy;
33

4+
use ScriptFUSION\Mapper\Mapping;
5+
46
/**
57
* Copies a portion of context data.
68
*/
@@ -11,7 +13,8 @@ class CopyContext extends Copy
1113
/**
1214
* {@inheritdoc}
1315
*
14-
* @param array|string $path Array of path components or string of `->`-delimited components.
16+
* @param Strategy|Mapping|array|mixed $path Array of path components, string of `->`-delimited path components or
17+
* a strategy or mapping resolving to such an expression.
1518
*/
1619
public function __construct($path = null)
1720
{

src/Strategy/Translate.php

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

66
/**
77
* Translates a value using a mapping.
8+
*
9+
* @deprecated Use Walk instead.
810
*/
911
class Translate extends Decorator
1012
{

src/Strategy/Walk.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22
namespace ScriptFUSION\Mapper\Strategy;
33

4+
use ScriptFUSION\Mapper\Mapper;
45
use ScriptFUSION\Mapper\Mapping;
56

67
/**
@@ -14,8 +15,9 @@ class Walk extends Delegate
1415
private $copy;
1516

1617
/**
17-
* @param Strategy|Mapping|array|mixed $expression Expression.
18-
* @param array|string $path Array of path components or string of `->`-delimited components.
18+
* @param Strategy|Mapping|array|mixed $expression Expression to walk.
19+
* @param Strategy|Mapping|array|mixed $path Array of path components, string of `->`-delimited path components or
20+
* a strategy or mapping resolving to such an expression.
1921
*/
2022
public function __construct($expression, $path)
2123
{
@@ -28,4 +30,11 @@ public function __invoke($data, $context = null)
2830
{
2931
return call_user_func($this->copy, parent::__invoke($data, $context), $context);
3032
}
33+
34+
public function setMapper(Mapper $mapper)
35+
{
36+
$this->copy->setMapper($mapper);
37+
38+
return parent::setMapper($mapper);
39+
}
3140
}

test/Functional/DocumentationTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,21 @@ public function testCopy()
100100
self::assertSame($bar, (new Mapper)->map($data, new Copy(['foo', 'bar'])));
101101
}
102102

103+
public function testNestedCopy()
104+
{
105+
self::assertSame(
106+
'qux',
107+
(new Mapper)->map(
108+
[
109+
'foo' => 'bar',
110+
'bar' => 'baz',
111+
'baz' => 'qux',
112+
],
113+
new Copy(new Copy(new Copy('foo')))
114+
)
115+
);
116+
}
117+
103118
public function testCopyContext()
104119
{
105120
$data = ['foo' => 123];

test/Integration/Mapper/Strategy/DebugTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ protected function setUp()
1414
self::$debugged = false;
1515
}
1616

17+
/**
18+
* Tests that the strategy can be created with no arguments.
19+
*/
20+
public function testNoArguments()
21+
{
22+
new Debug;
23+
}
24+
1725
/**
1826
* Tests that expressions are delegated to Mapper.
1927
*/
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
namespace ScriptFUSIONTest\Integration\Mapper\Strategy;
3+
4+
use ScriptFUSION\Mapper\Mapper;
5+
use ScriptFUSION\Mapper\Strategy\Walk;
6+
7+
final class WalkTest extends \PHPUnit_Framework_TestCase
8+
{
9+
public function testWalk()
10+
{
11+
/** @var Walk $walk */
12+
$walk = (new Walk(['foo' => ['bar' => 'baz']], 'foo->bar'))
13+
->setMapper(new Mapper)
14+
;
15+
16+
self::assertSame('baz', $walk([]));
17+
}
18+
}

test/Unit/Mapper/Strategy/CopyContextTest.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,26 @@
22
namespace ScriptFUSIONTest\Unit\Mapper\Strategy;
33

44
use ScriptFUSION\Mapper\Strategy\CopyContext;
5+
use ScriptFUSIONTest\MockFactory;
56

67
final class CopyContextTest extends \PHPUnit_Framework_TestCase
78
{
89
public function testNoPath()
910
{
10-
$copyContext = new CopyContext;
11+
$copyContext = self::createStrategy(null);
1112

1213
self::assertSame('foo', $copyContext(null, 'foo'));
1314
}
1415

1516
public function testPath()
1617
{
17-
$copyContext = new CopyContext('foo->bar');
18+
$copyContext = self::createStrategy('foo->bar');
1819

1920
self::assertSame('baz', $copyContext(null, ['foo' => ['bar' => 'baz']]));
2021
}
22+
23+
private static function createStrategy($path)
24+
{
25+
return (new CopyContext($path))->setMapper(MockFactory::mockMapper($path));
26+
}
2127
}

0 commit comments

Comments
 (0)