Extending Mediawiki
May 8th, 2006 by Karen
I spent the better part of the end of last week working on extending Mediawiki for our institution. One thing that was really important to me was being able to add users to Mediawiki from our Active Directory user and assign them to specific group. Normally, the way Mediawiki works I would have to wait for someone to sign in before I could assign them to a particular group. This is annoying if you have wikis that you only want specific people to edit. For example, I’ve been working on moving our policies and procedures for the Libraries website into a wiki. I want the members of the committee who are responsible for updating this document to be able to edit it but not anyone else. That would normally mean asking all the committee members to login to the wiki and then assigning them the proper group capable of editing. The same is true for being able to give system administrator privileges to the rest of the systems staff.
To deal with this problem I’ve be writing a Special Page that will display all of our Active Directory user and allow them to be added to as Mediawiki user to specific users. I’ve also made this page only visible to systems administrator so noone at random can add users. The experience of writing this Special Page has been rather daunting. Not because I’m a terrible programmer but because there isn’t great documentation on how to extend Mediawiki. So I’ve been working slowly by grabbing snippets from there and there on the web. Mediawiki has functions and classes that let you extend the base program. However, you have to be able to read the base documentation to understand what different classes do. This has been very frustrating for me. Because what I want to be in the documentation isn’t there. I want is something that says this function does this pass it these arguements in this form. I’ve yet to find anything exactly like this. So I’ve been working backwards from snippets of code that do similar things to what I want.
In particular I wish I understood the framework for accessing the MySQL database that drives the wiki. I understand database design and know where everything lives in the Mediawiki database. However, I don’t know how to get at it. Okay, I could use the brute force method of writing straight PHP code to query and update the database. However, this is a waste of coding effort and silly because Mediawiki itself does this all the time so it must have classes and functions to perform these tasks. After considerable digging I was able to grasp some basics about how the database API works. I’m going to share a little bit about what I learned.
First, there are two ways of interacting with the database in Mediawiki: DB_MASTER, and DB_SLAVE. Only use DB_MASTER if you intend to write information to the database. If you are just retrieving information then use DB_SLAVE. Basic queries are very simple to do with the database API. I’ve included some examples. However, if you have a more complex query you can use the query() function. I haven’t played with this and according to what I read it requires a great deal more savvy then the select() and insert() functions.
Insert query
$dbw =& wfGetDB( DB_MASTER );
$dbw->insert( 'user',
array(
'user_name' => ucwords($username),
'user_email' => $email,
'user_real_name' => $realname ),
$fname,
'IGNORE' );
Abstract version
$dbw =& wfGetDB( DB_MASTER );
$dbw->insert( 'table_to_insert_into',
array(
'fieldname' => 'value_to_insert',
'fieldname' => 'value_to_insert2'),
$fname,
'IGNORE' );
I also struggled to figure out how to get data out of the database using a select query in order to either print that to the screen or assign the values to variables. Below is a code example on how to do this.
Select Queries
Getting a Single Row
$dbr =& wfGetDB(DB_SLAVE);
$res = $dbr->select( 'user', array('user_id'), array( 'user_name' => 'librarian' ) );
$row = $dbr->fetchObject( $res );
$userID = $row->user_id;
$dbr->freeResult( $res );
The second array in the select statement is a WHERE SQL clause. So what I’m doing here translates into the following SQL statement:
SELECT user_id FROM user WHERE user_name =’librarian’ .
Abstract version
$dbr =& wfGetDB(DB_SLAVE);
$res = $dbr->select( 'table_to_select from', array('fieldname', 'fieldname2'), array( 'field_to_match' => 'value' ) );
$row = $dbr->fetchObject( $res );
$userID = $row->fieldname;
$dbr->freeResult( $res );
Retrieving multiple records and printing them to a table
$dbr =& wfGetDB( DB_SLAVE );
$res = $dbr->select( 'user', array('user_id', 'realname', 'email') );
$wgOut->addHTML ("<table>");
$wgOut->addHTML ("<tr><th>User ID</th><th>Real Name</th><th>Email</th></tr>");
while ( $row = $dbr->fetchObject( $res ) ) {
$wgOut->addHTML ("<tr><td>" .
$row->user_id . "</td><td>" .
$row->realname . "</td><td>" .
$row->email . "</td>");
}
$dbr->freeResult( $res );
This example has some sample code of how things are printed to the screen in Mediawiki. The basis idea with this example though is that the while statement allow you to loop through all the rows printing the relevant fields using the $row->fieldname syntax.
There appear to be functions for updating and deleting from as well. I haven’t used them yet but here is my basic understanding of them.
Update
$dbw =& wfGetDB( DB_MASTER ); $dbw->update( 'table_name', array( 'field_to_update' => $value_to_update_to ), array( 'field_to_match_on' => $value_to_match ) );
Delete
$dbw =& wfGetDB( DB_MASTER ); $dbw->delete( 'table_name', array( 'field_to_match' => $value_to_match ), $fname );
Getting to this point made me want to pull my hair out. Mostly because open source applications are typically written to be extended and they code is reusable. However, without good documentation (and examples PLEASE!) the code base is only extendible to those who have a programming background and can read the overwhelming documentation. (I’m mostly self taught and that has its downsides at times. This being one of them.)
When I was working with Movable Type one thing that made my life easier was that were good examples of how to use the database API in Movable Type. This made writing some custom code MUCH easier. Since I couldn’t find something like this for Mediawiki, the stuff here is the start of my personal compendium of what I learn about the database API. In addition to helping me document what I’ve done, maybe my notes will make some other folks lives easier.


