1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @package s9e\TextFormatter |
5
|
|
|
* @copyright Copyright (c) 2010-2017 The s9e Authors |
6
|
|
|
* @license http://www.opensource.org/licenses/mit-license.php The MIT License |
7
|
|
|
*/ |
8
|
|
|
namespace s9e\TextFormatter\Parser; |
9
|
|
|
|
10
|
|
|
use s9e\TextFormatter\Parser; |
11
|
|
|
use s9e\TextFormatter\Parser\Logger; |
12
|
|
|
use s9e\TextFormatter\Parser\Tag; |
13
|
|
|
|
14
|
|
|
class FilterProcessing |
15
|
|
|
{ |
16
|
|
|
/** |
17
|
|
|
* Execute all the attribute preprocessors of given tag |
18
|
|
|
* |
19
|
|
|
* @private |
20
|
|
|
* |
21
|
|
|
* @param Tag $tag Source tag |
22
|
|
|
* @param array $tagConfig Tag's config |
23
|
|
|
* @return void |
24
|
|
|
*/ |
25
|
6 |
|
public static function executeAttributePreprocessors(Tag $tag, array $tagConfig) |
26
|
|
|
{ |
27
|
6 |
|
if (empty($tagConfig['attributePreprocessors'])) |
28
|
|
|
{ |
29
|
|
|
return; |
30
|
|
|
} |
31
|
|
|
|
32
|
6 |
|
foreach ($tagConfig['attributePreprocessors'] as list($attrName, $regexp, $map)) |
33
|
|
|
{ |
34
|
6 |
|
if ($tag->hasAttribute($attrName)) |
35
|
|
|
{ |
36
|
6 |
|
self::executeAttributePreprocessor($tag, $attrName, $regexp, $map); |
37
|
|
|
} |
38
|
|
|
} |
39
|
6 |
|
} |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Filter the attributes of given tag |
43
|
|
|
* |
44
|
|
|
* @private |
45
|
|
|
* |
46
|
|
|
* @param Tag $tag Tag being checked |
47
|
|
|
* @param array $tagConfig Tag's config |
48
|
|
|
* @param array $registeredVars Array of registered vars for use in attribute filters |
49
|
|
|
* @param Logger $logger This parser's Logger instance |
50
|
|
|
* @return void |
51
|
|
|
*/ |
52
|
14 |
|
public static function filterAttributes(Tag $tag, array $tagConfig, array $registeredVars, Logger $logger) |
53
|
|
|
{ |
54
|
14 |
|
$attributes = []; |
55
|
14 |
|
foreach ($tagConfig['attributes'] as $attrName => $attrConfig) |
56
|
|
|
{ |
57
|
7 |
|
$attrValue = false; |
58
|
7 |
|
if ($tag->hasAttribute($attrName)) |
59
|
|
|
{ |
60
|
|
|
$vars = [ |
61
|
6 |
|
'attrName' => $attrName, |
62
|
6 |
|
'attrValue' => $tag->getAttribute($attrName), |
63
|
6 |
|
'logger' => $logger, |
64
|
6 |
|
'registeredVars' => $registeredVars |
65
|
|
|
]; |
66
|
6 |
|
$attrValue = self::executeAttributeFilterChain($attrConfig['filterChain'], $vars); |
67
|
|
|
} |
68
|
|
|
|
69
|
7 |
|
if ($attrValue !== false) |
70
|
|
|
{ |
71
|
3 |
|
$attributes[$attrName] = $attrValue; |
72
|
|
|
} |
73
|
4 |
|
elseif (isset($attrConfig['defaultValue'])) |
74
|
|
|
{ |
75
|
2 |
|
$attributes[$attrName] = $attrConfig['defaultValue']; |
76
|
|
|
} |
77
|
2 |
|
elseif (!empty($attrConfig['required'])) |
78
|
|
|
{ |
79
|
7 |
|
$tag->invalidate(); |
80
|
|
|
} |
81
|
|
|
} |
82
|
14 |
|
$tag->setAttributes($attributes); |
83
|
14 |
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* Execute a tag's filterChain |
87
|
|
|
* |
88
|
|
|
* @private |
89
|
|
|
* |
90
|
|
|
* @param Tag $tag Tag to filter |
91
|
|
|
* @param Parser $parser Parser |
92
|
|
|
* @param array $tagsConfig Tags' config |
93
|
|
|
* @param Tag[] $openTags List of open tags |
94
|
|
|
* @return void |
95
|
|
|
*/ |
96
|
6 |
|
public static function filterTag(Tag $tag, Parser $parser, array $tagsConfig, array $openTags) |
97
|
|
|
{ |
98
|
6 |
|
$tagName = $tag->getName(); |
99
|
6 |
|
$tagConfig = $tagsConfig[$tagName]; |
100
|
|
|
|
101
|
|
|
// Record the tag being processed into the logger it can be added to the context of |
102
|
|
|
// messages logged during the execution |
103
|
6 |
|
$logger = $parser->getLogger(); |
104
|
6 |
|
$logger->setTag($tag); |
105
|
|
|
|
106
|
|
|
// Prepare the variables that are accessible to filters |
107
|
|
|
$vars = [ |
108
|
6 |
|
'logger' => $logger, |
109
|
6 |
|
'openTags' => $openTags, |
110
|
6 |
|
'parser' => $parser, |
111
|
6 |
|
'registeredVars' => $parser->registeredVars, |
112
|
6 |
|
'tag' => $tag, |
113
|
6 |
|
'tagConfig' => $tagConfig, |
114
|
6 |
|
'text' => $parser->getText() |
115
|
|
|
]; |
116
|
6 |
|
foreach ($tagConfig['filterChain'] as $filter) |
117
|
|
|
{ |
118
|
6 |
|
if ($tag->isInvalid()) |
119
|
|
|
{ |
120
|
1 |
|
break; |
121
|
|
|
} |
122
|
6 |
|
self::executeFilter($filter, $vars); |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
// Remove the tag from the logger |
126
|
6 |
|
$logger->unsetTag(); |
127
|
6 |
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* Execute an attribute's filterChain |
131
|
|
|
* |
132
|
|
|
* @param array $filterChain Attribute's filterChain |
133
|
|
|
* @param array $vars Callback vars |
134
|
|
|
* @return mixed Filtered value |
135
|
|
|
*/ |
136
|
6 |
|
protected static function executeAttributeFilterChain(array $filterChain, array $vars) |
137
|
|
|
{ |
138
|
6 |
|
$vars['logger']->setAttribute($vars['attrName']); |
139
|
6 |
|
foreach ($filterChain as $filter) |
140
|
|
|
{ |
141
|
5 |
|
$vars['attrValue'] = self::executeFilter($filter, $vars); |
142
|
5 |
|
if ($vars['attrValue'] === false) |
143
|
|
|
{ |
144
|
5 |
|
break; |
145
|
|
|
} |
146
|
|
|
} |
147
|
6 |
|
$vars['logger']->unsetAttribute(); |
148
|
|
|
|
149
|
6 |
|
return $vars['attrValue']; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Execute an attribute preprocessor |
154
|
|
|
* |
155
|
|
|
* @param Tag $tag |
156
|
|
|
* @param string $attrName |
157
|
|
|
* @param string $regexp |
158
|
|
|
* @param string[] $map |
159
|
|
|
* @return void |
160
|
|
|
*/ |
161
|
5 |
|
protected static function executeAttributePreprocessor(Tag $tag, $attrName, $regexp, $map) |
162
|
|
|
{ |
163
|
5 |
|
$attrValue = $tag->getAttribute($attrName); |
164
|
5 |
|
$captures = self::getNamedCaptures($attrValue, $regexp, $map); |
165
|
5 |
|
foreach ($captures as $k => $v) |
166
|
|
|
{ |
167
|
|
|
// Attribute preprocessors cannot overwrite other attributes but they can |
168
|
|
|
// overwrite themselves |
169
|
4 |
|
if ($k === $attrName || !$tag->hasAttribute($k)) |
170
|
|
|
{ |
171
|
4 |
|
$tag->setAttribute($k, $v); |
172
|
|
|
} |
173
|
|
|
} |
174
|
5 |
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* Execute a filter |
178
|
|
|
* |
179
|
|
|
* @see s9e\TextFormatter\Configurator\Items\ProgrammableCallback |
180
|
|
|
* |
181
|
|
|
* @param array $filter Programmed callback |
182
|
|
|
* @param array $vars Variables to be used when executing the callback |
183
|
|
|
* @return mixed Whatever the callback returns |
184
|
|
|
*/ |
185
|
15 |
|
protected static function executeFilter(array $filter, array $vars) |
186
|
|
|
{ |
187
|
|
|
// Add vars from the registeredVars array to the list of vars |
188
|
15 |
|
$vars += ['registeredVars' => []]; |
189
|
15 |
|
$vars += $vars['registeredVars']; |
190
|
|
|
|
191
|
|
|
// Prepare the list of arguments |
192
|
15 |
|
$args = []; |
193
|
15 |
|
if (isset($filter['params'])) |
194
|
|
|
{ |
195
|
15 |
|
foreach ($filter['params'] as $k => $v) |
196
|
|
|
{ |
197
|
15 |
|
$args[] = (isset($vars[$k])) ? $vars[$k] : $v; |
198
|
|
|
} |
199
|
|
|
} |
200
|
|
|
|
201
|
15 |
|
return call_user_func_array($filter['callback'], $args); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Execute a regexp and return the values of the mapped captures |
206
|
|
|
* |
207
|
|
|
* @param string $str |
208
|
|
|
* @param string $regexp |
209
|
|
|
* @param string[] $map |
210
|
|
|
* @return array |
211
|
|
|
*/ |
212
|
5 |
|
protected static function getNamedCaptures($str, $regexp, $map) |
213
|
|
|
{ |
214
|
5 |
|
if (!preg_match($regexp, $str, $m)) |
215
|
|
|
{ |
216
|
1 |
|
return []; |
217
|
|
|
} |
218
|
|
|
|
219
|
4 |
|
$values = []; |
220
|
4 |
|
foreach ($map as $i => $k) |
221
|
|
|
{ |
222
|
4 |
|
if (isset($m[$i]) && $m[$i] !== '') |
223
|
|
|
{ |
224
|
4 |
|
$values[$k] = $m[$i]; |
225
|
|
|
} |
226
|
|
|
} |
227
|
|
|
|
228
|
4 |
|
return $values; |
229
|
|
|
} |
230
|
|
|
} |