Skip to content

Commit 674b4aa

Browse files
author
Paul
committed
Added CopyKey strategy, KeyAware interface and KeyAwareTrait.
Changed Mapper to forward keys to expressions. Changed Delegate to forward keys to mapper. Changed Collection to forward keys. Added unit and integration tests for CopyKey.
1 parent 8f58dd5 commit 674b4aa

9 files changed

Lines changed: 150 additions & 28 deletions

File tree

src/KeyAware.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
namespace ScriptFUSION\Mapper;
3+
4+
interface KeyAware
5+
{
6+
/**
7+
* Sets the key to the specified value.
8+
*
9+
* @param string|int $key Key.
10+
*
11+
* @return void
12+
*/
13+
public function setKey($key);
14+
}

src/KeyAwareTrait.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
namespace ScriptFUSION\Mapper;
3+
4+
trait KeyAwareTrait
5+
{
6+
/**
7+
* @var string|int
8+
*/
9+
private $key;
10+
11+
public function setKey($key)
12+
{
13+
$this->key = $key;
14+
}
15+
}

src/Mapper.php

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,24 @@ class Mapper
1414
*
1515
* @param array $record Record.
1616
* @param Strategy|Mapping|array|mixed $expression Expression.
17-
* @param mixed $context Context.
17+
* @param mixed $context Optional. Contextual data.
18+
* @param string|int|null $key Internal. Record key.
1819
*
1920
* @return mixed
2021
*
2122
* @throws InvalidExpressionException An invalid strategy or mapping object was specified.
2223
*/
23-
public function map(array $record, $expression, $context = null)
24+
public function map(array $record, $expression, $context = null, $key = null)
2425
{
2526
/* Strategy. */
2627
if ($expression instanceof Strategy) {
27-
return $this->mapStrategy($record, $expression, $context);
28+
return $this->mapStrategy($record, $expression, $context, $key);
2829
} /* Mapping. */
2930
elseif ($expression instanceof Mapping) {
30-
return $this->mapMapping($record, $expression, $context);
31+
return $this->mapMapping($record, $expression, $context, $key);
3132
} /* Mapping fragment. */
3233
elseif (is_array($expression)) {
33-
return $this->mapFragment($record, $expression, $context);
34+
return $this->mapFragment($record, $expression, $context, $key);
3435
} /* Null or scalar values. */
3536
elseif (null === $expression || is_scalar($expression)) {
3637
return $expression;
@@ -42,15 +43,16 @@ public function map(array $record, $expression, $context = null)
4243
/**
4344
* @param array $record Record.
4445
* @param Mapping $mapping Mapping.
45-
* @param mixed $context Contextual data.
46+
* @param mixed $context Optional. Contextual data.
47+
* @param string|int|null $key Internal. Record key.
4648
*
4749
* @return array Mapped record.
4850
*
4951
* @throws \Exception
5052
*/
51-
protected function mapMapping(array $record, Mapping $mapping, $context = null)
53+
protected function mapMapping(array $record, Mapping $mapping, $context = null, $key = null)
5254
{
53-
$mapped = $this->mapFragment($record, $mapping->toArray(), $context);
55+
$mapped = $this->mapFragment($record, $mapping->toArray(), $context, $key);
5456

5557
if ($mapping->isWrapped()) {
5658
// Unwrap.
@@ -60,12 +62,23 @@ protected function mapMapping(array $record, Mapping $mapping, $context = null)
6062
return $mapped;
6163
}
6264

63-
protected function mapFragment(array $record, array $fragment, $context = null)
65+
/**
66+
* @param array $record Record.
67+
* @param array $fragment Mapping.
68+
* @param null $context Optional. Contextual data.
69+
* @param string|int|null $key Internal. Record key.
70+
*
71+
* @return array Mapped record.
72+
*
73+
* @throws \Exception Mapping failed for an unknown reason.
74+
*/
75+
protected function mapFragment(array $record, array $fragment, $context = null, $key = null)
6476
{
6577
if (array_walk(
6678
$fragment,
67-
function (&$strategy, $key, array $record) use ($context) {
68-
$strategy = $this->map($record, $strategy, $context);
79+
// Mapping fragment keys are not useful because they are hard-coded.
80+
function (&$expression, $_, array $record) use ($context, $key) {
81+
$expression = $this->map($record, $expression, $context, $key);
6982
},
7083
$record
7184
)) {
@@ -76,14 +89,17 @@ function (&$strategy, $key, array $record) use ($context) {
7689
}
7790

7891
/**
79-
* @param array $record
80-
* @param Strategy $strategy
81-
* @param mixed $context
92+
* @param array $record Record.
93+
* @param Strategy $strategy Strategy.
94+
* @param mixed $context Optional. Contextual data.
95+
* @param string|int|null $key Internal. Record key.
8296
*
8397
* @return mixed
8498
*/
85-
protected function mapStrategy(array $record, Strategy $strategy, $context = null)
99+
protected function mapStrategy(array $record, Strategy $strategy, $context = null, $key = null)
86100
{
101+
$strategy instanceof KeyAware && $strategy->setKey($key);
102+
87103
$this->injectDependencies($strategy);
88104

89105
return $strategy($record, $context);

src/Strategy/Collection.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ public function __invoke($data, $context = null)
3131
return null;
3232
}
3333

34-
return array_map(function ($context) use ($data) {
35-
return $this->delegate($this->transformation, $data, $context);
36-
}, $collection);
34+
array_walk($collection, function (&$value, $key) use ($data) {
35+
$value = $this->delegate($this->transformation, $data, $value, $key);
36+
});
37+
38+
return $collection;
3739
}
3840
}

src/Strategy/CopyKey.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
namespace ScriptFUSION\Mapper\Strategy;
3+
4+
use ScriptFUSION\Mapper\KeyAware;
5+
use ScriptFUSION\Mapper\KeyAwareTrait;
6+
7+
/**
8+
* Copies the current key.
9+
*/
10+
class CopyKey implements Strategy, KeyAware
11+
{
12+
use KeyAwareTrait;
13+
14+
public function __invoke($data, $context = null)
15+
{
16+
return $this->key;
17+
}
18+
}

src/Strategy/Delegate.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ public function __invoke($data, $context = null)
2424
return $this->delegate($this->expression, $data, $context);
2525
}
2626

27-
protected function delegate($strategy, $data, $context)
27+
protected function delegate($strategy, $data, $context, $key = null)
2828
{
29-
return $this->mapper->map($data, $strategy, $context);
29+
return $this->mapper->map($data, $strategy, $context, $key);
3030
}
3131
}

test/Integration/Mapper/Strategy/CollectionTest.php

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,26 @@ public function testCollection()
2020
{
2121
/** @var Collection $collection */
2222
$collection = (new Collection(
23-
$this->createCollection('foo'),
23+
$this->createArray('foo'),
2424
[
2525
'bar' => new CopyContext('foo'),
2626
]
2727
))->setMapper(new Mapper);
2828

29-
self::assertSame($this->createCollection('bar'), $collection([]));
29+
self::assertSame($this->createArray('bar'), $collection([]));
3030
}
3131

32-
private function createCollection($key)
32+
private function createArray($key)
3333
{
34-
return array_map(
35-
function ($number) use ($key) {
36-
return [$key => $number];
37-
},
38-
range(1, 10)
34+
return array_combine(
35+
// Keys must not change.
36+
range('a', 'j'),
37+
array_map(
38+
function ($number) use ($key) {
39+
return [$key => $number];
40+
},
41+
range('k', 't')
42+
)
3943
);
4044
}
4145
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
namespace ScriptFUSIONTest\Integration\Mapper\Strategy;
3+
4+
use ScriptFUSION\Mapper\Mapper;
5+
use ScriptFUSION\Mapper\Strategy\Collection;
6+
use ScriptFUSION\Mapper\Strategy\Copy;
7+
use ScriptFUSION\Mapper\Strategy\CopyKey;
8+
9+
final class CopyKeyTest extends \PHPUnit_Framework_TestCase
10+
{
11+
public function test()
12+
{
13+
$mapped = (new Mapper)->map(
14+
[
15+
'foo' => 'bar',
16+
'baz' => [
17+
'qux' => 'quux',
18+
'corge' => 123,
19+
],
20+
],
21+
[
22+
'foo' => new CopyKey,
23+
'bar' => new Collection(
24+
new Copy('baz'),
25+
new CopyKey
26+
),
27+
]
28+
);
29+
30+
self::assertSame([
31+
'foo' => null,
32+
'bar' => [
33+
'qux' => 'qux',
34+
'corge' => 'corge',
35+
],
36+
], $mapped);
37+
}
38+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
namespace ScriptFUSIONTest\Unit\Mapper\Strategy;
3+
4+
use ScriptFUSION\Mapper\Strategy\CopyKey;
5+
6+
final class CopyKeyTest extends \PHPUnit_Framework_TestCase
7+
{
8+
public function testRoundTrip()
9+
{
10+
$copyKey = new CopyKey;
11+
$copyKey->setKey($key = 'foo');
12+
13+
self::assertSame($key, $copyKey([]));
14+
}
15+
}

0 commit comments

Comments
 (0)