Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ticket/15214] Add event & functionality for assigning template event priority #6571

Open
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

toxyy
Copy link
Contributor

@toxyy toxyy commented Dec 3, 2023

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

Checklist:

  • Correct branch: master for new features; 3.3.x for fixes
  • Tests pass
  • Code follows coding guidelines: master and 3.3.x
  • Commit follows commit message format

Tracker ticket:

https://tracker.phpbb.com/browse/PHPBB3-15214

… 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
@toxyy
Copy link
Contributor Author

toxyy commented Dec 3, 2023

Example event usage: (unsure about the name)

public function twig_tokenparser_constructor($event)
{
	$template_event_priority_array = $event['template_event_priority_array'];
	$template_event_priority_array += [
		'toxyy_postformtemplates' => [
			'event/overall_header_head_append' => 1000
		]
	];
	$event['template_event_priority_array'] = $template_event_priority_array;
}

image

With this, my template event is called before any others. Normal behavior would have it placed on the bottom of this list.

As stated in the commit message, priority works like in Symfony events, the higher number will be compiled first.

If two events have the same priority, then the last one added will be executed last - this differs from what's stated in my initial commit message, sorry about that, I was thinking about it wrong.

Reason being is that for an array:

[
  '0' => 'first_event',
  '1' => 'second_event',
  '2' => 'third_event',
  '3' => 'fourth_event'
]

if your priority is 2, then it will be placed as so:

[
  '0' => 'first_event',
  '1' => 'second_event',
  '2' => 'priority_set_event',
  '3' => 'third_event',
  '4' => 'fourth_event'
]

And then if another event has a priority of 2, then it will be placed above it:

[
  '0' => 'first_event',
  '1' => 'second_event',
  '2' => 'another_priority_set_event',
  '3' => 'priority_set_event'.
  '4' => 'third_event',
  '5' => 'fourth_event'
]

And because the higher numbers get executed first (krsort), it will get compiled after the previously set template event for the same priority. This is an edge case though. Not sure how Symfony handles this. Template events by default are parsed in alphabetical order by extension namespace. If no one uses the event, then template events will execute in the same order as they do now.

Add new dispatch parameter to the template\twig\extension call

PHPBB3-15214
Add new dispatch parameter to the template\twig\extension call

PHPBB3-15214
Add new dispatch parameter to the template\twig\extension calls

PHPBB3-15214
Arrow functions aren't added until PHP 7.4, so we can't use them yet.
Anonymous functions have been added since PHP 5.3

PHPBB3-15214
@toxyy
Copy link
Contributor Author

toxyy commented Dec 3, 2023

I don't know if the compiler object's write methods change the state of the compiler object itself. If so then $compiler should be passed as &$compiler in the use() of the anonymous functions, but as it's currently written, it works fine.

Also unsure if it's necessary to set $phpbb_dispatcher to null within phpbb\template\twig\tokenparser\event on this line and check for that on this line, but the null check seems to be standard for most other classes in the template\twig folder. Even though the constructor is only being called in one place in the entire codebase

Also unsure about proper code formatting for the anonymous functions, I don't have a phpstorm license so I can't run it through that to check, and there are no anonymous functions as far as I can find within core so I'm not sure if they're accounted for with code styling.

Hopefully this is fine on the 3.3 branch? 😄

It doesn't need to be set at the top and makes more sense to set it
at the bottom where it's used. Also removes a redundant check

PHPBB3-15214
extract($this->phpbb_dispatcher->trigger_event('core.twig_tokenparser_constructor', compact($vars)));
}

$this->template_event_priority_array = $template_event_priority_array;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably makes sense to unset($template_event_priority_array); as it's not used anymore.

Adds similar usage examples like the event core.permissions has

PHPBB3-15214
@toxyy
Copy link
Contributor Author

toxyy commented Dec 5, 2023

All I did was change what's within a docblock comment... that test should not have failed

Make docblock look a bit cleaner and restart the tests

PHPBB3-15214
@rxu
Copy link
Contributor

rxu commented Dec 5, 2023

That's random network issue, unrelated.

@toxyy
Copy link
Contributor Author

toxyy commented Dec 5, 2023

No matter, I think the format of this docblock update is cleaner anyways

@rxu
Copy link
Contributor

rxu commented Dec 9, 2023

