Plugins and Hooks

General discussion of development ideas and the approaches taken in the 3.x branch of phpBB. The current feature release of phpBB 3 is 3.3/Proteus.
Forum rules
Please do not post support questions regarding installing, updating, or upgrading phpBB 3.3.x. If you need support for phpBB 3.3.x please visit the 3.3.x Support Forum on phpbb.com.

If you have questions regarding writing extensions please post in Extension Writers Discussion to receive proper guidance from our staff and community.
Post Reply
code reader
Registered User
Posts: 653
Joined: Wed Sep 21, 2005 3:01 pm

Plugins and Hooks

Post by code reader »

This is going to be a lengthy message.
i plan to return and edit this message in the future, when useful input is received, when i change my mind, when i become smarter and figure a better way to do something, when i lose my mind ad post some crazy stuff etc.

this message outlines my views about hooks and plugins.
there are many details, some of them might be presented outside of logical order.

the ideas presented here are strongly influenced by what i understand about the way phorum hooks and plugin system works. if you feel this to be an insult to your "we are the best, always had been and always will be" sense, sorry.
i do not claim to fully understand phorum's system, and i do not claim to follow it loyally. this is more in the "inspired by phorum", but maybe here and there i *did* understand their system better than i think, in which cases this will be "imitating phorum". so i claim no original thought and idea in the description below.
it is, if you will, my mental image of what phorum does, which fits reality somewhere between "not at all" and "completely".


Chapter 1: what is a hook?
at the very first question i run into confusion.
a hook is a function of certain form, and at the same time it's a point in the code where such function is called.
strictly speaking, i should use two different names for these two different terms, but i am lazy, i can't think of better names, and almost always, it will be clear from the context which of the two is discussed. this may change later on when someone smarter than me comes with better names.
So, a "hook" is a point in the code where we call any plugin that wishes to be called at this specific point.
let's look at the post_message() Api call.
currently, we have an Api call that looks roughly so:
post_message($poster, $forum, $topic, $message)
where $poster and $message are objects, and $forum and $topic are IDs.
the code itself looks roughly so:

Code: Select all

function post_message($poster, $forum, $topic, $message)
{
   $result = "";
  // .. do all kinds of stuff, including assigning new values to $result
  return $result;
}
 
well, with the "hook system" in place this changes slightly:

Code: Select all

function post_message($poster, $forum, $topic, $message)
{
  $params = array('poster' => $poster, 'forum' => &$forum, 'topic' => &$topic, 'message' => $message, 'result' => "");
  if (! call_hook('hook_before_post_message', &$param))
  {
      // if call_hook returned false it means we should not continue.
      return $param['result'];
      // notice that this call may modify each of the parameters. 2 are "by ref", and 2 are objects, i.e. "by ref by def"
  }
  $result = "";
  // do all the stuff you should do.
  call_hook('hook_after_post_message', $param, &$result));  // no need to look at the return value: this is the end anyway.
  return $result;
}
 
we intersperse this "call_hook()" calls in as many places in our code as makes sense, *using a different name every time*.
we can also place hook calls in the templates, so:

Code: Select all

<!-- {HOOK before_show_password_inputfiled} -->

Chapter 2: What is a plugin?
A plugin is a bunch of source files in PHP (ideally one), (possibly) a bunch of resources (images, language files, etc.), and one metadata file.
the php source contain one or more functions (also sometimes called "hooks", although maybe they should be called "eyes", or "hookeys" or "hookers" ;) ).

all these functions have one thing in common: they always accept one by-ref parameter, and they all return boolean.
it is perfectly fine for a plugin to contain new hooks itself, so "secondary" (or "ternary" etc.) plugins that require this one can be written to modify the behavior of this plugin.

all strings used by the plugin are contained in a single language file. the language file name is directly derived from the plugin name.
a plugin package can contain as many translations as it wants, although an English one is generally expected.

when installing a plugin that lacks translation to language X on a board that supports language X, the installation infrastructure will contain a "translate it yourself" service for the admin that wishes to install it.

the plugin meta-data contains:
  • information about the plugin: Category, Name, Author, Version, Description
  • A single readme file
  • a list of hooking points. each hooking point is:
    • the hook itself (our "hook_before_post_message" from above),
    • the name of the function to be called call at this point.
      this name will always be prefixed with the plugin name, to avoid name collisions.
    • a call-order directive that can have the values "prefer-first", "prefer-last" or "dont-care"
  • configuration definition, so a plugin that does not require too complex configuration can be configured with a generic configuration service provided by the infrastructure based solely on the metadata.
    if more complex configuration is a must, the plugin can contain a management module (php files and templates) to facilitate this.
  • enough information to facilitate database changes required by the plugin, including uninstall.
    the precise rules of what DB changes are "kosher" for a plugin (if any) should be discussed.
  • list of available languages supported
  • dependency information: minimum infrastructure version required by the plugin, and list of other plugins (if any) which are required for this plugin, including minimum versions of each
  • known incompatibilities: list of *other* plugins known to be incompatible with this one
  • Optional addendum to the FAQ.
