@@ -27,7 +27,49 @@ class ExtractorDefinitionBuilder implements ExtractorDefinitionBuilderInterface
27
27
/**
28
28
* @var string
29
29
*/
30
- protected $ type_regexp = '/^((?<name>[-_\w]+)(?:\s*\(\s*(?<param>(?-3)*|[\w \\\\]+)\s*\))?(?:\s*\|\s*(?<alt>(?-4)))?)$/ ' ;
30
+ protected $ type_regexp = '/
31
+ ^
32
+ (
33
+ (?<name>
34
+ [-_\w]*
35
+ )
36
+ (?:
37
+ \s*
38
+ (?<group>
39
+ \(
40
+ \s*
41
+ (?<param>
42
+ (?-4)*
43
+ |
44
+ [\w \\\\]+
45
+ )
46
+ \s*
47
+ \)
48
+ )
49
+ )?
50
+ (?:
51
+ \s*
52
+ (?<arr>(?:\s*\[\s*\]\s*)+)
53
+ )?
54
+ (?:
55
+ \s*
56
+ \|
57
+ \s*
58
+ (?<alt>(?-6))
59
+ )?
60
+ )
61
+ $
62
+ /xi ' ;
63
+
64
+ protected $ type_regexp2 = '/
65
+ ^
66
+ (?:((\w+\b(?:\(.*\))?(?:\s*\[\s*\])?)(?:\s*\|\s*(?-1))*))
67
+ |
68
+ (?:\(\s*(?-2)\s*\)(?:\s*\[\s*\])?)
69
+ |
70
+ (\[\s*\])
71
+ $
72
+ /xi ' ;
31
73
32
74
/**
33
75
* {@inheritdoc}
@@ -40,32 +82,53 @@ public function build(string $definition): ExtractorDefinitionInterface
40
82
throw new ExtractorDefinitionBuilderException ('Definition must be non-empty string ' );
41
83
}
42
84
43
- if (preg_match ($ this ->type_regexp , $ definition , $ matches )) {
44
- return $ this ->buildExtractor ($ matches ['name ' ], $ matches ['param ' ] ?? null , $ matches ['alt ' ] ?? null );
85
+ try {
86
+ if (preg_match ($ this ->type_regexp , $ definition , $ matches )) {
87
+ $ extractor = $ this ->buildExtractor ($ matches ['name ' ], $ matches ['param ' ] ?? '' , $ matches ['alt ' ] ?? '' , $ this ->getDepth ($ matches ), $ this ->hasGroups ($ matches ));
88
+
89
+ return $ extractor ;
90
+ }
91
+ } catch (ExtractorDefinitionBuilderException $ e ) {
92
+ // We don't care about what specific issue we hit inside,
93
+ // for API user it means that the definition is invalid
45
94
}
46
95
47
96
throw new ExtractorDefinitionBuilderException ("Unable to parse definition: ' {$ definition }' " );
48
97
}
49
98
50
99
/**
51
- * @param string $name
100
+ * @param string $name
52
101
* @param null|string $param
53
102
* @param null|string $alt_definitions
103
+ * @param int $depth
104
+ * @param bool $groups
54
105
*
55
106
* @return ExtractorDefinitionInterface
56
107
* @throws ExtractorDefinitionBuilderException
57
108
*/
58
- protected function buildExtractor (string $ name , ? string $ param , ? string $ alt_definitions ): ExtractorDefinitionInterface
109
+ protected function buildExtractor (string $ name , string $ param , string $ alt_definitions, int $ depth , bool $ groups ): ExtractorDefinitionInterface
59
110
{
60
111
$ next = null ;
61
112
62
- if ($ param && preg_match ($ this ->type_regexp , $ param , $ matches )) {
63
- $ next = $ this ->buildExtractor ($ matches ['name ' ], $ matches ['param ' ] ?? null , $ matches ['alt ' ] ?? null );
113
+ if ('' !== $ param && preg_match ($ this ->type_regexp , $ param , $ matches )) {
114
+ $ next = $ this ->buildExtractor ($ matches ['name ' ], $ matches ['param ' ] ?? '' , $ matches ['alt ' ] ?? '' , $ this ->getDepth ($ matches ), $ this ->hasGroups ($ matches ));
115
+ }
116
+
117
+ if ($ name ) {
118
+ $ definition = new PlainExtractorDefinition ($ name , $ next );
119
+ } else {
120
+ $ definition = $ next ;
121
+ }
122
+
123
+ if ($ depth > 0 ) {
124
+ $ definition = $ this ->buildArrayDefinition ($ definition , $ depth , $ groups );
64
125
}
65
126
66
- $ definition = new PlainExtractorDefinition ($ name , $ next );
127
+ if (!$ definition ) {
128
+ throw new ExtractorDefinitionBuilderException ('Empty group is not allowed ' );
129
+ }
67
130
68
- if ($ alt_definitions ) {
131
+ if ('' !== $ alt_definitions ) {
69
132
$ definition = $ this ->buildVariableDefinition ($ definition , $ alt_definitions );
70
133
}
71
134
@@ -74,7 +137,7 @@ protected function buildExtractor(string $name, ?string $param, ?string $alt_def
74
137
75
138
/**
76
139
* @param PlainExtractorDefinitionInterface $definition
77
- * @param string $alt_definitions
140
+ * @param string $alt_definitions
78
141
*
79
142
* @return VariableExtractorDefinition
80
143
* @throws ExtractorDefinitionBuilderException
@@ -83,19 +146,61 @@ protected function buildVariableDefinition(PlainExtractorDefinitionInterface $de
83
146
{
84
147
$ alt = [$ definition ];
85
148
86
- while ($ alt_definitions && preg_match ($ this ->type_regexp , $ alt_definitions , $ matches )) {
149
+ while ('' !== $ alt_definitions && preg_match ($ this ->type_regexp , $ alt_definitions , $ matches )) {
87
150
// build alt
88
- $ alt [] = $ this ->buildExtractor ($ matches ['name ' ], $ matches ['param ' ] ?? null , null );
151
+ $ alt [] = $ this ->buildExtractor ($ matches ['name ' ], $ matches ['param ' ] ?? '' , '' , $ this -> getDepth ( $ matches ), $ this -> hasGroups ( $ matches ) );
89
152
90
- $ alt_definitions = $ matches ['alt ' ] ?? null ;
153
+ $ alt_definitions = trim ( $ matches ['alt ' ] ?? '' ) ;
91
154
}
92
155
93
- if ($ alt_definitions ) {
156
+ if ('' !== $ alt_definitions ) {
157
+ // UNEXPECTED
94
158
// this should not be possible, but just in case we will ever get here
95
159
throw new ExtractorDefinitionBuilderException ('Invalid varying definition ' );
96
160
}
97
161
98
162
return new VariableExtractorDefinition (...$ alt );
99
163
}
100
164
165
+ /**
166
+ * @param null|ExtractorDefinitionInterface $definition
167
+ * @param int $depth
168
+ * @param bool $groups
169
+ *
170
+ * @return ExtractorDefinitionInterface
171
+ * @throws ExtractorDefinitionBuilderException
172
+ */
173
+ protected function buildArrayDefinition (?ExtractorDefinitionInterface $ definition , int $ depth , bool $ groups ): ExtractorDefinitionInterface
174
+ {
175
+ if (!$ definition && $ groups ) {
176
+ throw new ExtractorDefinitionBuilderException ('Empty group is not allowed ' );
177
+ }
178
+
179
+ while ($ depth ) {
180
+ $ depth --;
181
+ // arrayed definition
182
+ $ definition = new PlainExtractorDefinition ('[] ' , $ definition );
183
+ }
184
+
185
+ return $ definition ;
186
+ }
187
+
188
+ /**
189
+ * @param array $matches
190
+ *
191
+ * @return int
192
+ */
193
+ private function getDepth (array $ matches ): int
194
+ {
195
+ if (!isset ($ matches ['arr ' ]) || '' === $ matches ['arr ' ]) {
196
+ return 0 ;
197
+ }
198
+
199
+ return substr_count ($ matches ['arr ' ], '[ ' );
200
+ }
201
+
202
+ private function hasGroups (array $ matches ): bool
203
+ {
204
+ return isset ($ matches ['group ' ]) && '' !== $ matches ['group ' ];
205
+ }
101
206
}
0 commit comments