Extension:ArticleProperties

From Organic Design wiki
Revision as of 17:19, 31 May 2012 by Nad (talk | contribs) (table: desc)

This extension was created in early 2012 and is available from our extensions repository here. The extension which creates a new ArticleProperties class that is a sub-class of Article. As the name indicates, the extensions main idea was to provide a mechanism by which different classes of articles could be created that each have their own collection of persistent properties.

The ArticleProperties class is an abstract class (one that's designed to be sub-classed, and not to be instantiated directly). It provides the common functionality allowing all its sub-classes to declare the names and types of properties that should be associated with each article if that type. This common class also offers a simple means by which the page can render its MediaWiki actions in their own specific ways.

Each ArticleProperties sub-class has three 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 allows the creation of the tables for the sub-classes or to add new columns to them.

Simple example

Here's a basic example ArticleProperties sub-class definition.

{{{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. Here's the "locations" table created by the ArticleProperties class for the sub-class shown above.

+------------------+-------------+------+-----+---------+-------+
| 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    |       |
+------------------+-------------+------+-----+---------+-------+


Determining which class a page should instantiate as

The extension 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 sub-class instead of the standard Article. In this example, the LocationExample class defined above will be used if the article is in the NS_FOO namespace:

{{{1}}}

Overriding default MediaWiki actions

Not only does the ArticleProperties class allow its sub-classes to have persistent properties, but it also allows the default rendering, editing and saving actions to be overridden so that they can incorporate their properties appropriately. A number of other methods are provided for making interaction with the properties easier which are described in more detail below.

The 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 an edit and save method added to integrate the page with one of the persistent properties (the Notes 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 wpNotes 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.

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 instances in a search result, and "non-passive" instantiation which occurs when the instance represents a 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}}}

JavaScript integration

Often ArticleProperties sub-classes have JavaScript aspects to their view and edit methods and these client-side code needs to have access to some of the instances properties. The ArticleProperties class provides a simple solution to this which is to add an array to the sub-class that defines the object properties which should be made available to the client side. These will be placed into a JavaScript object of the same name as the ArticleProperties sub-class. Here's an example continuing with the "ExampleLocation" class defined above.

{{{1}}}

This makes two of the persistent properties available to the JavaScript as window.LocationExample.Lat and window.LocationExample.Lon.

Main ArticleProperties methods

properties

The central method of the ArticleProperties class is the properties method, which is the basic interface to an article's persistent properties. It takes just one parameter which is an hash of properties to read or write. The hash key is the property name, and the value is either null which indicates a request for the value to be read from the database, or anything else which indicates a value to write to the database. In this way a number of properties can be read and written with a single function call. If no parameter is apssed at all, or the array is empty, then all the current properties will be returned.

dbGetValue

This properties method above sends any value retrieved form the database via this method first. This method takes a property name and value as parameters and by default simply returns the value unchanged, but its presence allows sub-classes to process the values that are retrieved from the database by the properties method. This is useful for exotic types of properties such as dates, currencies, lists or objects that require some kind of standard formatting or de-serialisation after the read from the database as plain-text.

dbSetValue

This is the corresponding method to dbGetValue but does the processing before the data is stored such as "unformatting" or serialising. Note that dbGetValue and dbSetValue are internal methods that should not only ever be called by the ArticleProperties::properties method under normal circumstances. Their purpose is to be overridden by the sub-classes, but not directly called by those sub-classes.

getValue

This is a simpler method than properties to call if the value of just one property is wanted, the name of the property is passed and its current value is returned.

setValue

This is a simpler method than properties to call if the value of just one property needs to be updated the name of the property is passed as the first parameter, and its new value as the second parameter.

updatePropertiesFromRequest

Many classes of page based on ArticleProperties will need to allow the wiki save function to some of the properties. Many of these values will come from the $wgRequest object after a form in the edit view of the page has been submitted. This method allows takes a single parameter listing the names of properties to be extracted from the form submission request and stored into the properties. The method expects the forms values to have the same names as their corresponding property names but with the convention of a preceding wp.

query

Most of the database queries done that involve an articles properties are a request of a matching list of pages (instances of ArticleProperties sub-classes) which can all be referred to by a normal Title instance. This method allows such queries to be simplified by accepting as parameters just the name of the ArticleProperties sub-class that the resulting titles should be of, an optional array of the SQL conditions for the query and an optional array of the SQL options for the query. The result is an array of Title objects referring to the pages that match the query, or an empty array if there were no matches.

HTML rendering helpers

table

One of the most common things that need to be done with a list of titles of ArticleProperties pages such as is returned by the ArticleProperties::query method is to format selected properties of the results as an HTML table to be sent to the client. This method does this job and takes three parameters, first the array of Title objects, second an optional array of HTML attributes that the table should have, and third an optional list of property names required for the table columns (all are used if no list is supplied).

label

input

inputRow

select

options

textarea

Hooks

ArticleFromTitle

ArticlePropertiesClassFromTitle

EditFormPreloadText

EditPage::showEditForm:fields

ArticleSaveComplete

ArticleDeleteComplete

TemplateProperties extension

Another extension which is still in development 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