Extension:ArticleProperties

From Organic Design wiki

MediaWiki has a page properties table which is used to store and manipulate named property lists for articles. The parser includes the required hooks to integrate with this properties system in an event-driven way so that other functionality that depends on these values can be prompted to update their state when changes occur.

Since template parameters play such an important role in wiki based data structures, it makes sense that the named parameters of the template should be stored in the properties table, so that templates can effectively become objects that have both properties and methods.

It also allows much more efficient querying of properties defined in template syntax since these queries can be carried out directly on the properties table rather than having to convert wikitext which is much more expensive even with caching.

The first useful application would be to change the #recordtable parser-function to use the properties table instead of referring to the wikitext. The RA extension has methods for converting to and from value-arrays and wikitext template syntax, so this could be implemented easily be effectively using the properties table as a "live" cache tied into those two methods. But also the queries in the parser-function should be updated too since they no longer need to refer to the text field of the articles.

ArticleProperties extension

I've created a new extension called ArticleProperties which creates a new ArticleProperties class that is a sub-class of Article. It main purpose is to add a properties method allowing named properties to be read from and written to an articles article_properties table.

Note that the page_props table actually already has a use and can't be used for general property storage like this, so I've made the extension create a new table called article_properties instead. I've added a column for namespace too which will make querying the properties more efficient since the namespace serves as the type, or class of property set.

+--------------+---------------+------+-----+---------+-------+
| Field        | Type          | Null | Key | Default | Extra |
+--------------+---------------+------+-----+---------+-------+
| ap_page      | int(11)       | NO   |     | NULL    |       |
| ap_namespace | int(11)       | NO   |     | NULL    |       |
| ap_propname  | varbinary(30) | NO   |     | NULL    |       |
| ap_value     | blob          | NO   |     | NULL    |       |
+--------------+---------------+------+-----+---------+-------+


It also provides a hook called "ArticlePropertiesClassFromTitle" which allows its sub-classes to easily define rules by which they should become the class used for a MediaWiki page, for example a specified namespace could use a specific ArticleProperties class instead of the standard Article. In this example, the FooArticle class will be used if the article is in the NS_FOO namespace:

{{{1}}}


These sub-classes can use view(), edit() and save() methods to override the default article functionality. The edit method allows new form fields to be added to the edit form, and the save method allows these to be processed and written into the page_props table. To continue the example above, here's s possible definition of the FooArticle sub-class which creates an additional property.

{{{1}}}

The input and label methods are supplied by the ArticleProperties class (along with a number of other useful methods for constructing forms and dealing with page properties). It creates an input named wpFoo and a label for it using an i18n message. The save method then writes this value into the page properties. Any existing value will automatically be shown in the input field.

The ArticleProperties class also provides a query method which allows conditions and options to be sent in the same format used by the SQL Database::select method, and it returns a list of Title objects for matching articles.

And it also provides a table method that allows a list of titles to be rendered as an HTML table. The method takes three parameters, the second two are optional. The first is the title-list, the second an array of HTML attributes such as class and id that the resulting table should have. And the third parameter is an array of columns that the table should use. If the columns are not provided, they will be extracted from the properties of the first article from the title list.

ArticleProperties 2.0

After using the extension in a real development project for a while, it became obvious that using a single table for all the different ArticleProperties sub-classes was an unnecessary complication and a serious limitation to performance.

For this reason, the article_properties table has now been deprecated and each ArticleProperties sub-class now has some static class variables to specify its own database table name and structure. This involves three new static variables, table which is the name of the database table the class will store it's instances data in, columns which determine the property names and their database data-types, and an option prefix to use for column names so they don't conflict with column names of other tables. A special page called Special:ArticleProperties has been created to create the tables for these sub-classes or to add new columns to them. Here's a basic example class:

{{{1}}}


A column called "page" is automatically added which will contain the page ID of the MediaWiki article that the properties apply to. There is only a single row for any given page.

+------------------+-------------+------+-----+---------+-------+
| Field            | Type        | Null | Key | Default | Extra |
+------------------+-------------+------+-----+---------+-------+
| example_page     | int(11)     | NO   |     | NULL    |       |
| example_lat      | float       | YES  |     | NULL    |       |
| example_lon      | float       | YES  |     | NULL    |       |
| example_streetno | varchar(8)  | YES  |     | NULL    |       |
| example_street   | varchar(32) | YES  |     | NULL    |       |
| example_city     | varchar(32) | YES  |     | NULL    |       |
| example_postal   | varchar(16) | YES  |     | NULL    |       |
| example_country  | varchar(32) | YES  |     | NULL    |       |
| example_notes    | text        | YES  |     | NULL    |       |
+------------------+-------------+------+-----+---------+-------+

Passive and non-passive instantiations

Another aspect that has been found to be required is a way for the sub-classes constructors to differentiate between a "passive" instantiation used for example to call methods on ArticleProperties items in a search result, and non-passive instantiation which occurs when the instance represents the wiki article being currently viewed. The constructor needs to know because the class may make adjustments to the skin or other global elements of the system in the latter case, but should leave them alone for passive instantiations.

When the ArticleProperties class creates one of the sub-classes via the ArticleFromTitle hook it calls the constructor along with the extra $passive parameter set to false. The following example demonstrates how a sub-class defines its constructor to make adjustments to the skin in the non-passive case.

{{{1}}}

ArticleInstances extension (possibly include functionality in ArticleProperties)

This extension adds further functionality to the ArticleProperties class by allowing a special-purpose property to exist in ArticleProperties articles called "instances".

This property is a list of classes and instances (names of other ArticleProperties classes or ArticleID values of actual articles of these type). Whenever a method is executed in an ArticleProperties instance, each instance ID in it's instance list will be checked to see if it implements that method, and the method called if so. In the case of the item in the instance list being a class-name instead of an instance ID, the class will be instantiated and will have a "parent" property that refers to the instance that had it in it's list (so that it can access the parent instance and modify it's properties if necessary). This allows the ArticleProperties instances to behave together as if inherited from one-another using multi-inheritance.

An example usage of this functionality could be a "AuthoriseByTxt" class. Another Articleproperties class such as a User could then click a checkbox in their preferences that implements an instance of the AuthoriseByTxt class. This new class can then be responsible for carrying out and presenting the current state of the authorisation procedure in the user's home page.

The normal revision text of the article can act as a kind of historical log of activity for the instance. When it's finished it removes itself from the parent context and may delete all its properties, but it still exists as still at least one initial revision in history.

TemplateProperties extension

Another extension called TemplateProperties then extends the ArticleProperties concept by tying in to the events of a specified list of templates (similar to the concept of "record" articles in RecordAdmin). It adds events so that the named parameters in these specified templates are synchronised with the article's properties.

The extension also adds three parser-functions to allow access to the property information from within article text. The three parser-functions allow for the retrieval of a single property, a query resulting in a simple list, and a query resulting in a sortable table respectively.

These queries retrieve their data from the article properties so that no text parsing is necessary. But if any value being requested doesn't exist in the page_props database table, then it is extracted from the text (if it exists in the text) and added to the table before being returned.

When the template values are changed by an article's text being edited, the new values are extracted (or possibly obtained by hooking in to the parser's information on the current values, and the page_prop table updated.

It would also make sense for this extension replace RecordAdmin by making it add fields to the edit form for editing the article properties and removing the template syntax from the article.

See also