@@ -19,6 +19,9 @@ class ArrayMatcher extends Matcher
1919 */
2020 private $ accessor ;
2121
22+ /**
23+ * @param PropertyMatcher $propertyMatcher
24+ */
2225 public function __construct (PropertyMatcher $ propertyMatcher )
2326 {
2427 $ this ->propertyMatcher = $ propertyMatcher ;
@@ -49,68 +52,109 @@ public function canMatch($pattern)
4952 }
5053
5154 /**
52- * @param array $value
53- * @param array $pattern
55+ * @param array $values
56+ * @param array $patterns
5457 * @param string $parentPath
5558 * @return bool
5659 */
57- private function iterateMatch (array $ value , array $ pattern , $ parentPath = "" )
60+ private function iterateMatch (array $ values , array $ patterns , $ parentPath = "" )
5861 {
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 );
6165
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+ }
6969
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 );
7472 } 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) );
7674 return false ;
7775 }
7876
79- if ($ this ->propertyMatcher ->canMatch ($ elementPattern )) {
80- if (true === $ this ->propertyMatcher ->match ($ element , $ elementPattern )) {
81- continue ;
82- }
77+ if ($ this ->shouldSkippValueMatchingFor ($ pattern )) {
78+ continue ;
8379 }
8480
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 )) {
8786 return false ;
8887 }
8988
90- if (false === $ this ->iterateMatch ($ element , $ elementPattern , $ parentPath . $ path )) {
89+ if (false === $ this ->iterateMatch ($ value , $ pattern , $ this -> formatFullPath ( $ parentPath, $ path) )) {
9190 return false ;
9291 }
9392 }
9493
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 ;
96140 }
97141
98142 /**
99- * @param $array
100143 * @param $path
144+ * @param $haystack
101145 * @return bool
102146 */
103- private function hasValue ( $ array , $ path )
147+ private function valueExist ( $ path , array $ haystack )
104148 {
105- return null !== $ this ->getPropertyAccessor ()->getValue ($ array , $ path );
149+ return null !== $ this ->getPropertyAccessor ()->getValue ($ haystack , $ path );
106150 }
107151
108152 /**
109153 * @param $array
110154 * @param $path
111155 * @return mixed
112156 */
113- private function getValue ($ array , $ path )
157+ private function getValueByPath ($ array , $ path )
114158 {
115159 return $ this ->getPropertyAccessor ()->getValue ($ array , $ path );
116160 }
@@ -131,23 +175,39 @@ private function getPropertyAccessor()
131175 }
132176
133177 /**
134- * @param array $value
135- * @param array $pattern
136- * @param $parentPath
137- * @return bool
178+ * @param $place
179+ * @param $path
138180 */
139- private function checkIfPathsFromPatternExistInValue ( array $ value , array $ pattern , $ parentPath )
181+ private function setMissingElementInError ( $ place , $ path )
140182 {
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+ }
143185
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+ }
150194
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 ;
152212 }
153213}
0 commit comments