Chapter 3: the call_hook() function
The call_hook() function, as shown above, accepts the hook name, and a single by-ref parameter.
it looks at the currently registered addon, and for each of them that registered a hookey to be called at this particular point (as identified by the hook name) it calls them with the by-ref param. after each call it examine the return value. as soon as one of them returns "false", it terminates and return false itself.
it should call all the "prefer-first" hookies before any non-prefer-first hookies, and all "prefer-last" hookies after all the non-prefer-last hookies.
since all the parameter-passing is by ref, every hookie can modify the values to be used by the next hookie or by the original caller itself.
template hooks are similar, except that the parameter that is passed is the template_var, which is, i believe a stateful object.
most typically, a template hook will emit some more html into the template. since it knows nothing about the specific style being used, it should respect all local style parameters.

Chapter 4: Tying it all together
after a new plugin is pushed, (presumably somewhere at a ....../plugins/PLUGIN_NAME/ directory), the user has to go to the "configure plugins" page in the ACP.
the ACP looks at the plugins directory, and find there a new subdirectory. it goes on and read the metadata of the plugin, and adds it to the list. since this plugin was never configured, it appears in the list of disabled plugins.
the user then can view the details (name, author, description, version etc.), configure it (based on the metadata), and eventually enable it.
as soon as the user enable the plugin, we go over all the hookies in this plugin and tie them to all the hooks w have to. (this, of course, i s kept in the database).
when we initialize the code (e.g. at the point we read all the config data from the database) we also read the hooking information and create the global $hooking_info dictionary/structure/object that is used by the call_hook() function.
of course, the same system should allow you to disable existing hooks (including ones that came with the system, i.e., "in the box" ones) at will.


Chapter 5: disabling all hooks
as a safety measure, in case some plugin did something ungodly that actually block the admin from accessing the ACP, we have a safety measure/backdoor: if $_GET['NO_PLUGINS'] == 1, the hook system look at the current logged in user and does one of the three:
-- if it's anonymous, it is redirected to login
-- if it's a regular user, the switch is ignored, and the hooks get called as usual.
-- if it's an admin, no hooks code is executed, and the function returns "true", so in effect the system behaves as if all the hooks are disabled. at this point the manager can get to the ACP and disable the offending plugin.


My Opinion
by placing enough call_hook() calls in the code and templates at the right places, practically no hacks will need to be written.
of stated differently: every time you think you need to write a "real" hack, ask yourself: are there one or twelve places in the code where injecting new hooks would allow me to implement this as a plugin and not a hack?
in 9 cases out of 10 the answer will be "yes" in those cases, new hooks should be injected to the code.
in the one out of ten cases where the answer is "no" ask yourself: "do i really want to do this"? and reply "no". ;)

i did not describe the system that pulls new plugins from the repos. feel free to fill the blanks.

[EDIT]
Added information about metadata, dependency and incompatibility information, some more stuff about translations.
[/EDIT]
Last edited by code reader on Thu Dec 17, 2009 2:39 pm, edited 4 times in total.

User avatar
Kellanved
Former Team Member
Posts: 407
Joined: Sun Jul 30, 2006 4:59 pm
Location: Berlin

Re: Plugins and Hooks

Post by Kellanved »

Well, a phorum - or rather Drupal - style hook system is very crude and not appropriate for 4.0 . The 4.0 architecture, as it is planned at the moment, goes far beyond simple hooks by relying on dependency injection and queued manipulation of data objects. We will see how that will play out.

You might not be aware of it, but a "phorum" style hook system is present in 3.0., although the hooks are mostly placed for wrapping rather than plugins.
No support via PM.
Trust me, I'm a doctor.

code reader
Registered User
Posts: 653
Joined: Wed Sep 21, 2005 3:01 pm

Re: Plugins and Hooks

Post by code reader »

-- the key to a useful hook system is plentiful interspersing of hook calls in the code. this does not exist in 3.0
-- to be complete it should also support hooks in the templates. this, ttbomk, does not exist in 3.0
-- without chaining it's not useful. again, ttbomk this is not part of 3.0
-- without complete *plugin* support in the ACP, including support for configuration, enabling and disabling, finding new plugin when present it can't work.

so i think it's a huge stretch to say that a phorum style hook system is present in 3.0: what i was talking about is not "phorum style hook system", but rather "phorum style plugin system", where hooks are a critical part of the system, but you can't get by by implementing just this part.

the beauty of this system is its simplicity. if you find a system which is very simple and at the same time achieve the goal, it's almost in every single case better than a complex system.

i do not know what exactly do you mean by:
Kellanved wrote:The 4.0 architecture, as it is planned at the moment, goes far beyond simple hooks by relying on dependency injection and queued manipulation of data objects. We will see how that will play
but if this forum is to remain true to its objective, and if you guys are serious in the "open development" statement -
naderman wrote:Starting with phpBB4 we want to try a much more open development process than phpBB used to have. The first step in this direction is opening up the planning process. We want to design a new architecture together with the phpBB community, you!

