From d8ae0f5d75ea63b9045a26d9509aa9a9a1c3239a Mon Sep 17 00:00:00 2001 From: toxyy Date: Sun, 3 Dec 2023 16:32:02 -0500 Subject: [PATCH] [ticket/15214] Add event & functionality for assigning template event priority Event added to allow template events to be assigned priority per extension, event location chosen so that it only fires once. Twig node event class refactored to allow template event priority assignment, compile calls are deferred until all locations are processed per extension namespace. Priority precedence mirrors Symfony priority, with higher numbers being placed at the beginning of the array. Duplicate priority assignment will currently have the later events compiled before the others. PHPBB3-15214 --- .../default/container/services_twig.yml | 1 + phpBB/phpbb/template/twig/extension.php | 9 +++- phpBB/phpbb/template/twig/node/event.php | 51 +++++++++++++++++-- .../phpbb/template/twig/tokenparser/event.php | 28 +++++++++- 4 files changed, 80 insertions(+), 9 deletions(-) diff --git a/phpBB/config/default/container/services_twig.yml b/phpBB/config/default/container/services_twig.yml index 5547ca2608..f229814bcc 100644 --- a/phpBB/config/default/container/services_twig.yml +++ b/phpBB/config/default/container/services_twig.yml @@ -40,6 +40,7 @@ services: - '@template_context' - '@template.twig.environment' - '@language' + - '@dispatcher' tags: - { name: twig.extension } diff --git a/phpBB/phpbb/template/twig/extension.php b/phpBB/phpbb/template/twig/extension.php index 95c710ad7e..fcf1ce52cc 100644 --- a/phpBB/phpbb/template/twig/extension.php +++ b/phpBB/phpbb/template/twig/extension.php @@ -26,18 +26,23 @@ class extension extends \Twig\Extension\AbstractExtension /** @var \phpbb\language\language */ protected $language; + /** @var \phpbb\event\dispatcher_interface */ + protected $phpbb_dispatcher; + /** * Constructor * * @param \phpbb\template\context $context * @param \phpbb\template\twig\environment $environment * @param \phpbb\language\language $language + * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher */ - public function __construct(\phpbb\template\context $context, \phpbb\template\twig\environment $environment, $language) + public function __construct(\phpbb\template\context $context, \phpbb\template\twig\environment $environment, $language, \phpbb\event\dispatcher_interface $phpbb_dispatcher) { $this->context = $context; $this->environment = $environment; $this->language = $language; + $this->phpbb_dispatcher = $phpbb_dispatcher; } /** @@ -62,7 +67,7 @@ class extension extends \Twig\Extension\AbstractExtension new \phpbb\template\twig\tokenparser\includeparser, new \phpbb\template\twig\tokenparser\includejs, new \phpbb\template\twig\tokenparser\includecss, - new \phpbb\template\twig\tokenparser\event($this->environment), + new \phpbb\template\twig\tokenparser\event($this->environment, $this->phpbb_dispatcher), new \phpbb\template\twig\tokenparser\includephp($this->environment), new \phpbb\template\twig\tokenparser\php($this->environment), ); diff --git a/phpBB/phpbb/template/twig/node/event.php b/phpBB/phpbb/template/twig/node/event.php index 9766750500..e871b39b9f 100644 --- a/phpBB/phpbb/template/twig/node/event.php +++ b/phpBB/phpbb/template/twig/node/event.php @@ -21,12 +21,16 @@ class event extends \Twig\Node\Node */ protected $listener_directory = 'event/'; - /** @var \Twig\Environment */ + /** @var \phpbb\template\twig\environment */ protected $environment; - public function __construct(\Twig\Node\Expression\AbstractExpression $expr, \phpbb\template\twig\environment $environment, $lineno, $tag = null) + /** @var array */ + protected $template_event_priority_array; + + public function __construct(\Twig\Node\Expression\AbstractExpression $expr, \phpbb\template\twig\environment $environment, $lineno, $tag = null, $template_event_priority_array = []) { $this->environment = $environment; + $this->template_event_priority_array = $template_event_priority_array; parent::__construct(array('expr' => $expr), array(), $lineno, $tag); } @@ -42,17 +46,26 @@ class event extends \Twig\Node\Node $location = $this->listener_directory . $this->getNode('expr')->getAttribute('name'); + $compiler_steps = []; + foreach ($this->environment->get_phpbb_extensions() as $ext_namespace => $ext_path) { $ext_namespace = str_replace('/', '_', $ext_namespace); + if (isset($this->template_event_priority_array[$ext_namespace][$location])) + { + $priority_key = $this->template_event_priority_array[$ext_namespace][$location]; + } + + $compiler_calls = []; + if ($this->environment->isDebug()) { // If debug mode is enabled, lets check for new/removed EVENT // templates on page load rather than at compile. This is // slower, but makes developing extensions easier (no need to // purge the cache when a new event template file is added) - $compiler + $compiler_calls[] = fn() => $compiler ->write("if (\$this->env->getLoader()->exists('@{$ext_namespace}/{$location}.html')) {\n") ->indent() ; @@ -60,7 +73,7 @@ class event extends \Twig\Node\Node if ($this->environment->isDebug() || $this->environment->getLoader()->exists('@' . $ext_namespace . '/' . $location . '.html')) { - $compiler + $compiler_calls[] = fn() => $compiler ->write("\$previous_look_up_order = \$this->env->getNamespaceLookUpOrder();\n") // We set the namespace lookup order to be this extension first, then the main path @@ -72,11 +85,39 @@ class event extends \Twig\Node\Node if ($this->environment->isDebug()) { - $compiler + $compiler_calls[] = fn() => $compiler ->outdent() ->write("}\n\n") ; } + + if (!empty($compiler_calls)) + { + if (isset($priority_key)) + { + if (array_key_exists($priority_key, $compiler_steps)) + { + array_splice($compiler_steps, $priority_key, 0, [$compiler_calls]); + } + else + { + $compiler_steps[$priority_key] = $compiler_calls; + } + } + else + { + array_unshift($compiler_steps, $compiler_calls); + } + } + } + + krsort($compiler_steps); + foreach ($compiler_steps as $ext_namespace_steps) + { + foreach ($ext_namespace_steps as $step) + { + $step(); + } } } } diff --git a/phpBB/phpbb/template/twig/tokenparser/event.php b/phpBB/phpbb/template/twig/tokenparser/event.php index 7b9742cc95..3dadc7e3b3 100644 --- a/phpBB/phpbb/template/twig/tokenparser/event.php +++ b/phpBB/phpbb/template/twig/tokenparser/event.php @@ -18,14 +18,38 @@ class event extends \Twig\TokenParser\AbstractTokenParser /** @var \phpbb\template\twig\environment */ protected $environment; + /** @var \phpbb\event\dispatcher_interface */ + protected $phpbb_dispatcher; + + /** @var array */ + protected $template_event_priority_array; + /** * Constructor * * @param \phpbb\template\twig\environment $environment */ - public function __construct(\phpbb\template\twig\environment $environment) + public function __construct(\phpbb\template\twig\environment $environment, \phpbb\event\dispatcher_interface $phpbb_dispatcher = null) { $this->environment = $environment; + $this->phpbb_dispatcher = $phpbb_dispatcher; + + $template_event_priority_array = []; + + /** + * Allow assigning priority to template events + * + * @event core.twig_tokenparser_constructor + * @var array template_event_priority_array Array with template event priority assignments per extension namespace + * @since 3.3.12-RC1 + */ + if ($this->phpbb_dispatcher) + { + $vars = array('template_event_priority_array'); + extract($this->phpbb_dispatcher->trigger_event('core.twig_tokenparser_constructor', compact($vars))); + } + + $this->template_event_priority_array = $template_event_priority_array; } /** @@ -42,7 +66,7 @@ class event extends \Twig\TokenParser\AbstractTokenParser $stream = $this->parser->getStream(); $stream->expect(\Twig\Token::BLOCK_END_TYPE); - return new \phpbb\template\twig\node\event($expr, $this->environment, $token->getLine(), $this->getTag()); + return new \phpbb\template\twig\node\event($expr, $this->environment, $token->getLine(), $this->getTag(), $this->template_event_priority_array); } /**