This is very useful information indeed - thank you! I do a lot of work at mediawiki.org, where we are trying (amongst other things) to build a comprehensive technical manual for the MediaWiki software. Would you consider licensing this article under the GFDL and allowing us to include it on the site? I may not remember to check back here, but you can contact me through my e-mail or via my user page at mediawiki.org (http://www.mediawiki.org/wiki/User_talk:HappyDog) if you have any questions.
I have also been frustrated by the documentation for MediaWiki in my efforts to customize and extend it for use at the company at which I’m currently working.
The ironic part is that the documentation has been assembled in a Wiki itself and I worry a little that this approach is not necessarily conducive to compiling a detailed manual which should have relevancy to different levels of expertise.
Using a wiki for documentation isn’t necessarily a bad thing. What you are seeing with the lack of documentation isn’t a result of the technology. In my opinion things go wrong when people don’t contribute enough information so that all portions of functionality are covered thoroughly. The ideal of having documentation maintained by a large user group is a good one. However, someone need to take responsibility for seeing that the salient information is documented. So anything that is a critical part of the generated codebase should be documented in normal language in the wiki document.
Thanks a lot! This entry has really helped me.
Hey, great article. I’m writing an extension for MediaWiki right now, and I was looking for some samples on interfacing with the database. This is perfect.
Very useful information. I spent a lot of time looking on the MediaWiki site such a tutorial with no luck. Thanks for sharing.
I’m currently trying to write an extension for MediaWiki, and this has helped me greatly. Thanks for the information!
Very helpful indeed. I realize the original post is now a bit old, but perhaps you still retain the information you used to accomplish this.
Is there an authoritative reference source for this API? Can you include a link please?
My select queries need to be a little more complicated than simple single-table fetches that the arrays of field names and where terms models. I presume the API permits more complicated queries, and probably has a function for precisely what I’m trying to do (externally retrieve the filesystem’s filename of the latest version of a given image file) and indeed probably most likely also has a function that takes straight SQL.
Links to references and sources always appreciated!
The API is documented (sort of) in the file /includes/Database.php . Chet, you might be looking for the “query” function (I haven’t used this function directly myself).
One thing that isn’t obvious: Database changes are not committed until the who PHP page finishes. So if you have a die() statement (or anything else that finishes processing the rest of the page) then your database statements will not take effect.
Also the $fname variable seems to be for debugging purposes only, to identify the function which is currently running. I can’t find any documentation to that effect, but it seems to be used that way in the source code.