|
18 | 18 | use Magento\Framework\Filter\DirectiveProcessor\TemplateDirective;
|
19 | 19 | use Magento\Framework\Filter\DirectiveProcessor\VarDirective;
|
20 | 20 | use Magento\Framework\Stdlib\StringUtils;
|
| 21 | +use Magento\Framework\Filter\Template\SignatureProvider; |
21 | 22 |
|
22 | 23 | /**
|
23 | 24 | * Template filter
|
@@ -100,23 +101,32 @@ class Template implements \Zend_Filter_Interface
|
100 | 101 | */
|
101 | 102 | private $variableResolver;
|
102 | 103 |
|
| 104 | + /** |
| 105 | + * @var SignatureProvider|null |
| 106 | + */ |
| 107 | + private $signatureProvider; |
| 108 | + |
103 | 109 | /**
|
104 | 110 | * @param StringUtils $string
|
105 | 111 | * @param array $variables
|
106 | 112 | * @param DirectiveProcessorInterface[] $directiveProcessors
|
107 | 113 | * @param VariableResolverInterface|null $variableResolver
|
| 114 | + * @param SignatureProvider|null $signatureProvider |
108 | 115 | */
|
109 | 116 | public function __construct(
|
110 | 117 | StringUtils $string,
|
111 | 118 | $variables = [],
|
112 | 119 | $directiveProcessors = [],
|
113 |
| - VariableResolverInterface $variableResolver = null |
| 120 | + VariableResolverInterface $variableResolver = null, |
| 121 | + SignatureProvider $signatureProvider = null |
114 | 122 | ) {
|
115 | 123 | $this->string = $string;
|
116 | 124 | $this->setVariables($variables);
|
117 | 125 | $this->directiveProcessors = $directiveProcessors;
|
118 | 126 | $this->variableResolver = $variableResolver ?? ObjectManager::getInstance()
|
119 | 127 | ->get(VariableResolverInterface::class);
|
| 128 | + $this->signatureProvider = $signatureProvider ?? ObjectManager::getInstance() |
| 129 | + ->get(SignatureProvider::class); |
120 | 130 |
|
121 | 131 | if (empty($directiveProcessors)) {
|
122 | 132 | $this->directiveProcessors = [
|
@@ -180,22 +190,83 @@ public function filter($value)
|
180 | 190 | )->render());
|
181 | 191 | }
|
182 | 192 |
|
| 193 | + // Processing of template directives. |
| 194 | + $templateDirectivesResults = $this->processDirectives($value); |
| 195 | + |
| 196 | + foreach ($templateDirectivesResults as $result) { |
| 197 | + $value = str_replace($result['directive'], $result['output'], $value); |
| 198 | + } |
| 199 | + |
| 200 | + // Processing of deferred directives received from child templates. |
| 201 | + $deferredDirectivesResults = $this->processDirectives($value, true); |
| 202 | + |
| 203 | + foreach ($deferredDirectivesResults as $result) { |
| 204 | + $value = str_replace($result['directive'], $result['output'], $value); |
| 205 | + } |
| 206 | + |
| 207 | + // Signing own deferred directives (if any). |
| 208 | + $signature = $this->signatureProvider->get(); |
| 209 | + |
| 210 | + foreach ($templateDirectivesResults as $result) { |
| 211 | + if ($result['directive'] === $result['output']) { |
| 212 | + $value = str_replace( |
| 213 | + $result['output'], |
| 214 | + $signature . $result['output'] . $signature, |
| 215 | + $value |
| 216 | + ); |
| 217 | + } |
| 218 | + } |
| 219 | + |
| 220 | + $value = $this->afterFilter($value); |
| 221 | + |
| 222 | + return $value; |
| 223 | + } |
| 224 | + |
| 225 | + /** |
| 226 | + * Processes template directives and returns an array |
| 227 | + * that contains results produced by each directive. |
| 228 | + * |
| 229 | + * @param string $value |
| 230 | + * @param bool $isSigned |
| 231 | + * |
| 232 | + * @return array |
| 233 | + * |
| 234 | + * @throws InvalidArgumentException |
| 235 | + * @throws \Magento\Framework\Exception\LocalizedException |
| 236 | + */ |
| 237 | + private function processDirectives($value, $isSigned = false) |
| 238 | + { |
| 239 | + $results = []; |
| 240 | + |
183 | 241 | foreach ($this->directiveProcessors as $directiveProcessor) {
|
184 | 242 | if (!$directiveProcessor instanceof DirectiveProcessorInterface) {
|
185 | 243 | throw new InvalidArgumentException(
|
186 | 244 | 'Directive processors must implement ' . DirectiveProcessorInterface::class
|
187 | 245 | );
|
188 | 246 | }
|
189 | 247 |
|
190 |
| - if (preg_match_all($directiveProcessor->getRegularExpression(), $value, $constructions, PREG_SET_ORDER)) { |
| 248 | + $pattern = $directiveProcessor->getRegularExpression(); |
| 249 | + |
| 250 | + if ($isSigned) { |
| 251 | + $signature = $this->signatureProvider->get(); |
| 252 | + |
| 253 | + $pattern = substr_replace($pattern, $signature, strpos($pattern, '/') + 1, 0); |
| 254 | + $pattern = substr_replace($pattern, $signature, strrpos($pattern, '/'), 0); |
| 255 | + } |
| 256 | + |
| 257 | + if (preg_match_all($pattern, $value, $constructions, PREG_SET_ORDER)) { |
191 | 258 | foreach ($constructions as $construction) {
|
192 | 259 | $replacedValue = $directiveProcessor->process($construction, $this, $this->templateVars);
|
193 |
| - $value = str_replace($construction[0], $replacedValue, $value); |
| 260 | + |
| 261 | + $results[] = [ |
| 262 | + 'directive' => $construction[0], |
| 263 | + 'output' => $replacedValue |
| 264 | + ]; |
194 | 265 | }
|
195 | 266 | }
|
196 | 267 | }
|
197 | 268 |
|
198 |
| - return $this->afterFilter($value); |
| 269 | + return $results; |
199 | 270 | }
|
200 | 271 |
|
201 | 272 | /**
|
|
0 commit comments