Skip to content

Commit 3f54780

Browse files
teklakctnorberttech
authored andcommitted
Allow to mark JSON properties & XML nodes as optional (#102)
* Add optional expander definition * Add hasExpander method for Pattern * Allow mark JSON properties & xml nodes as optional * Use intuitive matcher type definition in Xml test stock qty node definition * Add information about optional Expander to README * Remove return type declaration * Catch PHPMatcher Exception when parsing pattern for optional values * Add getName to PatternExpander interface * Remove unncessary ExpanderInitializer dependency in TypePattern * Use constants for expander name instead of method * Redeclare $expanderDefinitions using constants * Add static is($name) method to PatternExpander interface
1 parent 6c60f49 commit 3f54780

24 files changed

+501
-27
lines changed

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ $matcher->getError(); // returns null or error message
8383
* ``inArray($value)``
8484
* ``oneOf(...$expanders)`` - example usage ``"@[email protected](contains('foo'), contains('bar'), contains('baz'))"``
8585
* ``matchRegex($regex)`` - example usage ``"@[email protected]('/^lorem.+/')"``
86+
* ``optional()`` - work's only with ``ArrayMatcher``, ``JsonMatcher`` and ``XmlMatcher``
8687

8788
##Example usage
8889

@@ -237,7 +238,8 @@ $matcher->match(
237238
'id' => 1,
238239
'firstName' => 'Norbert',
239240
'lastName' => 'Orzechowicz',
240-
'roles' => array('ROLE_USER')
241+
'roles' => array('ROLE_USER'),
242+
'position' => 'Developer',
241243
),
242244
array(
243245
'id' => 2,
@@ -261,7 +263,8 @@ $matcher->match(
261263
'id' => '@[email protected](0)',
262264
'firstName' => '@string@',
263265
'lastName' => 'Orzechowicz',
264-
'roles' => '@array@'
266+
'roles' => '@array@',
267+
'position' => '@[email protected]()'
265268
),
266269
array(
267270
'id' => '@integer@',
@@ -303,7 +306,8 @@ $matcher->match(
303306
"firstName": @string@,
304307
"lastName": @string@,
305308
"created": "@[email protected]()",
306-
"roles": @array@
309+
"roles": @array@,
310+
"posiiton": "@[email protected]()"
307311
}
308312
]
309313
}'
@@ -347,6 +351,7 @@ XML
347351
<m:GetStockPrice>
348352
<m:StockName>@string@</m:StockName>
349353
<m:StockValue>@string@</m:StockValue>
354+
<m:StockQty>@[email protected]()</m:StockQty>
350355
</m:GetStockPrice>
351356
</soap:Body>
352357

src/Matcher/ArrayMatcher.php

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Coduo\PHPMatcher\Matcher;
44

5+
use Coduo\PHPMatcher\Exception\Exception;
56
use Coduo\PHPMatcher\Parser;
67
use Coduo\ToString\StringConverter;
78
use Symfony\Component\PropertyAccess\PropertyAccess;
@@ -144,19 +145,56 @@ private function iterateMatch(array $values, array $patterns, $parentPath = "")
144145
private function isPatternValid(array $pattern, array $values, $parentPath)
145146
{
146147
if (is_array($pattern)) {
147-
$notExistingKeys = array_diff_key($pattern, $values);
148+
$skipPattern = static::UNBOUNDED_PATTERN;
149+
150+
$pattern = array_filter(
151+
$pattern,
152+
function ($item) use ($skipPattern) {
153+
return $item !== $skipPattern;
154+
}
155+
);
156+
157+
$notExistingKeys = $this->findNotExistingKeys($pattern, $values);
148158

149159
if (count($notExistingKeys) > 0) {
150160
$keyNames = array_keys($notExistingKeys);
151161
$path = $this->formatFullPath($parentPath, $this->formatAccessPath($keyNames[0]));
152162
$this->setMissingElementInError('value', $path);
163+
153164
return false;
154165
}
155166
}
156167

157168
return true;
158169
}
159170

171+
/**
172+
* Finds not existing keys
173+
* Excludes keys with pattern which includes Optional Expander
174+
*
175+
* @param $pattern
176+
* @param $values
177+
* @return array
178+
*/
179+
private function findNotExistingKeys($pattern, $values)
180+
{
181+
$notExistingKeys = array_diff_key($pattern, $values);
182+
183+
return array_filter($notExistingKeys, function ($pattern) use ($values) {
184+
if (is_array($pattern)) {
185+
return !$this->match($values, $pattern);
186+
}
187+
188+
try {
189+
$typePattern = $this->parser->parse($pattern);
190+
} catch (Exception $e) {
191+
return true;
192+
}
193+
194+
return !$typePattern->hasExpander('optional');
195+
});
196+
}
197+
160198
/**
161199
* @param $value
162200
* @param $pattern

src/Matcher/Pattern/Expander/Contains.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
final class Contains implements PatternExpander
99
{
10+
const NAME = 'contains';
11+
1012
/**
1113
* @var null|string
1214
*/
@@ -22,6 +24,14 @@ final class Contains implements PatternExpander
2224
*/
2325
private $ignoreCase;
2426

27+
/**
28+
* {@inheritdoc}
29+
*/
30+
public static function is(string $name)
31+
{
32+
return self::NAME === $name;
33+
}
34+
2535
/**
2636
* @param $string
2737
* @param bool $ignoreCase

src/Matcher/Pattern/Expander/Count.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
final class Count implements PatternExpander
99
{
10+
const NAME = 'count';
11+
1012
/**
1113
* @var null|string
1214
*/
@@ -17,6 +19,14 @@ final class Count implements PatternExpander
1719
*/
1820
private $value;
1921

22+
/**
23+
* {@inheritdoc}
24+
*/
25+
public static function is(string $name)
26+
{
27+
return self::NAME === $name;
28+
}
29+
2030
/**
2131
* @param $value
2232
*/

src/Matcher/Pattern/Expander/EndsWith.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
final class EndsWith implements PatternExpander
99
{
10+
const NAME = 'endsWith';
11+
1012
/**
1113
* @var
1214
*/
@@ -22,6 +24,14 @@ final class EndsWith implements PatternExpander
2224
*/
2325
private $ignoreCase;
2426

27+
/**
28+
* {@inheritdoc}
29+
*/
30+
public static function is(string $name)
31+
{
32+
return self::NAME === $name;
33+
}
34+
2535
/**
2636
* @param string $stringEnding
2737
* @param bool $ignoreCase

src/Matcher/Pattern/Expander/GreaterThan.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
final class GreaterThan implements PatternExpander
99
{
10+
const NAME = 'greaterThan';
11+
1012
/**
1113
* @var
1214
*/
@@ -17,6 +19,14 @@ final class GreaterThan implements PatternExpander
1719
*/
1820
private $error;
1921

22+
/**
23+
* {@inheritdoc}
24+
*/
25+
public static function is(string $name)
26+
{
27+
return self::NAME === $name;
28+
}
29+
2030
/**
2131
* @param $boundary
2232
*/

src/Matcher/Pattern/Expander/InArray.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
final class InArray implements PatternExpander
99
{
10+
const NAME = 'inArray';
11+
1012
/**
1113
* @var null|string
1214
*/
@@ -17,6 +19,14 @@ final class InArray implements PatternExpander
1719
*/
1820
private $value;
1921

22+
/**
23+
* {@inheritdoc}
24+
*/
25+
public static function is(string $name)
26+
{
27+
return self::NAME === $name;
28+
}
29+
2030
/**
2131
* @param $value
2232
*/

src/Matcher/Pattern/Expander/IsDateTime.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,21 @@
77

88
final class IsDateTime implements PatternExpander
99
{
10+
const NAME = 'isDateTime';
11+
1012
/**
1113
* @var null|string
1214
*/
1315
private $error;
1416

17+
/**
18+
* {@inheritdoc}
19+
*/
20+
public static function is(string $name)
21+
{
22+
return self::NAME === $name;
23+
}
24+
1525
/**
1626
* @param string $value
1727
* @return boolean

src/Matcher/Pattern/Expander/IsEmail.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,21 @@
77

88
final class IsEmail implements PatternExpander
99
{
10+
const NAME = 'isEmail';
11+
1012
/**
1113
* @var null|string
1214
*/
1315
private $error;
1416

17+
/**
18+
* {@inheritdoc}
19+
*/
20+
public static function is(string $name)
21+
{
22+
return self::NAME === $name;
23+
}
24+
1525
/**
1626
* @param string $value
1727
* @return boolean

src/Matcher/Pattern/Expander/IsEmpty.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,18 @@
77

88
final class IsEmpty implements PatternExpander
99
{
10+
const NAME = 'isEmpty';
11+
1012
private $error;
1113

14+
/**
15+
* {@inheritdoc}
16+
*/
17+
public static function is(string $name)
18+
{
19+
return self::NAME === $name;
20+
}
21+
1222
/**
1323
* @param mixed $value
1424
*

src/Matcher/Pattern/Expander/IsNotEmpty.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,18 @@
77

88
final class IsNotEmpty implements PatternExpander
99
{
10+
const NAME = 'isNotEmpty';
11+
1012
private $error;
1113

14+
/**
15+
* {@inheritdoc}
16+
*/
17+
public static function is(string $name)
18+
{
19+
return self::NAME === $name;
20+
}
21+
1222
/**
1323
* @param $value
1424
* @return boolean

src/Matcher/Pattern/Expander/IsUrl.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,21 @@
77

88
final class IsUrl implements PatternExpander
99
{
10+
const NAME = 'isUrl';
11+
1012
/**
1113
* @var null|string
1214
*/
1315
private $error;
1416

17+
/**
18+
* {@inheritdoc}
19+
*/
20+
public static function is(string $name)
21+
{
22+
return self::NAME === $name;
23+
}
24+
1525
/**
1626
* @param string $value
1727
* @return boolean

src/Matcher/Pattern/Expander/LowerThan.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
final class LowerThan implements PatternExpander
99
{
10+
const NAME = 'lowerThan';
11+
1012
/**
1113
* @var
1214
*/
@@ -17,6 +19,14 @@ final class LowerThan implements PatternExpander
1719
*/
1820
private $error;
1921

22+
/**
23+
* {@inheritdoc}
24+
*/
25+
public static function is(string $name)
26+
{
27+
return self::NAME === $name;
28+
}
29+
2030
/**
2131
* @param $boundary
2232
*/

src/Matcher/Pattern/Expander/MatchRegex.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
final class MatchRegex implements PatternExpander
99
{
10+
const NAME = 'matchRegex';
11+
1012
/**
1113
* @var null|string
1214
*/
@@ -17,6 +19,14 @@ final class MatchRegex implements PatternExpander
1719
*/
1820
private $pattern;
1921

22+
/**
23+
* {@inheritdoc}
24+
*/
25+
public static function is(string $name)
26+
{
27+
return self::NAME === $name;
28+
}
29+
2030
/**
2131
* @param string $pattern
2232
*/

0 commit comments

Comments
 (0)