There are some initial ideas up on our wiki. You can find them here: http://wiki.phpbb.com/PhpBB4. Feel free to add stuff to the wiki. If there's something that requires discussion post it on here and we'll put the result of such a discussion on the wiki.

Discussion can also take place on IRC #phpbb-coding . Results / conclusions should obviously be documented here and / or in the wiki depending on where they belong ;-)
then i think it may be best if someone will describe it here.

peace.

User avatar
Kellanved
Former Team Member
Posts: 407
Joined: Sun Jul 30, 2006 4:59 pm
Location: Berlin

Re: Plugins and Hooks

Post by Kellanved »

code reader wrote:-- the key to a useful hook system is plentiful interspersing of hook calls in the code. this does not exist in 3.0
-- to be complete it should also support hooks in the templates. this, ttbomk, does not exist in 3.0
-- without chaining it's not useful. again, ttbomk this is not part of 3.0
-- without complete *plugin* support in the ACP, including support for configuration, enabling and disabling, finding new plugin when present it can't work.
Well,
1. Hooks are present in the code, but only at places for wrapping. Complete coverage is underway for 3.1
2. The template system is hooked, the output can be altered completely by hooks. This does not meet the expectation for plugins, as we know. The template system is a bit of a problem here, so that I can't promise a good solution for 3.1 beyond offering a few injection points.
3. Of course it is in 3.0, there seems to be a misunderstandment about chaining: 3.0 allows attaching several modules to one hook. I was talking about an architecture consisting of chained elements that makes hooks obsolete
4. work in progress for 3.1

Generally, we will post everything as soon as it is written as RFC. We can't yet paste items straight out of our heads, sorry.
No support via PM.
Trust me, I'm a doctor.

code reader
Registered User
Posts: 653
Joined: Wed Sep 21, 2005 3:01 pm

Re: Plugins and Hooks

Post by code reader »

i did not understand the
Kellanved wrote:2. The template system is hooked, the output can be altered completely by hooks. This does not meet the expectation for plugins, as we know. The template system is a bit of a problem here, so that I can't promise a good solution for 3.1 beyond offering a few injection points.
does this mean the template engine is hooked, or that it can handle <!-- {HOOK name} --> ?
if the former, it's not really useful.
if the latter, could you point me to some reference?

thanks,
Kellanved wrote:Generally, we will post everything as soon as it is written as RFC. We can't yet paste items straight out of our heads, sorry.
i do not and did not mean to berate anyone, and if i sound so then please forgive me.
however, as far as i understand the purpose of this forum, it should be perfectly OK to post WIP, long before it's a shining RFC with beginning, middle and an end.
bits and pieces would be better than nothing.

and just to clarify: i am not in love with "my" design, especially as it's not really mine.
i was just trying to get the wagon rolling in one of the key areas, at least as i see it.
if indeed the direction is minimalistic kernel and everything that *can* be implemented as plugin *is*, then the details of the plugin system becomes of utmost importance to the project, practically make or break.



peace.
Last edited by code reader on Wed Dec 16, 2009 12:23 am, edited 1 time in total.

User avatar
Kellanved
Former Team Member
Posts: 407
Joined: Sun Jul 30, 2006 4:59 pm
Location: Berlin

Re: Plugins and Hooks

Post by Kellanved »

In 3.0: the former. You can alter the HTML after the template engine is done. 3.1 will see <!-- HOOK {NAME} -->, related to the dynamic includes used in the 3.0 captcha plugins -- just looped to include all hooking plugins.
No support via PM.
Trust me, I'm a doctor.

code reader
Registered User
Posts: 653
Joined: Wed Sep 21, 2005 3:01 pm

Re: Plugins and Hooks

Post by code reader »

[bump]
edited the opening post.
[/bump]

you may want to re-read the opening post. i believe the system i describe is a bit more elaborated than phorum's plugin system.
i am not familiar with drupal's.
even if 4.0 will sport a more sophisticated plugin infrastructure that does not use hooks as the one i described, you may still want to read it - maybe it has one or two good ideas that can be used in 3.1 plugin system which *does* use hooks.

IMO, this system might be good enough even for 4.0.
the main difference is that with 3.1, i assume that all the 3.0 functionality is provided in a monolithic manner similar to 3.0, while in 4.0 the intention is to extract a lot of the "core/in-the-box" functionality outside of the monolithic kernel.
since the 3.0 feature set is very rich, the plugins would only replace 3.0 MODs.
unlike 2.0, with 3.0 the feature set is rich enough that many boards are using very small number of MODs or none at all.
with 4.0, the naked kernel would be almost useless, and a lot of functionality, including stuff which was available in 2.0 is provided in the form of plugin.

peace.

Post Reply