This is a MediaWiki programming issue; if you're only interested in admin stuff, you can safely delete.
So, I'd like to set up a system of hooks and filters for MediaWiki. We have right now four ways to change how MediaWiki works:
1. Tag extensions. You can add new tags that the parser can generate code for. 2. Special pages. You can add special pages that do different kinds of queries. 3. Edit filtering. You can put a pre-filter on editing. 4. Skin changes. You can create new skins.
However, we don't have an easy way to change the behaviour of mainline functionality. I think it would be a good idea to add some simple hook processing to MediaWiki, so that extensions can add hooks and run custom code when something happens.
Consider, for example, an extension to log key actions in the wiki to a specialized logging system. The extension setup function could look something like this:
function setup_logging { global $wgLogFile; wfAddHook('after_article_save', log_article_save, $wgLogFile); wfAddHook('after_delete', log_deletion, $wgLogFile); wfAddHook('after_user_ban', log_user_ban, $wgLogFile); }
By calling the wfAddHook() function, the extension asks that a function get called if/when an event happens. wfAddHook() takes three arguments: the name of the event (say, after an article is deleted), a function to call, and an optional data block that can be used by the function. This way, we can use the same function for different hooks or different actions, like:
wfAddHook('after_article_save', irc_notify, 'brion'); wfAddHook('after_article_save', irc_notify, 'TimStarling');
A hook function would look something like this:
function log_deletion(&$params, $data) { $title = $params['title']; $dbkey = $title->getDBkey(); $filename = $data; foo_log_message("Article '$dbkey' deleted.", $filename); return true; }
The $params argument here is an associative array of the event-specific parameters. We use this instead of named arguments so that the same function could be used for different events. The $data is just the data item that was used when the hook was added.
Hooks can return four possible values:
* true -- the hook has operated successfully and subsequent hooks should be run * false -- the hook has operated successfully but no subsequent hooks should be run * "some string" -- an error occurred; processing should stop and the error should be shown to the user * NULL -- the hook has successfully done the work necessary and the calling function should skip
The last result would be for cases where the hook function replaces the main functionality. For example, if you wanted to authenticate users to a custom system (LDAP, another PHP program, whatever), you could do:
wfAddHook('before_user_login', ldap_login);
# ...
function ldap_login(&$params, $data) { $user_id = $params['user_id']; $password = $params['password']; # log user into LDAP return NULL; }
Note that a reference to the parameters is passed to the hook function: the hook could theoretically change its parameters, like so:
wfAddHook('before_article_save', reverse_title);
# ...
function reverse_title(&$params, $data) { $old_title = $params['title']; $params['title'] = Title::makeTitle($old_title->getNamespace(), strrev($old_title->getDBkey())); return true; }
A calling function or method would use the wfRunHooks() function to run the hooks related to a particular event, like so:
class Article {
# ...
function submit(...) { $params['title'] = ...; $params['user'] = ...; $params['section'] = ...; $params['is_new'] = ...; if (wfRunHooks('before_article_save', $params)) { # save the article wfRunHooks('after_article_save'); } }
wfRunHooks() returns true if the calling function should continue processing (the hooks ran OK), or false if it shouldn't (an error occurred, or one of the hooks handled the action already). Checking the return value matters more for "before_*" hooks than for "after_*" hooks.
The big advantage to this event-handling approach is that we can start isolating site-specific features into extension files. The "mainline" code only concerns itself with "mainline" features, and "extension" code can handle more exotic ones. It simplifies our mainline code, centralizes extension features into one easy-to-comprehend package, and hopefully improves our quality and reliability. (The simpler our mainline code is, the fewer bugs it will have; the easier it is to read, the more people will want to help maintain it.)
It should also help us evaluate/implement experimental new features, and obviate the need to patch the mainline code to do so. Lastly, it could let us move little-used features out to extension files to simplify the main code.
There are disadvantages, of course, too. If MediaWiki is only supposed to work for a single wiki installation, or multiple installations that should behave exactly the same, then the hooks code is unnecessary -- we should just code it all in the mainline code. There's also some additional complexity in the mainline code in setting up the parameters and calling the hook functions; this can be balanced against the complexity of adding each extension's code into the mainline functions.
Finally, there is a lot of documentation that would need to be done to say 1) where hooks are defined and 2) what parameters they provide.
Anyways, I'm going to post this to meta, and implement it for 1.4. But I figured this would be a good forum for discussion -- hopefully making the feature better.
~ESP
I am still very excited about this prospect but I haven't gotten any feedback on the problem I was having with passing references through the hook method.
http://mail.wikipedia.org/pipermail/wikitech-l/2004-December/026533.html
Once possible way to make it easier to make sure that the refs get through (using php4 at least, I imagine that php5 will take care of some of these issues), is to bundle up all the parametes within dictionaries, thereby fixing the signature of all hook methods and avoiding the get_func_args. This would also make it easier to add more parameters to the hook methods in the future without breaking old hooks. Besides, when you start passing around longer lists of parameters, named parameters are a bit easier to manage, since the order doesn't matter.
Beyond this suggestion, a friend of mine threw out the idea of implementing this functionality using the interceptor pattern
something like this: http://www.jroller.com/comments/deep?anchor=aop_fun_with_javascript
but that is probably more trouble than it is worth for now.
It looks like this hook infrastructure made it into 1.4, so there may not be a chance for the parameter packaging modification, but I think it might be worth the effort.
Any comments?
Jonah
Heli Retzek wrote:
that is really a great and very useful plan !!
So, I'd like to set up a system of hooks and filters for MediaWiki. We
HeliR
wikitech-l@lists.wikimedia.org