@@ -19,6 +19,9 @@ class ArrayMatcher extends Matcher
19
19
*/
20
20
private $ accessor ;
21
21
22
+ /**
23
+ * @param PropertyMatcher $propertyMatcher
24
+ */
22
25
public function __construct (PropertyMatcher $ propertyMatcher )
23
26
{
24
27
$ this ->propertyMatcher = $ propertyMatcher ;
@@ -49,68 +52,109 @@ public function canMatch($pattern)
49
52
}
50
53
51
54
/**
52
- * @param array $value
53
- * @param array $pattern
55
+ * @param array $values
56
+ * @param array $patterns
54
57
* @param string $parentPath
55
58
* @return bool
56
59
*/
57
- private function iterateMatch (array $ value , array $ pattern , $ parentPath = "" )
60
+ private function iterateMatch (array $ values , array $ patterns , $ parentPath = "" )
58
61
{
59
- $ lastPattern = array_values ($ pattern );
60
- $ unboundedMode = end ($ lastPattern ) === self ::UNBOUNDED_PATTERN ;
62
+ $ pattern = null ;
63
+ foreach ($ values as $ key => $ value ) {
64
+ $ path = $ this ->formatAccessPath ($ key );
61
65
62
- if ($ unboundedMode ) {
63
- $ unboundedPattern = prev ($ lastPattern );
64
- array_pop ($ pattern );
65
- }
66
-
67
- foreach ($ value as $ key => $ element ) {
68
- $ path = sprintf ("[%s] " , $ key );
66
+ if ($ this ->shouldSkippValueMatchingFor ($ pattern )) {
67
+ continue ;
68
+ }
69
69
70
- if ($ this ->hasValue ($ pattern , $ path )) {
71
- $ elementPattern = $ this ->getValue ($ pattern , $ path );
72
- } else if ($ unboundedMode ) {
73
- $ elementPattern = $ unboundedPattern ;
70
+ if ($ this ->valueExist ($ path , $ patterns )) {
71
+ $ pattern = $ this ->getValueByPath ($ patterns , $ path );
74
72
} else {
75
- $ this ->error = sprintf ( ' There is no element under path %s%s in pattern. ' , $ parentPath , $ path );
73
+ $ this ->setMissingElementInError ( ' pattern ' , $ this -> formatFullPath ( $ parentPath , $ path) );
76
74
return false ;
77
75
}
78
76
79
- if ($ this ->propertyMatcher ->canMatch ($ elementPattern )) {
80
- if (true === $ this ->propertyMatcher ->match ($ element , $ elementPattern )) {
81
- continue ;
82
- }
77
+ if ($ this ->shouldSkippValueMatchingFor ($ pattern )) {
78
+ continue ;
83
79
}
84
80
85
- if (!is_array ($ element ) || !is_array ($ elementPattern )) {
86
- $ this ->error = $ this ->propertyMatcher ->getError ();
81
+ if ($ this ->valueMatchPattern ($ value , $ pattern )) {
82
+ continue ;
83
+ }
84
+
85
+ if (!is_array ($ value ) || !$ this ->canMatch ($ pattern )) {
87
86
return false ;
88
87
}
89
88
90
- if (false === $ this ->iterateMatch ($ element , $ elementPattern , $ parentPath . $ path )) {
89
+ if (false === $ this ->iterateMatch ($ value , $ pattern , $ this -> formatFullPath ( $ parentPath, $ path) )) {
91
90
return false ;
92
91
}
93
92
}
94
93
95
- return $ this ->checkIfPathsFromPatternExistInValue ($ value , $ pattern , $ parentPath );
94
+ if (!$ this ->isPatternValid ($ patterns , $ values , $ parentPath )) {
95
+ return false ;
96
+ }
97
+
98
+ return true ;
99
+ }
100
+
101
+ /**
102
+ * Check if pattern elements exist in value array
103
+ *
104
+ * @param array $pattern
105
+ * @param array $values
106
+ * @param $parentPath
107
+ * @return bool
108
+ */
109
+ private function isPatternValid (array $ pattern , array $ values , $ parentPath )
110
+ {
111
+ if (is_array ($ pattern )) {
112
+ $ notExistingKeys = array_diff_key ($ pattern , $ values );
113
+
114
+ if (count ($ notExistingKeys ) > 0 ) {
115
+ $ keyNames = array_keys ($ notExistingKeys );
116
+ $ path = $ this ->formatFullPath ($ parentPath , $ this ->formatAccessPath ($ keyNames [0 ]));
117
+ $ this ->setMissingElementInError ('value ' , $ path );
118
+ return false ;
119
+ }
120
+ }
121
+
122
+ return true ;
123
+ }
124
+
125
+ /**
126
+ * @param $value
127
+ * @param $pattern
128
+ * @return bool
129
+ */
130
+ private function valueMatchPattern ($ value , $ pattern )
131
+ {
132
+ $ match = $ this ->propertyMatcher ->canMatch ($ pattern ) &&
133
+ true === $ this ->propertyMatcher ->match ($ value , $ pattern );
134
+
135
+ if (!$ match ) {
136
+ $ this ->error = $ this ->propertyMatcher ->getError ();
137
+ }
138
+
139
+ return $ match ;
96
140
}
97
141
98
142
/**
99
- * @param $array
100
143
* @param $path
144
+ * @param $haystack
101
145
* @return bool
102
146
*/
103
- private function hasValue ( $ array , $ path )
147
+ private function valueExist ( $ path , array $ haystack )
104
148
{
105
- return null !== $ this ->getPropertyAccessor ()->getValue ($ array , $ path );
149
+ return null !== $ this ->getPropertyAccessor ()->getValue ($ haystack , $ path );
106
150
}
107
151
108
152
/**
109
153
* @param $array
110
154
* @param $path
111
155
* @return mixed
112
156
*/
113
- private function getValue ($ array , $ path )
157
+ private function getValueByPath ($ array , $ path )
114
158
{
115
159
return $ this ->getPropertyAccessor ()->getValue ($ array , $ path );
116
160
}
@@ -131,23 +175,39 @@ private function getPropertyAccessor()
131
175
}
132
176
133
177
/**
134
- * @param array $value
135
- * @param array $pattern
136
- * @param $parentPath
137
- * @return bool
178
+ * @param $place
179
+ * @param $path
138
180
*/
139
- private function checkIfPathsFromPatternExistInValue ( array $ value , array $ pattern , $ parentPath )
181
+ private function setMissingElementInError ( $ place , $ path )
140
182
{
141
- if ( is_array ( $ pattern )) {
142
- $ notExistingKeys = array_diff_key ( $ pattern , $ value );
183
+ $ this -> error = sprintf ( ' There is no element under path %s in %s. ' , $ path , $ place );
184
+ }
143
185
144
- if (count ($ notExistingKeys ) > 0 ) {
145
- $ keyNames = array_keys ($ notExistingKeys );
146
- $ this ->error = sprintf ('There is no element under path %s[%s] in value. ' , $ parentPath , $ keyNames [0 ]);
147
- return false ;
148
- }
149
- }
186
+ /**
187
+ * @param $key
188
+ * @return string
189
+ */
190
+ private function formatAccessPath ($ key )
191
+ {
192
+ return sprintf ("[%s] " , $ key );;
193
+ }
150
194
151
- return true ;
195
+ /**
196
+ * @param $parentPath
197
+ * @param $path
198
+ * @return string
199
+ */
200
+ private function formatFullPath ($ parentPath , $ path )
201
+ {
202
+ return sprintf ("%s%s " , $ parentPath , $ path );
203
+ }
204
+
205
+ /**
206
+ * @param $lastPattern
207
+ * @return bool
208
+ */
209
+ private function shouldSkippValueMatchingFor ($ lastPattern )
210
+ {
211
+ return $ lastPattern === self ::UNBOUNDED_PATTERN ;
152
212
}
153
213
}
0 commit comments