@@ -19,9 +19,42 @@ class DotArray implements
1919{
2020
2121 /* Traits. */
22- use DotPathTrait;
2322 use DotFilteringTrait;
2423
24+ /**
25+ * Internal Dot Path Config.
26+ *
27+ * @var array
28+ */
29+ protected static $ dotPathConfig = [
30+ 'template ' => '#(?|(?|[<token-start>](.*?)[<token-end>])|(.*?))(?:$|\.+)#i ' ,
31+ 'wrapKey ' => '{%s} ' ,
32+ 'wildcards ' => [
33+ '<token-start> ' => ['\'' , '\" ' , '\[ ' , '\( ' , '\{ ' ],
34+ '<token-end> ' => ['\'' , '\" ' , '\] ' , '\) ' , '\} ' ],
35+ ],
36+ ];
37+
38+ /**
39+ * The cached pattern that allow to match the JSON paths that use the dot notation.
40+ *
41+ * Allowed tokens for more complex paths: '', "", [], (), {}
42+ * Examples:
43+ *
44+ * - foo.bar
45+ * - foo.'bar'
46+ * - foo."bar"
47+ * - foo.[bar]
48+ * - foo.(bar)
49+ * - foo.{bar}
50+ *
51+ * Or more complex:
52+ * - foo.{bar}.[component].{version.1.0}
53+ *
54+ * @var string
55+ */
56+ protected static $ dotPathPattern ;
57+
2558 /**
2659 * Unique object identifier.
2760 *
@@ -61,6 +94,132 @@ public static function createFromJson($json)
6194 }
6295
6396
97+ /**
98+ * Getting the dot path pattern.
99+ *
100+ * @return string
101+ */
102+ protected static function dotPathPattern ()
103+ {
104+ if (empty (self ::$ dotPathPattern )) {
105+ $ path = self ::$ dotPathConfig ['template ' ];
106+
107+ foreach (self ::$ dotPathConfig ['wildcards ' ] as $ wildcard => $ tokens ) {
108+ $ path = \str_replace ($ wildcard , \implode ('' , $ tokens ), $ path );
109+ }
110+
111+ self ::$ dotPathPattern = $ path ;
112+ }
113+
114+ return self ::$ dotPathPattern ;
115+ }
116+
117+
118+ /**
119+ * Converts dot string path to segments.
120+ *
121+ * @param string $path
122+ *
123+ * @return array
124+ */
125+ protected static function pathToSegments ($ path )
126+ {
127+ $ path = \trim ($ path , " \t\n\r\0\x0B\. " );
128+ $ segments = [];
129+ $ matches = [];
130+
131+ if (\mb_strlen ($ path , 'UTF-8 ' ) === 0 ) {
132+ return [];
133+ }
134+
135+ \preg_match_all (static ::dotPathPattern (), $ path , $ matches );
136+
137+ if (!empty ($ matches [1 ])) {
138+ $ matches = $ matches [1 ];
139+
140+ $ segments = \array_filter (
141+ $ matches ,
142+ function ($ match ) {
143+ return (\mb_strlen ($ match , 'UTF-8 ' ) > 0 );
144+ }
145+ );
146+ }
147+
148+ unset($ path , $ matches );
149+
150+ return $ segments ;
151+ }
152+
153+
154+ /**
155+ * Wrap a given string into special characters.
156+ *
157+ * @param string $key
158+ *
159+ * @return string
160+ */
161+ protected static function wrapSegmentKey ($ key )
162+ {
163+ return vsprintf (static ::$ dotPathConfig ['wrapKey ' ], [$ key ]);
164+ }
165+
166+
167+ /**
168+ * @param array $segments
169+ *
170+ * @return string
171+ */
172+ protected static function segmentsToKey (array $ segments )
173+ {
174+ return (
175+ \implode (
176+ '. ' ,
177+ \array_map (
178+ function ($ segment ) {
179+ return static ::wrapSegmentKey ($ segment );
180+ },
181+ $ segments
182+ )
183+ )
184+ );
185+ }
186+
187+
188+ /**
189+ * Flatten the internal array using the dot delimiter,
190+ * also the keys are wrapped inside {key} (1 x curly braces).
191+ *
192+ * @param array $items
193+ * @param array $prepend
194+ *
195+ * @return array
196+ */
197+ protected static function flatten (array $ items , $ prepend = [])
198+ {
199+ $ flatten = [];
200+
201+ foreach ($ items as $ key => $ value ) {
202+ if (\is_array ($ value ) && !empty ($ value )) {
203+ $ flatten = array_merge (
204+ $ flatten ,
205+ static ::flatten (
206+ $ value ,
207+ array_merge ($ prepend , [$ key ])
208+ )
209+ );
210+
211+ continue ;
212+ }
213+
214+ $ segmentsToKey = static ::segmentsToKey (array_merge ($ prepend , [$ key ]));
215+
216+ $ flatten [$ segmentsToKey ] = $ value ;
217+ }
218+
219+ return $ flatten ;
220+ }
221+
222+
64223 /**
65224 * Return the given items as an array
66225 *
0 commit comments