To sum my all above comments, I feel like simplified all the stuff and below code works just fine.

	public function compile(\Twig\Compiler $compiler)
	{
		$compiler->addDebugInfo($this);

		$location = $this->listener_directory . $this->getNode('expr')->getAttribute('name');

		$template_events = [];
		foreach ($this->environment->get_phpbb_extensions() as $ext_namespace => $ext_path)
		{
			$ext_namespace = str_replace('/', '_', $ext_namespace);
			$priority_key = $this->template_event_priority_array[$ext_namespace][$location] ?? 0;
			$template_events[$priority_key][] = $ext_namespace;
		}
		krsort($template_events);

		foreach ($template_events as $priority => $events)
		{
			foreach ($events as $ext_namespace)
			{
				if ($this->environment->isDebug() || $this->environment->getLoader()->exists('@' . $ext_namespace . '/' . $location . '.html'))
				{
					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
							->write("if (\$this->env->getLoader()->exists('@{$ext_namespace}/{$location}.html')) {\n")
							->indent();
					}

					$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
						->write("\$this->env->setNamespaceLookUpOrder(array('{$ext_namespace}', '__main__'));\n")
						->write("\$this->env->loadTemplate('@{$ext_namespace}/{$location}.html')->display(\$context);\n")
						->write("\$this->env->setNamespaceLookUpOrder(\$previous_look_up_order);\n");

					if ($this->environment->isDebug())
					{
						$compiler
							->outdent()
							->write("}\n\n");
					}
				}
			}
		}
	}

@rxu
Copy link
Contributor

rxu commented Dec 9, 2023

I guess the issue with the commit messages here is an empty line needed between the explanation line and PHPBB3-15214 line.

@toxyy
Copy link
Contributor Author

toxyy commented Dec 9, 2023

I guess the issue with the commit messages here is an empty line needed between the explanation line and PHPBB3-15214 line.

There are also some other failures like here:
https://github.com/phpbb/phpbb/actions/runs/7152664064/job/19478240191?pr=6571#step:10:1060

I'll do a force push to fix the messages in a bit.

Putting this here will have the loop run the same amount of times as default.
Without this, the loop runs too many extra times.

PHPBB3-15214
@toxyy
Copy link
Contributor Author

toxyy commented Dec 9, 2023

@rxu Yeah looks like it doesn't like the added tests right now

I'm guessing that it's because template_event_order.php and template_event_order.php have the same class name for foo\bar and the same for template_event_order.php and template_event_order_lower.php for foo\foo. Unsure though. Maybe not. I've tried to look through everything else and I don't understand why it's failing.

Added this when I initially tested the if block move.
but I forgot to add it in the actual commit.
If this isn't moved, no template events work, and the tests fail.

PHPBB3-15214
@rxu
Copy link
Contributor

rxu commented Dec 10, 2023

That's weird as everything works when installing both of the test extensions on a local test board and yaml for both of services.yml is valid.

EDIT: I guess I've got what's the issue, let me test something.

@toxyy
Copy link
Contributor Author

toxyy commented Dec 10, 2023

@rxu That solved the errors we were seeing before, but we've got a new set of failures 😓

@rxu
Copy link
Contributor

rxu commented Dec 10, 2023

I'm afraid Win+PHP 8.3 errors aren't related to this PR. Will dig into it a bit.

@toxyy
Copy link
Contributor Author

toxyy commented Dec 10, 2023

Tests passed earlier in this PR so I'm not sure what changed.

@toxyy
Copy link
Contributor Author

toxyy commented Dec 10, 2023

Also, I've been thinking.

Currently, all events are added to the same priority of 0 in the order that they would originally be run. I'm not sure how Symfony events work exactly, but would there be any scenario in which someone would want to place a template event in the middle of those? Technically, that would mean that they cannot all be at priority key 0. That is also installation dependent, as the priority keys would change based on what extensions you have enabled, assuming multiple extensions use the same events.

Would it be beneficial to somehow make it so you could say "if extension X is installed, make my template event compile before theirs"? That could be solved with a priority key, yes, but lets say you also want all other extensions to execute before yours as well - meaning you specifically want your template event to compile right before extension X's event of the same name (though anyone else doing the same would run into default behavior, of course).

Let's take navlinks for example. Maybe you want to place your link right before the other nav links of extension X, but you don't want it to be the first links added. With a priority key, the only way to get it before extension X would be to make it compile first, meaning your links would be first. That doesn't seem versatile.

Is what I'm explaining making sense, and is that a valid use case to try to add functionality for?

@rxu
Copy link
Contributor

rxu commented Dec 10, 2023

I'm not sure I fully got the point in question.
With your PR you're able to set priority for any other extension template event (by other authors, unlike core events). So if you want to change, f.e., quick links extensions order with your extension you just set priority keys as you wish for another extension(s) template events.

@toxyy
Copy link
Contributor Author

toxyy commented Dec 10, 2023

Ah yes you could do that. I guess that case would be solved then.

@rxu
Copy link
Contributor

rxu commented Dec 10, 2023

And the error is:

