Repligard-safe applications

There are several things about application writing that touch replicateability. Originally Midgard used server-specific id numbers for referring to objects in the database.

When replicating, local ids change to whatever is available on the target server. Instead, application writers should use GUIDs or names for referring to objects.

The issues for proper replicated applications have been addressed many times in Midgard development.

The first attempt at this was a year and half ago when addressing of topics and articles by a name was enabled in Midgard-PHP. Example: Use mgd_get_article_by_name(topic id, 'article name'); instead of mgd_get_article(id);

However, the name functions still require using of local ids when referring to root topics. Of course, the topic id could first be dynamically queried by using a series of recurring mgd_get_topic_by_name queries starting from the topic id 0. Example:


$topic = mgd_get_topic_by_name(0, 'Company');

$article = mgd_get_article_by_name($topic->id, 'Contact us');

When writing applications, many developers refer to objects by statically writing id numbers to the application code. However, this will not work after replication. For solving this, the named functions provide a working, if cumbersome solution. However, not all Midgard objects are available through names.

As another solution, we have defined the GUID system for providing a method of addressing documents that is uniformal on any Midgard installation, and is still relatively quick to use.

To provide the GUID information for an object, a guid() method was added to all objects, and for retrieving objects based on GUIDs, a function mgd_get_object_by_guid was added. Example:


$topic = mgd_get_object_by_guid("af3a4eafe7a83bca73323421");

if ($topic) {

    $article = mgd_list_topic_articles($topic->id);

    if ($article) {

       while ($article->fetch()) {

	    ...
       }

    }

}

By using GUIDs for referring to all objects, your application will be completely replication safe, as Repligard maintains relations between GUID entries, and local ids of objects.

How to write code to support these new addressing methods depends on how your original code has been written. It may even require complete redesign of your code.

However, at its easiest, it requires only replacing original local ids with GUIDs retrieved from the repligard table. Example:


$ mysql midgard

mysql> select guid from repligard where id=123 and realm='article';

Example 2:


$ export ID=123
$ export TYPE='article'
$ echo "select guid from repligard where id=$ID and realm='$TYPE';" | 
mysql midgard | tail +2

This method solves most problems with replicateable applications. Current Midgard administration interfaces do not show GUID information for objects.

In the future, Repligard will probably be able to provide GUID information with some commandline argument.

Once you have changed your application to refer to objects by GUIDs, you can freely use their properties to refer to other objects. As these properties (like up) are dynamically retrieved with each query, they will be consistent for the local database. Example:


$topic = mgd_get_object_by_guid("892d9343acc66c0a730fd5e6ffc6cbdf");

$article = mgd_get_article_by_name($topic->id, "Contact us");

It does not matter whether the application worked on is a real application that you want to distribute, or a web site prepared for moving to production server. As long as you use GUIDs, the applications should be distributeable.

When you are packaging an application, you must assure that all objects references in the application go into the package. Because of this, the replicate statements in the Repligard configuration file should be used to refer to them.

Currently Repligard does not know how to inherit objects from an upper dependency level. For example, if you have specified a page in the resource statement, also the page elements will be replicated. However, as the page usually does not refer to a style (common case is to inherit style information from upper level which in case of page is host), Repligard will not replicate it, even while the host refers to it because relation between pages and hosts is unidirectional (reverse link creates one to multiple relation which couldn't be solved easily and you end up selecting manually from which host style information should be retrievied)

All distributeable applications should be owned by person 0, the Midgard Administrator, as that is available on all Midgard systems. Otherwise regular user accounts might be replicated as well.

After Repligard has produced the XML file, it can then be put to a web site with some documentation for distribution.

The problems also come from internationalization. Since Repligard's XML format will support only one encoding per file, this can mess up localized translation catalogues in your application. Because of this, it is a good idea to distribute the application code in one package, and each translation catalogue as its own package file.

At the moment, translation catalogues are best stored as snippets, which can then be referred to using the snippet path, which is replication safe. This way the snippet name can be the locale, which helps usage within the application. Example:


mgd_include_snippet("/my/snippet/path/$lang");

Another option is to store the translation catalogues as page or style elements. However, this will make mod_midgard load all catalogues from the database, causing some overhead. Example:


mgd_eval("?><($lang)><?");

If your application has images or other files, it is best to store them as BLOBs. This way they will be embedded to the replication XML file, and will be installed automatically alongside the application package.

If the files are big, it might be better for perfomance reasons for to keep them in file system.