Skip to content

Commit a5c3914

Browse files
committed
JsonMatcher introduction
1 parent 5fd095d commit a5c3914

File tree

5 files changed

+100
-44
lines changed

5 files changed

+100
-44
lines changed

src/JsonMatcher/Matcher/ArrayMatcher.php

Lines changed: 71 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Symfony\Component\PropertyAccess\PropertyAccess;
66
use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException;
7+
use Symfony\Component\PropertyAccess\PropertyAccessor;
78

89
class ArrayMatcher implements PropertyMatcher
910
{
@@ -14,6 +15,11 @@ class ArrayMatcher implements PropertyMatcher
1415

1516
private $paths;
1617

18+
/**
19+
* @var PropertyAccessor
20+
*/
21+
private $accessor;
22+
1723
public function __construct(PropertyMatcher $propertyMatcher)
1824
{
1925
$this->propertyMatcher = $propertyMatcher;
@@ -24,60 +30,94 @@ public function __construct(PropertyMatcher $propertyMatcher)
2430
*/
2531
public function match($value, $pattern)
2632
{
27-
$accessorBuilder = PropertyAccess::createPropertyAccessorBuilder();
28-
$accessorBuilder->enableExceptionOnInvalidIndex();
29-
$accessor = $accessorBuilder->getPropertyAccessor();
33+
if (!is_array($value)) {
34+
return false;
35+
}
36+
37+
if (false === $this->iterateMatch($value, $pattern)) {
38+
return false;
39+
}
40+
41+
return true;
42+
}
3043

31-
$this->paths = array();
44+
/**
45+
* {@inheritDoc}
46+
*/
47+
public function canMatch($pattern)
48+
{
49+
return is_array($pattern);
50+
}
51+
52+
/**
53+
* @param array $value
54+
* @param array $pattern
55+
* @return bool
56+
*/
57+
private function iterateMatch(array $value, array $pattern)
58+
{
3259
foreach ($value as $key => $element) {
3360
$path = sprintf("[%s]", $key);
3461

35-
if (is_array($element)) {
36-
$this->buildPath($element, $path);
37-
continue;
62+
if (!$this->hasValue($pattern, $path)) {
63+
return false;
64+
}
65+
$elementPattern = $this->getValue($pattern, $path);
66+
if ($this->propertyMatcher->canMatch($elementPattern)) {
67+
if (true === $this->propertyMatcher->match($element, $elementPattern)) {
68+
continue;
69+
}
3870
}
3971

40-
$this->paths[] = $path;
41-
}
42-
43-
foreach ($this->paths as $path) {
44-
$elementValue = $accessor->getValue($value, $path);
45-
try {
46-
$patternValue = $accessor->getValue($pattern, $path);
47-
} catch (NoSuchIndexException $e) {
72+
if (!is_array($element)) {
4873
return false;
4974
}
5075

51-
if ($this->propertyMatcher->canMatch($patternValue)) {
52-
if (false === $this->propertyMatcher->match($elementValue, $patternValue)) {
53-
return false;
54-
}
76+
if (false === $this->iterateMatch($element, $elementPattern)) {
77+
return false;
5578
}
79+
}
80+
}
5681

82+
/**
83+
* @param $array
84+
* @param $path
85+
* @return bool
86+
*/
87+
private function hasValue($array, $path)
88+
{
89+
try {
90+
$this->getPropertyAccessor()->getValue($array, $path);
91+
} catch (NoSuchIndexException $e) {
92+
return false;
5793
}
5894

5995
return true;
6096
}
6197

6298
/**
63-
* {@inheritDoc}
99+
* @param $array
100+
* @param $path
101+
* @return mixed
64102
*/
65-
public function canMatch($pattern)
103+
private function getValue($array, $path)
66104
{
67-
return is_array($pattern);
105+
return $this->getPropertyAccessor()->getValue($array, $path);
68106
}
69107

70-
private function buildPath(array $array, $parentPath)
108+
/**
109+
* @return \Symfony\Component\PropertyAccess\PropertyAccessorInterface
110+
*/
111+
private function getPropertyAccessor()
71112
{
72-
foreach ($array as $key => $element) {
73-
$path = sprintf("%s[%s]", $parentPath, $key);
113+
if (isset($this->accessor)) {
114+
return $this->accessor;
115+
}
74116

75-
if (is_array($element)) {
76-
$this->buildPath($element, $path);
77-
continue;
78-
}
117+
$accessorBuilder = PropertyAccess::createPropertyAccessorBuilder();
118+
$accessorBuilder->enableExceptionOnInvalidIndex();
119+
$this->accessor = $accessorBuilder->getPropertyAccessor();
79120

80-
$this->paths[] = $path;
81-
}
121+
return $this->accessor;
82122
}
83123
}

src/JsonMatcher/Matcher/TypeMatcher.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
class TypeMatcher implements PropertyMatcher
66
{
7-
87
/**
98
* {@inheritDoc}
109
*/
@@ -18,12 +17,11 @@ public function match($value, $pattern)
1817
*/
1918
public function canMatch($pattern)
2019
{
21-
return is_string($pattern) && 0 !== preg_match("/^@(string|integer|boolean|double)@$/", $pattern);
20+
return is_string($pattern) && 0 !== preg_match("/^@(string|integer|boolean|double|array)@$/", $pattern);
2221
}
2322

2423
private function extractType($pattern)
2524
{
2625
return str_replace("@", "", $pattern);
2726
}
28-
2927
}

tests/JsonMatcher/Matcher/ArrayMatcherTest.php

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,39 @@
44
use JsonMatcher\Matcher\ArrayMatcher;
55
use JsonMatcher\Matcher\ChainMatcher;
66
use JsonMatcher\Matcher\ScalarMatcher;
7+
use JsonMatcher\Matcher\WildcardMatcher;
78

89
class ArrayMatcherTest extends \PHPUnit_Framework_TestCase
910
{
11+
/**
12+
* @var ArrayMatcher
13+
*/
14+
private $matcher;
15+
16+
public function setUp()
17+
{
18+
$this->matcher = new ArrayMatcher(
19+
new ChainMatcher(array(
20+
new ScalarMatcher(),
21+
new WildcardMatcher()
22+
))
23+
);
24+
}
25+
1026
/**
1127
* @dataProvider positiveMatchData
1228
*/
1329
public function test_positive_match_arrays($value, $pattern)
1430
{
15-
$matcher = new ArrayMatcher(new ScalarMatcher());
16-
$this->assertTrue($matcher->match($value, $pattern));
31+
$this->assertTrue($this->matcher->match($value, $pattern));
1732
}
1833

1934
/**
2035
* @dataProvider negativeMatchData
2136
*/
2237
public function test_negative_match_arrays($value, $pattern)
2338
{
24-
$matcher = new ArrayMatcher(new ScalarMatcher());
25-
$this->assertFalse($matcher->match($value, $pattern));
39+
$this->assertFalse($this->matcher->match($value, $pattern));
2640
}
2741

2842
public static function positiveMatchData()
@@ -48,7 +62,8 @@ public static function positiveMatchData()
4862
array($simpleArr, $simpleArr),
4963
array(array(), array()),
5064
array(array('key' => 'val'), array('key' => 'val')),
51-
array(array(1), array(1))
65+
array(array(1), array(1)),
66+
array(array('roles' => array('ROLE_ADMIN', 'ROLE_DEVELOPER')), array('roles' => '@wildcard@'))
5267
);
5368
}
5469

tests/JsonMatcher/Matcher/JsonMatcherTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ public static function positiveMatches()
8585
'{"users":["@string@","@string@"]}'
8686
),
8787
array(
88-
'{"users":[{"firstName":"Norbert","lastName":"Orzechowicz","roles":["ROLE_USER"]}]}',
89-
'{"users":[{"firstName":"Norbert","lastName":"Orzechowicz","roles":["@wildcard@"]}]}'
88+
'{"users":[{"firstName":"Norbert","lastName":"Orzechowicz","roles":["ROLE_USER", "ROLE_DEVELOPER"]}]}',
89+
'{"users":[{"firstName":"Norbert","lastName":"Orzechowicz","roles":"@wildcard@"}]}'
9090
)
9191
);
9292
}

tests/JsonMatcher/Matcher/TypeMatcherTest.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ public static function positiveCanMatchData()
4747
array("@integer@"),
4848
array("@string@"),
4949
array("@boolean@"),
50-
array("@double@")
50+
array("@double@"),
51+
array("@array@")
5152
);
5253
}
5354

@@ -57,7 +58,8 @@ public static function positiveMatchData()
5758
array(false, "@boolean@"),
5859
array("Norbert", "@string@"),
5960
array(1, "@integer@"),
60-
array(6.66, "@double@")
61+
array(6.66, "@double@"),
62+
array(array('test'), '@array@')
6163
);
6264
}
6365

@@ -79,7 +81,8 @@ public static function negativeMatchData()
7981
array("test", "@boolean@"),
8082
array(new \stdClass, "@string@"),
8183
array(1.1, "@integer@"),
82-
array(false, "@double@")
84+
array(false, "@double@"),
85+
array(1, "@array@")
8386
);
8487
}
8588
}

0 commit comments

Comments
 (0)