PHP FATAL ERROR:  UNCAUGHT TWIG\ERROR\LOADERERROR: UNABLE TO FIND TEMPLATE "@FOO_BAR/EVENT/NAVBAR_HEADER_QUICK_LINKS_AFTER.HTML" (LOOKED INTO: ) IN "NAVBAR_HEADER.HTML" AT LINE 75. IN D:\A\PHPBB3\PHPBB3\PHPBB\VENDOR\TWIG\TWIG\SRC\LOADER\FILESYSTEMLOADER.PHP

D:\a\phpbb3\phpbb3\tests\test_framework\phpbb_functional_test_case.php:983
D:\a\phpbb3\phpbb3\tests\test_framework\phpbb_functional_test_case.php:143
D:\a\phpbb3\phpbb3\tests\test_framework\phpbb_functional_test_case.php:807
D:\a\phpbb3\phpbb3\tests\functional\notification_test.php:46

That's weird again as this template event shouldn't be involved there.

@toxyy
Copy link
Contributor Author

toxyy commented Dec 10, 2023

If that said that it was for @FOO_FOO I'd say to also add foo/foo/styles/prosilver/template/ to $fixtures but I'm at a loss currently.

Why is it looking in /event/ for the template?

@rxu
Copy link
Contributor

rxu commented Dec 10, 2023

The issue revealed by this PR is the twig compiled cache folder was never purged in Windows test environment. Will send a fix PR to this PR soon.

Purge Twig compiled cache in Windows.
Set appropriate folder access control options to do that.

PHPBB3-15214
@toxyy
Copy link
Contributor Author

toxyy commented Dec 10, 2023

Failed asserting that 'PHP FATAL ERROR: UNCAUGHT TWIG\ERROR\LOADERERROR: THERE ARE NO REGISTERED PATHS FOR NAMESPACE "FOO_BAR" IN "NAVBAR_HEADER.HTML" AT LINE 75. IN D:\A\PHPBB\PHPBB\PHPBB\VENDOR\TWIG\TWIG\SRC\LOADER\FILESYSTEMLOADER.PHP:227

😄

@rxu
Copy link
Contributor

rxu commented Dec 10, 2023

Hmm. Tests were passing successfully here https://github.com/rxu/phpbb3/actions/runs/7157430146 on Win+PHP 8.3 with this code. One more weirdness :) Okay, will look into it furher.

@rxu
Copy link
Contributor

rxu commented Dec 10, 2023

@toxyy Could you try adding these 3 lines to .github/workflows/tests.yml rxu@0e2b349#diff-1db27d93186e46d3b441ece35801b244db8ee144ff1405ca27a163bfe878957fR171-R173
Tests pass here https://github.com/rxu/phpbb3/actions/runs/7158983020

Adding per rxu's recommendation

PHPBB3-15214
@toxyy
Copy link
Contributor Author

toxyy commented Dec 10, 2023

@rxu same error 😄
Failed asserting that 'PHP FATAL ERROR: UNCAUGHT TWIG\ERROR\LOADERERROR: THERE ARE NO REGISTERED PATHS FOR NAMESPACE "FOO_BAR" IN "NAVBAR_HEADER.HTML" AT LINE 75. IN D:\A\PHPBB\PHPBB\PHPBB\VENDOR\TWIG\TWIG\SRC\LOADER\FILESYSTEMLOADER.PHP:227

@rxu
Copy link
Contributor

rxu commented Dec 10, 2023

Nice.

EDIT: the problem is that twig cache folder is not being purged under Windows for some reason. I'm out of ideas for now.

@toxyy
Copy link
Contributor Author

toxyy commented Dec 10, 2023

@marc1706 maybe you have some ideas? Not sure who else has worked with the tests a lot

@toxyy
Copy link
Contributor Author

toxyy commented Dec 12, 2023

@rxu It worked this time 😄 thanks for the help

@rxu
Copy link
Contributor

rxu commented Dec 12, 2023

Great. The issue is that after the purge_cache() call tests go forward fast so that the next one got executed before all cache files are finished to delete. Hence the error. sleep() solves it.

@marc1706
Copy link
Member

marc1706 commented May 4, 2024

As noted on discord, the PR might result in BC breaks for some and adds quite a bit of changes to behavior and introduces new functionality so this shouldn't aim for 3.3.x but rather 4.0.

@rxu
Copy link
Contributor

rxu commented May 4, 2024

@toxyy mind to rebase vs master?

@toxyy toxyy changed the base branch from 3.3.x to master May 7, 2024 15:04
@toxyy
Copy link
Contributor Author

toxyy commented May 7, 2024

@rxu there are a lot of conflicts that I'll need to go through, but sure. I also need to change the event's since version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants