<?xml version="1.0" encoding="utf-8"?>
<!-- generator="FeedCreator 1.7.6(BH)" -->
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Midgard RFCs</title>
    <subtitle></subtitle>
    <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/"/>
    <id>http://www.midgard-project.org/development/mrfc/</id>
    <updated>2012-02-08T20:04:34+00:00</updated>
    <generator>FeedCreator 1.7.6(BH) (info@mypapit.net)</generator>
    <link rel="self" type="application/atom+xml" href="http://www.midgard-project.org/development/mrfc/atom.xml" />
    <entry>
        <title>mgdschema and namespaces</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0049/"/>
        <published>2010-01-10T17:03:26+00:00</published>
        <updated>2010-01-10T17:03:26+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-11883fe8fe0a11deb8704f25148042a842a8</id>
        <author>
            <name>indeyets@gmail.com (Alexey Zakhlestin)</name>
        </author>
        <content type="html"><![CDATA[
<h1>Revision History</h1>

<ul><li>2010-01-10, created by Alexey Zakhlestin and Jarkko Ala-Louvesniemi</li>
</ul><h1>PROBLEM</h1>

<p>Modern programming languages have concept of namespaces within them. Midgard, historically, used underscores as pseudo-namespacing tool, but these days we try to use real namespaces in python (and in php soon). Using namespaces in python led to the following code:</p>

<pre><code>obj = midgard.mgdschema.midgard_article()
</code></pre>

<p>This code mentions "midgard" 2 times which doesn't look nice. Direct approach to fixing this leads to bad hacks and breaks backwards compatibility. See <a href="http://trac.midgard-project.org/ticket/1559">bug #1559</a> as an example. It removes <em>midgard_</em> prefix from all type-names, which can result in names-conflict if there is some type which had the unprefixed name. Clearly a fully designed approach is needed because the API can't change in every Midgard release and we can't support multiple legacy syntaxes.</p>

<p>This document is a proposal for discussion on implementation, which would work as the long-term solution for all future language bindings.</p>

<h1>SOLUTION</h1>

<p>We propose to add explicit &lt;namespace&gt; tag in schema declaration file. Namespaces are supposed to have &lt;class&gt; tags as their children. On the side of language binding it might be translated either to true namespaces (python, php-5.3, etc.) or in pseudo-namespaces (php-5.2) depending on what binding author want/can do. For namespace-capable bindings we propose to use <em>midgard.schema</em> as the root namespace for everything.</p>

<p>It is recommended to prefix table names with <em>namespace_</em>. It shouldn't be enforced, but as a recommended practice would prevent table name conflicts and ease database-management (all tables would be grouped by component, if listed alphabetically). "<em>table</em>" attribute of &lt;class&gt; tag is optional (if left out, table name would be <em>namespace_</em>class) and it is recommended to leave it unset (less coupling between code and actual database implementation).</p>

<p>For backwards compatibility reasons, old syntax with missing namespace tags and &lt;type&gt; tags should still be supported. In this case class should be put in <em>midgard.mgdschema</em> (note that it is <em>mgdschema</em>, not <em>schema</em> as in first clause) namespace. This is a <em>strictly</em> backwards-compatibility option. Such files must not be distributed with Ratatoskr.</p>

<h2>schema:</h2>

<pre><code>&lt;namespace name="core"&gt;
    &lt;class name="host" table="core_host"&gt;
        …
    &lt;/class&gt;

    …
&lt;/namespace&gt;

&lt;namespace name="my_component"&gt;
    &lt;class name="host" table="my_component_host"&gt;
        …
    &lt;/class&gt;

    …
&lt;/namespace&gt;
</code></pre>

<p>And compatibility mode:</p>

<pre><code>&lt;!-- Compatibility example --&gt;
&lt;type name="midgard_host" table="host&gt;
    …
&lt;/type&gt;

&lt;type name="my_component_host" table="my_component_host"&gt;
        …
&lt;/type&gt;
&lt;!-- /Compatibility example --&gt;
</code></pre>

<h2>python:</h2>

<pre><code>obj = midgard.schema.core.host()
obj2 = midgard.schema.my_component.host()

# we can use class-name directly, instead of string. python allows it
qb = midgard.query_builder(midgard.schema.my_component.host)


# this should also work
from midgard.schema import core
from midgard.schema.my_component import *

obj = core.host()
obj2 = host()
qb = midgard.query_builder(core.host)
qb2 = midgard.query_builder(host)
</code></pre>

<p>and for "compatibility" mode:</p>

<pre><code>obj = midgard.mgdschema.midgard_host()
obj2 = midgard.mgdschema.my_component_host()
qb = midgard.query_builder(midgard.mgdschema.my_component_host)

# string-parameter should work for "old schemas" in ratatoskr too (with deprecated-notice)
# (strings translate to classes under the midgard.mgdschema namespace only)
qb = midgard.query_builder('my_component_host')
</code></pre>

<h2>php 5.3+:</h2>

<pre><code>$obj = new midgard\schema\core\host();
$obj2 = new midgard\schema\my_component\host();

// in php we can't pass class as parameter. have to use string.
// (use single quotes because with double quotes e.g. \n wouldn't work like expected)
$qb = new midgard\query_builder('midgard\schema\my_component\host');

// but this should work
$qb = midgard\schema\my_component\host::new_query_builder();


// and this
use midgard\schema\my_component as my;

$qb = my\host::new_query_builder();
</code></pre>

<p>and for "compatibility" mode:</p>

<pre><code>$obj = new midgard_host();
$obj2 = new my_component_host();

$qb = new midgard_query_builder('my_component_host');
$qb2 = my_component_host::new_query_builder();
</code></pre>

<h2>php 5.2:</h2>

<p><em>if we continue to support php 5.2…</em></p>

<pre><code>// "core" is represented as "midgard_" for historical reasons
$obj = new midgard_host();
$obj2 = new my_component_host();

$qb = new midgard_query_builder('my_component_host');
$qb2 = my_component_host::new_query_builder();

// "compatibility" mode translates to same API as above
</code></pre>
]]></content>
        <summary type="html"><![CDATA[
<h1>Revision History</h1>

<ul><li>2010-01-10, created by Alexey Zakhlestin and Jarkko Ala-Louvesniemi</li>
</ul><h1>PROBLEM</h1>

<p>Modern programming languages have concept of namespaces within them. Midgard, historically, used underscores as pseudo-namespacing tool, but these days we try to use real namespaces in python (and in php soon). Using namespaces in python led to the following code:</p>

<pre><code>obj = midgard.mgdschema.midgard_article()
</code></pre>

<p>This code mentions "midgard" 2 times which doesn't look nice. Direct approach to fixing this leads to bad hacks and breaks backwards compatibility. See <a href="http://trac.midgard-project.org/ticket/1559">bug #1559</a> as an example. It removes <em>midgard_</em> prefix from all type-names, which can result in names-conflict if there is some type which had the unprefixed name. Clearly a fully designed approach is needed because the API can't change in every Midgard release and we can't support multiple legacy syntaxes.</p>

<p>This document is a proposal for discussion on implementation, which would work as the long-term solution for all future language bindings.</p>

<h1>SOLUTION</h1>

<p>We propose to add explicit &lt;namespace&gt; tag in schema declaration file. Namespaces are supposed to have &lt;class&gt; tags as their children. On the side of language binding it might be translated either to true namespaces (python, php-5.3, etc.) or in pseudo-namespaces (php-5.2) depending on what binding author want/can do. For namespace-capable bindings we propose to use <em>midgard.schema</em> as the root namespace for everything.</p>

<p>It is recommended to prefix table names with <em>namespace_</em>. It shouldn't be enforced, but as a recommended practice would prevent table name conflicts and ease database-management (all tables would be grouped by component, if listed alphabetically). "<em>table</em>" attribute of &lt;class&gt; tag is optional (if left out, table name would be <em>namespace_</em>class) and it is recommended to leave it unset (less coupling between code and actual database implementation).</p>

<p>For backwards compatibility reasons, old syntax with missing namespace tags and &lt;type&gt; tags should still be supported. In this case class should be put in <em>midgard.mgdschema</em> (note that it is <em>mgdschema</em>, not <em>schema</em> as in first clause) namespace. This is a <em>strictly</em> backwards-compatibility option. Such files must not be distributed with Ratatoskr.</p>

<h2>schema:</h2>

<pre><code>&lt;namespace name="core"&gt;
    &lt;class name="host" table="core_host"&gt;
        …
    &lt;/class&gt;

    …
&lt;/namespace&gt;

&lt;namespace name="my_component"&gt;
    &lt;class name="host" table="my_component_host"&gt;
        …
    &lt;/class&gt;

    …
&lt;/namespace&gt;
</code></pre>

<p>And compatibility mode:</p>

<pre><code>&lt;!-- Compatibility example --&gt;
&lt;type name="midgard_host" table="host&gt;
    …
&lt;/type&gt;

&lt;type name="my_component_host" table="my_component_host"&gt;
        …
&lt;/type&gt;
&lt;!-- /Compatibility example --&gt;
</code></pre>

<h2>python:</h2>

<pre><code>obj = midgard.schema.core.host()
obj2 = midgard.schema.my_component.host()

# we can use class-name directly, instead of string. python allows it
qb = midgard.query_builder(midgard.schema.my_component.host)


# this should also work
from midgard.schema import core
from midgard.schema.my_component import *

obj = core.host()
obj2 = host()
qb = midgard.query_builder(core.host)
qb2 = midgard.query_builder(host)
</code></pre>

<p>and for "compatibility" mode:</p>

<pre><code>obj = midgard.mgdschema.midgard_host()
obj2 = midgard.mgdschema.my_component_host()
qb = midgard.query_builder(midgard.mgdschema.my_component_host)

# string-parameter should work for "old schemas" in ratatoskr too (with deprecated-notice)
# (strings translate to classes under the midgard.mgdschema namespace only)
qb = midgard.query_builder('my_component_host')
</code></pre>

<h2>php 5.3+:</h2>

<pre><code>$obj = new midgard\schema\core\host();
$obj2 = new midgard\schema\my_component\host();

// in php we can't pass class as parameter. have to use string.
// (use single quotes because with double quotes e.g. \n wouldn't work like expected)
$qb = new midgard\query_builder('midgard\schema\my_component\host');

// but this should work
$qb = midgard\schema\my_component\host::new_query_builder();


// and this
use midgard\schema\my_component as my;

$qb = my\host::new_query_builder();
</code></pre>

<p>and for "compatibility" mode:</p>

<pre><code>$obj = new midgard_host();
$obj2 = new my_component_host();

$qb = new midgard_query_builder('my_component_host');
$qb2 = my_component_host::new_query_builder();
</code></pre>

<h2>php 5.2:</h2>

<p><em>if we continue to support php 5.2…</em></p>

<pre><code>// "core" is represented as "midgard_" for historical reasons
$obj = new midgard_host();
$obj2 = new my_component_host();

$qb = new midgard_query_builder('my_component_host');
$qb2 = my_component_host::new_query_builder();

// "compatibility" mode translates to same API as above
</code></pre>
]]></summary>
    </entry>
    <entry>
        <title>(Mjölnir) Switching codebase to PHP 5.3+</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0048/"/>
        <published>2009-07-02T10:17:51+00:00</published>
        <updated>2009-07-02T10:17:51+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-99aea51666f111de8363a77c23c48dc18dc1</id>
        <author>
            <name>indeyets@gmail.com (Alexey Zakhlestin)</name>
        </author>
        <content type="html"><![CDATA[
<h1>Revision History</h1>

<ul><li>2009-07-02, created by Alexey Zakhlestin</li>
</ul><h1>Introduction</h1>

<p>On June 30, 2009 <a href="http://php.net/releases/5_3_0.php" title="PHP: PHP 5.3.0 Release Announcement">PHP 5.3.0 was released</a>. It brings major functionality changes, which would bring a lot of benefits for Midgard-MVC. Midgard-MVC is, currently, a part of <a href="http://www.midgard-project.org/discussion/developer-forum/what_is_mjolnir/" title="Midgard: What is Mjolnir?">Mjölnir release</a>. Mjölnir is not planned to be a LTS-release, but as a first release of midgard-2 for building produciton sites upon.</p>

<p>I propose to switch Mjölnir development to PHP-5.3+ only compatibility. As a result we will get a cleaner, faster and more powerful code. It would be a bad idea to break compatibility after we release Mjölnir. Majority of application-developers wouldn't rely on Mjölnir for quite some time, which gives unix-distributions enough time to include PHP-5.3 in their releases.</p>

<h1>New Features of PHP 5.3</h1>

<h2>Closures/Lambda-functions</h2>

<p>In 5.2 and earlier callbacks could be either runtime-compiled
(create_function()), which is slow, or you had to define method and
pass it's name, which clutters namespace. Anyway, both these cases
lack scope-inheritance which limits their usefulness.</p>

<p>5.3 has true closures, which allows usage of functional patterns in
php code. First thing which comes to mind is work with arrays: map,
reduce, filter, etc. instead of foreach-cycles. But even more
interesting pattern is context-aware callbacks. There's a nice example
of such callback <a href="http://www.phparch.com/main/news/view/29/Poll__Five_PHP_5_3_Reasons_to_Make_You_Switch">here</a></p>

<pre><code>function loadData($url, $handler)
{
     $handler(file_get_contents($url));
}

function sendPageTo($email, $url)
{
    loadData($url, function($data) use ($email) {
        mail($email, "Here's your data", $data);
    });
}
</code></pre>

<p>In general, closures give us a whole new dimension of reusability.</p>

<h2>Namespaces</h2>

<p>This, probably, is the most discussed feature of PHP 5.3. I'll be
short: we have use-case for this. Current naming pattern in
Midgard-MVC leads to extremely long class-names. Switching to
namespaces would make code more compact, more readable and less
fragile.</p>

<p>Also, there is an interesting related topic: using exception-model
proposed by php.standards initiative. See "<a href="http://news.php.net/php.standards/2">PHP Standards and Best Practices for PHP 5.3+ Frameworks and Libraries</a>" document.</p>

<p>Basic idea is, that application should inherit it's exceptions from
the standard SPL-exceptions while giving them the same name (but in
it's own namespaces)</p>

<pre><code>namespace Midgard;
class RuntimeException extends \RuntimeException();
</code></pre>

<p>after that, framework-developers can use usual "throw new
RuntimeException();" in code, and application developers can
distinguish between exceptions which come from different frameworks:</p>

<pre><code>try {
    // some code
} catch (Midgard\RuntimeException $e) {
    // Midgard-specific handling
} catch (PEAR2\RuntimeException $e) {
    // PEAR-specific handling
} catch (RuntimeException $e) {
    // Generic handling
}
</code></pre>

<h2>Late Static Binding (aka LSB)</h2>

<p>This is a major step ahead in PHP's dynamic nature. My favourite
example for this feature is ActiveRecord-like classes. In PHP 5.2 it
was possible to define ActiveRecord class with generic methods for
loading, creating, updating of database-records. After that, it was
possible to inherit another class from it, while not defining class
body. Like this, literally:</p>

<pre><code>class Book extends ActiveRecord {}

$book = new Book();
$book-&gt;name = 'name';
$book-&gt;author = 'author';
$book-&gt;save();
</code></pre>

<p>ActiveRecord's save() method, in this case, would detect object's
class at runtime and figure out what to do dynamically. That's a
common knowledge and is really useful. But… It was impossible to do
the same with class-methods (aka "static" methods) until now. Class
methods couldn't detect the class they were called on. So, in 5.2 it
was impossible to implement generic method for the following case:</p>

<pre><code>$books = Book::find_all();
</code></pre>

<p>ActiveRecord's find_all() method would only know, that it belongs to
ActiveRecord and wouldn't know anything about Book class.</p>

<p>PHP 5.3 introduces 2 things in this regard:</p>

<ul><li><a href="http://docs.php.net/get_called_class" title="PHP: get_called_class - Manual">get_called_class()</a> function, which returns class, on which the call was made ("Book" in my example)</li>
<li>"static::" caller in addition to "self::". "static::" propagates the call-chain to the parent, so __CLASS__ constant would return child's class name.</li>
</ul><p>check <a href="http://docs.php.net/manual/en/language.oop5.late-static-bindings.php">PHP Manual</a> for more details</p>

<h2>Garbage collector for cyclic references</h2>

<p>This one is simple. In PHP 5.2 and earlier, if you had situation where
object $a has reference to object $b, while, at the same time, $b has
reference to $a the memory they occupy would never be freed (until
program termination). This limitation, effectively, killed possibility
of having complex long-running php processes. Sooner or later, process
would take all available memory and die("in agony").</p>

<p>PHP 5.3 fixes this and gives us ability to write complex daemons in php.</p>

<h2>Efficient data-structures in SPL</h2>

<p>Starting with PHP 5.3, <a href="http://docs.php.net/spl" title="PHP: SPL - Manual">SPL</a> (Standard PHP Library) gains real value.
Until now it was a set of small, helpful, but mostly under-the-hood
goodies. 5.3 brings fast implementations of the most common
data-structures:</p>

<ul><li>Doubly-linked List (<a href="http://docs.php.net/manual/en/class.spldoublylinkedlist.php" title="PHP: SplDoublyLinkedList - Manual">SplDoublyLinkedList</a>)</li>
<li>Stack (<a href="http://docs.php.net/manual/en/class.splstack.php" title="PHP: SplStack - Manual">SplStack</a>)</li>
<li>Fixed-size Array (<a href="http://docs.php.net/manual/en/class.splfixedarray.php" title="PHP: SplFixedArray - Manual">SplFixedArray</a>)</li>
<li>Heap (<a href="http://docs.php.net/manual/en/class.splheap.php" title="PHP: SplHeap - Manual">SplHeap</a>, <a href="http://docs.php.net/manual/en/class.splmaxheap.php" title="PHP: SplMaxHeap - Manual">SplMaxHeap</a>, <a href="http://docs.php.net/manual/en/class.splminheap.php" title="PHP: SplMinHeap - Manual">SplMinHeap</a>)</li>
<li>Queue (<a href="http://docs.php.net/manual/en/class.splqueue.php" title="PHP: SplQueue - Manual">SplQueue</a>)</li>
<li>Priority Queue (<a href="http://docs.php.net/manual/en/class.splpriorityqueue.php" title="PHP: SplPriorityQueue - Manual">SplPriorityQueue</a>)</li>
</ul><p>Usual speed difference between this implementation and implementation
in PHP is several tens times, at least. They are really fast.</p>

<h2>New default extensions: PHAR (PHP Archive), enchant</h2>

<p>(spell-checking), intl (unicode-compliant collation + ICU-based formatting)</p>

<p><a href="http://docs.php.net/phar" title="PHP: Phar - Manual">PHAR</a> let's us pack a library or an application into a single
"project.phar" file. That is convenient for distribution and gives
speed-boost if you use phar and APC at the same time (APC can use more
efficient cache-strategy, when application is packed as a single-file
on filesystem level).</p>

<p><a href="http://docs.php.net/enchant" title="PHP: Enchant - Manual">Enchant</a> is a generalized extension, which can work with the majority
of spell-checking backends. This includes ispell, aspell and even
AppleSpell</p>

<p><a href="http://docs.php.net/intl" title="PHP: intl - Manual">intl</a> (aka Internationalization extension) is a binding to ICU
(International Components for Unicode) library. It provides means for
working with unicode-compliant locale's, proper unicode-compliant
sorting and unicode-compliant formatting of dates and numbers. That's
a necessity in 21-st century and POSIX-locales are way outdated to
handle complex cases properly.</p>
]]></content>
        <summary type="html"><![CDATA[
<h1>Revision History</h1>

<ul><li>2009-07-02, created by Alexey Zakhlestin</li>
</ul><h1>Introduction</h1>

<p>On June 30, 2009 <a href="http://php.net/releases/5_3_0.php" title="PHP: PHP 5.3.0 Release Announcement">PHP 5.3.0 was released</a>. It brings major functionality changes, which would bring a lot of benefits for Midgard-MVC. Midgard-MVC is, currently, a part of <a href="http://www.midgard-project.org/discussion/developer-forum/what_is_mjolnir/" title="Midgard: What is Mjolnir?">Mjölnir release</a>. Mjölnir is not planned to be a LTS-release, but as a first release of midgard-2 for building produciton sites upon.</p>

<p>I propose to switch Mjölnir development to PHP-5.3+ only compatibility. As a result we will get a cleaner, faster and more powerful code. It would be a bad idea to break compatibility after we release Mjölnir. Majority of application-developers wouldn't rely on Mjölnir for quite some time, which gives unix-distributions enough time to include PHP-5.3 in their releases.</p>

<h1>New Features of PHP 5.3</h1>

<h2>Closures/Lambda-functions</h2>

<p>In 5.2 and earlier callbacks could be either runtime-compiled
(create_function()), which is slow, or you had to define method and
pass it's name, which clutters namespace. Anyway, both these cases
lack scope-inheritance which limits their usefulness.</p>

<p>5.3 has true closures, which allows usage of functional patterns in
php code. First thing which comes to mind is work with arrays: map,
reduce, filter, etc. instead of foreach-cycles. But even more
interesting pattern is context-aware callbacks. There's a nice example
of such callback <a href="http://www.phparch.com/main/news/view/29/Poll__Five_PHP_5_3_Reasons_to_Make_You_Switch">here</a></p>

<pre><code>function loadData($url, $handler)
{
     $handler(file_get_contents($url));
}

function sendPageTo($email, $url)
{
    loadData($url, function($data) use ($email) {
        mail($email, "Here's your data", $data);
    });
}
</code></pre>

<p>In general, closures give us a whole new dimension of reusability.</p>

<h2>Namespaces</h2>

<p>This, probably, is the most discussed feature of PHP 5.3. I'll be
short: we have use-case for this. Current naming pattern in
Midgard-MVC leads to extremely long class-names. Switching to
namespaces would make code more compact, more readable and less
fragile.</p>

<p>Also, there is an interesting related topic: using exception-model
proposed by php.standards initiative. See "<a href="http://news.php.net/php.standards/2">PHP Standards and Best Practices for PHP 5.3+ Frameworks and Libraries</a>" document.</p>

<p>Basic idea is, that application should inherit it's exceptions from
the standard SPL-exceptions while giving them the same name (but in
it's own namespaces)</p>

<pre><code>namespace Midgard;
class RuntimeException extends \RuntimeException();
</code></pre>

<p>after that, framework-developers can use usual "throw new
RuntimeException();" in code, and application developers can
distinguish between exceptions which come from different frameworks:</p>

<pre><code>try {
    // some code
} catch (Midgard\RuntimeException $e) {
    // Midgard-specific handling
} catch (PEAR2\RuntimeException $e) {
    // PEAR-specific handling
} catch (RuntimeException $e) {
    // Generic handling
}
</code></pre>

<h2>Late Static Binding (aka LSB)</h2>

<p>This is a major step ahead in PHP's dynamic nature. My favourite
example for this feature is ActiveRecord-like classes. In PHP 5.2 it
was possible to define ActiveRecord class with generic methods for
loading, creating, updating of database-records. After that, it was
possible to inherit another class from it, while not defining class
body. Like this, literally:</p>

<pre><code>class Book extends ActiveRecord {}

$book = new Book();
$book-&gt;name = 'name';
$book-&gt;author = 'author';
$book-&gt;save();
</code></pre>

<p>ActiveRecord's save() method, in this case, would detect object's
class at runtime and figure out what to do dynamically. That's a
common knowledge and is really useful. But… It was impossible to do
the same with class-methods (aka "static" methods) until now. Class
methods couldn't detect the class they were called on. So, in 5.2 it
was impossible to implement generic method for the following case:</p>

<pre><code>$books = Book::find_all();
</code></pre>

<p>ActiveRecord's find_all() method would only know, that it belongs to
ActiveRecord and wouldn't know anything about Book class.</p>

<p>PHP 5.3 introduces 2 things in this regard:</p>

<ul><li><a href="http://docs.php.net/get_called_class" title="PHP: get_called_class - Manual">get_called_class()</a> function, which returns class, on which the call was made ("Book" in my example)</li>
<li>"static::" caller in addition to "self::". "static::" propagates the call-chain to the parent, so __CLASS__ constant would return child's class name.</li>
</ul><p>check <a href="http://docs.php.net/manual/en/language.oop5.late-static-bindings.php">PHP Manual</a> for more details</p>

<h2>Garbage collector for cyclic references</h2>

<p>This one is simple. In PHP 5.2 and earlier, if you had situation where
object $a has reference to object $b, while, at the same time, $b has
reference to $a the memory they occupy would never be freed (until
program termination). This limitation, effectively, killed possibility
of having complex long-running php processes. Sooner or later, process
would take all available memory and die("in agony").</p>

<p>PHP 5.3 fixes this and gives us ability to write complex daemons in php.</p>

<h2>Efficient data-structures in SPL</h2>

<p>Starting with PHP 5.3, <a href="http://docs.php.net/spl" title="PHP: SPL - Manual">SPL</a> (Standard PHP Library) gains real value.
Until now it was a set of small, helpful, but mostly under-the-hood
goodies. 5.3 brings fast implementations of the most common
data-structures:</p>

<ul><li>Doubly-linked List (<a href="http://docs.php.net/manual/en/class.spldoublylinkedlist.php" title="PHP: SplDoublyLinkedList - Manual">SplDoublyLinkedList</a>)</li>
<li>Stack (<a href="http://docs.php.net/manual/en/class.splstack.php" title="PHP: SplStack - Manual">SplStack</a>)</li>
<li>Fixed-size Array (<a href="http://docs.php.net/manual/en/class.splfixedarray.php" title="PHP: SplFixedArray - Manual">SplFixedArray</a>)</li>
<li>Heap (<a href="http://docs.php.net/manual/en/class.splheap.php" title="PHP: SplHeap - Manual">SplHeap</a>, <a href="http://docs.php.net/manual/en/class.splmaxheap.php" title="PHP: SplMaxHeap - Manual">SplMaxHeap</a>, <a href="http://docs.php.net/manual/en/class.splminheap.php" title="PHP: SplMinHeap - Manual">SplMinHeap</a>)</li>
<li>Queue (<a href="http://docs.php.net/manual/en/class.splqueue.php" title="PHP: SplQueue - Manual">SplQueue</a>)</li>
<li>Priority Queue (<a href="http://docs.php.net/manual/en/class.splpriorityqueue.php" title="PHP: SplPriorityQueue - Manual">SplPriorityQueue</a>)</li>
</ul><p>Usual speed difference between this implementation and implementation
in PHP is several tens times, at least. They are really fast.</p>

<h2>New default extensions: PHAR (PHP Archive), enchant</h2>

<p>(spell-checking), intl (unicode-compliant collation + ICU-based formatting)</p>

<p><a href="http://docs.php.net/phar" title="PHP: Phar - Manual">PHAR</a> let's us pack a library or an application into a single
"project.phar" file. That is convenient for distribution and gives
speed-boost if you use phar and APC at the same time (APC can use more
efficient cache-strategy, when application is packed as a single-file
on filesystem level).</p>

<p><a href="http://docs.php.net/enchant" title="PHP: Enchant - Manual">Enchant</a> is a generalized extension, which can work with the majority
of spell-checking backends. This includes ispell, aspell and even
AppleSpell</p>

<p><a href="http://docs.php.net/intl" title="PHP: intl - Manual">intl</a> (aka Internationalization extension) is a binding to ICU
(International Components for Unicode) library. It provides means for
working with unicode-compliant locale's, proper unicode-compliant
sorting and unicode-compliant formatting of dates and numbers. That's
a necessity in 21-st century and POSIX-locales are way outdated to
handle complex cases properly.</p>
]]></summary>
    </entry>
    <entry>
        <title>SVN reorganization to stable and devel versions of each branch</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0047/"/>
        <published>2009-07-02T10:17:06+00:00</published>
        <updated>2009-07-02T10:17:06+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-7eb75dca66f111dea7b9a3b4efee304d304d</id>
        <author>
            <name>rambo@nemein.com (Eero af Heurlin)</name>
        </author>
        <content type="html"><![CDATA[
<h2>Changes</h2>

<ul><li>2009.07.02 rambo: Initial version</li>
</ul><h2>Introduction</h2>

<p>This is related to the problem <a href="http://www.midgard-project.org/development/mrfc/0046/">mRFC 0046</a> tries to address but will propose approach that is usable for the older generations as well (for various reasons it's practical impossibility to require unit tests in pre-Vinland MidCOM).</p>

<h2>Discussion</h2>

<p>In <a href="http://www.midgard-project.org/discussion/developer-forum/mrfc_0047/">the dev list</a></p>

<h2>Proposal</h2>

<p>See <a href="http://www.midgard-project.org/discussion/developer-forum/read/83fc02dc5f2a11de93c7ef73ca5cebe7ebe7.html">this discussion</a> for background and details.</p>

<ol><li>Split each generation branch to branchname-stable and branchname-devel</li>
<li>Stable branch commit rights will be severely limited</li>
<li>All changes are made to devel branch, they're merged to stable upon request confirming to a set process (see below)</li>
<li>Official channel packages are built from stable branch</li>
<li>Nice-to-have: unofficial devel channel with autobuilt packages for

<ul><li>Testing</li>
<li>Those who like to live dangerously</li>
</ul></li>
</ol><h3>Merge process</h3>

<ol><li>Requester makes a task ticket to trac with the info on which exact revisions and paths to merge, in format usable directly as arguments to svn merge and the reason for merge (security fix, new feature) and links to all tickets related.</li>
<li>Requester gets someone else to test the changes as well (all tests against the stable branch merged with the provided revisions), that someone will add their test results to the trac ticket, in some cases (critical components) 3 test reports from different people may be required.</li>
<li>Requester informs the VCS tyrant that this is ready for merge</li>
<li>VCS tyrant reviews the request and determines whether to proceed (for example in some branches we may only accept bug fixes, or even more strictly only security fixes)</li>
</ol>]]></content>
        <summary type="html"><![CDATA[
<h2>Changes</h2>

<ul><li>2009.07.02 rambo: Initial version</li>
</ul><h2>Introduction</h2>

<p>This is related to the problem <a href="http://www.midgard-project.org/development/mrfc/0046/">mRFC 0046</a> tries to address but will propose approach that is usable for the older generations as well (for various reasons it's practical impossibility to require unit tests in pre-Vinland MidCOM).</p>

<h2>Discussion</h2>

<p>In <a href="http://www.midgard-project.org/discussion/developer-forum/mrfc_0047/">the dev list</a></p>

<h2>Proposal</h2>

<p>See <a href="http://www.midgard-project.org/discussion/developer-forum/read/83fc02dc5f2a11de93c7ef73ca5cebe7ebe7.html">this discussion</a> for background and details.</p>

<ol><li>Split each generation branch to branchname-stable and branchname-devel</li>
<li>Stable branch commit rights will be severely limited</li>
<li>All changes are made to devel branch, they're merged to stable upon request confirming to a set process (see below)</li>
<li>Official channel packages are built from stable branch</li>
<li>Nice-to-have: unofficial devel channel with autobuilt packages for

<ul><li>Testing</li>
<li>Those who like to live dangerously</li>
</ul></li>
</ol><h3>Merge process</h3>

<ol><li>Requester makes a task ticket to trac with the info on which exact revisions and paths to merge, in format usable directly as arguments to svn merge and the reason for merge (security fix, new feature) and links to all tickets related.</li>
<li>Requester gets someone else to test the changes as well (all tests against the stable branch merged with the provided revisions), that someone will add their test results to the trac ticket, in some cases (critical components) 3 test reports from different people may be required.</li>
<li>Requester informs the VCS tyrant that this is ready for merge</li>
<li>VCS tyrant reviews the request and determines whether to proceed (for example in some branches we may only accept bug fixes, or even more strictly only security fixes)</li>
</ol>]]></summary>
    </entry>
    <entry>
        <title>(Mjölnir) new cvs-model</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0046/"/>
        <published>2009-06-15T07:19:56+00:00</published>
        <updated>2009-06-15T07:19:56+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-ed6b58d4597c11deb1967f5a713e82ba82ba</id>
        <author>
            <name>oskari.kokko@iki.fi (Oskari Kokko)</name>
        </author>
        <content type="html"><![CDATA[
<h1>Revision History</h1>

<ul><li>2009-06-16, created by Oskari Kokko</li>
</ul><h1>About the current model of commiting to the midgard repo</h1>

<p>Nowdays anyone can commit to the repo of ragnaroek and to the new midcom 3. I'm not talking about how things work in MidCOM 3, because so few is using or commiting to the yet. So, the examples I'm writing are from ragnaroek and the main idea of this mRFC is to avoid these problems in MidCOM 3 (I speak of MidCOM 3, even though we desided to ditch that name and start using Midgard CMS instead).</p>

<p>Problems that I have had lately with the midcom have allways somewhat related to something that was working being broken all of a sudden. And the only thing that I did, was to upgrade some midcom-component, because some other fix was made to the new release. So, while something is fixed, the new version allways brings other new 'features' along, that somehow broke things. This is because everyone has commit rights to the repo and no one has enought time to test the every outcome of their changes to the code. So, we need some rules for commiting.</p>

<h1>New cvs-model</h1>

<p>The codebase of midcom being so big as it is now, there is no possibility for anyone to see all the possible risks in a new feature all by himself, at least when that someone needs to work at the same time. So, what I propose, is to have testing and stable branches and make some sort of a valuation when moving fixes and features from testing-branch to the stable branch. Now we have the trunk for ragnaroek, whitch automatically becomes 'stable', when a new release is made. So, there should be selected group of people, who can approve a set of commits from the testing-branch to the stable one.</p>

<h2>What does a set of commits nead to be approved to the stable branch</h2>

<p>For any feature needed to be in the stable branch, there is someone who needs it there. So, he / she makes a document containing following things</p>

<ul><li>List of commits needed to be moved to stable branch</li>
<li>List of tickets affected by this

<ul><li>So, basicly this is the list of fixed things</li>
</ul></li>
<li>List of new features</li>
<li>List of things that these changes might affect</li>
<li>Unit tests of all the new features

<ul><li>Basicly, in the end, all the features in Midcom 3 should have unit test</li>
</ul></li>
<li>A test report

<ul><li>Screenshot about the unit test results</li>
<li>Test report must contain tests about all the new features, fixed issues and tests about the things that these changes may affect</li>
<li>Test report should contain at least few screenshots of the tests (these tests mean manually clicking the feature, because with unit tests you propably won't see all of the possible outcomes)</li>
</ul></li>
</ul><p>After the person neading the new features in the stable branch has made this request with enought test data, those who can approve commits from testing to stable, make the changes. So, for those who can approve, the job really isn't that big, because the coder has done all the testing and made a report about it. Report can be then made public, so afterwards others can see what happened and where.</p>

<p>As a side note at this point, those who are able to approve commits, can't approve their own commits. They need allways some other to approve their commits.</p>

<p>Other option is to have someone, who really has time to run tests after every commit. But as we don't have the Midgard Foundation yet, I see no possibility in here. And to be honest, testing others commits might be a bit hard job.</p>

<p>Basicly, what I'm saying, is that the current situation is unbearable and we need to do things a bit differently than it is now.</p>
]]></content>
        <summary type="html"><![CDATA[
<h1>Revision History</h1>

<ul><li>2009-06-16, created by Oskari Kokko</li>
</ul><h1>About the current model of commiting to the midgard repo</h1>

<p>Nowdays anyone can commit to the repo of ragnaroek and to the new midcom 3. I'm not talking about how things work in MidCOM 3, because so few is using or commiting to the yet. So, the examples I'm writing are from ragnaroek and the main idea of this mRFC is to avoid these problems in MidCOM 3 (I speak of MidCOM 3, even though we desided to ditch that name and start using Midgard CMS instead).</p>

<p>Problems that I have had lately with the midcom have allways somewhat related to something that was working being broken all of a sudden. And the only thing that I did, was to upgrade some midcom-component, because some other fix was made to the new release. So, while something is fixed, the new version allways brings other new 'features' along, that somehow broke things. This is because everyone has commit rights to the repo and no one has enought time to test the every outcome of their changes to the code. So, we need some rules for commiting.</p>

<h1>New cvs-model</h1>

<p>The codebase of midcom being so big as it is now, there is no possibility for anyone to see all the possible risks in a new feature all by himself, at least when that someone needs to work at the same time. So, what I propose, is to have testing and stable branches and make some sort of a valuation when moving fixes and features from testing-branch to the stable branch. Now we have the trunk for ragnaroek, whitch automatically becomes 'stable', when a new release is made. So, there should be selected group of people, who can approve a set of commits from the testing-branch to the stable one.</p>

<h2>What does a set of commits nead to be approved to the stable branch</h2>

<p>For any feature needed to be in the stable branch, there is someone who needs it there. So, he / she makes a document containing following things</p>

<ul><li>List of commits needed to be moved to stable branch</li>
<li>List of tickets affected by this

<ul><li>So, basicly this is the list of fixed things</li>
</ul></li>
<li>List of new features</li>
<li>List of things that these changes might affect</li>
<li>Unit tests of all the new features

<ul><li>Basicly, in the end, all the features in Midcom 3 should have unit test</li>
</ul></li>
<li>A test report

<ul><li>Screenshot about the unit test results</li>
<li>Test report must contain tests about all the new features, fixed issues and tests about the things that these changes may affect</li>
<li>Test report should contain at least few screenshots of the tests (these tests mean manually clicking the feature, because with unit tests you propably won't see all of the possible outcomes)</li>
</ul></li>
</ul><p>After the person neading the new features in the stable branch has made this request with enought test data, those who can approve commits from testing to stable, make the changes. So, for those who can approve, the job really isn't that big, because the coder has done all the testing and made a report about it. Report can be then made public, so afterwards others can see what happened and where.</p>

<p>As a side note at this point, those who are able to approve commits, can't approve their own commits. They need allways some other to approve their commits.</p>

<p>Other option is to have someone, who really has time to run tests after every commit. But as we don't have the Midgard Foundation yet, I see no possibility in here. And to be honest, testing others commits might be a bit hard job.</p>

<p>Basicly, what I'm saying, is that the current situation is unbearable and we need to do things a bit differently than it is now.</p>
]]></summary>
    </entry>
    <entry>
        <title>(Mjölnir) Midgard authentication system</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0045/"/>
        <published>2009-06-14T15:31:39+00:00</published>
        <updated>2009-06-14T15:31:39+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-7488a57258f811deb5987116dad47b297b29</id>
        <author>
            <name>indeyets@gmail.com (Alexey Zakhlestin)</name>
        </author>
        <content type="html"><![CDATA[
<h1>Revision History</h1>

<ul><li>2009-06-14, created by Alexey Zakhlestin</li>
<li>2009-07-06, major updates by Piotr Pokora</li>
<li>2009-07-23, major updates which include ideas from developers forum by Piotr Pokora</li>
</ul><h1>Background</h1>

<p>Current Midgard's authentication system uses several hardcoded scenarios and doesn't reflect needs of modern web-world. This mRFC focuses mostly on implementation part, as it's impossible to describe idea for any single authentication mechanism.</p>

<h2>References</h2>

<ul><li>http://trac.midgard-project.org/ticket/1199</li>
<li>http://trac.midgard-project.org/ticket/1037</li>
<li>http://trac.midgard-project.org/ticket/1036</li>
<li>http://www.midgard-project.org/discussion/developer-forum/midgard_authentication_implementation_proposal/</li>
<li>http://www.midgard-project.org/discussion/developer-forum/new_auth-system_mrfc/</li>
</ul><h1>Needs</h1>

<p>Midgard needs modular authentication system which would allow developers to implement various authentication schemes for their needs. Midgard core shall provide abstraction layer API for any authentication type provided on any level and written with any language for which Midgard core provides bindings. Any new authentication type shall not require additional routines to be written in core or on language bindings level.</p>

<p>It should be possible to use it for implementing at least the following:</p>

<ul><li>Username and password stored in Midgard itself</li>
<li>Username in Midgard, password via PAM</li>
<li>Apache-based authentication where Apache gives us the username (Kerberos for instance)</li>
<li>Apache-based authentication where Apache passes us a token we must authenticate with (http://www.gpgauth.com/ for instance)</li>
<li>Delegated authentication and/or registration (Shibboleth, Facebook Connect, OpenID)</li>
<li>Token-based authentication (OAuth)</li>
</ul><h1>Implementation</h1>

<p>Basic idea is to provide routines which would be very similar to already known Midgard "Trusted" auth type. Midgard core shall implement midgard_auth and midgard_user classes.</p>

<h2>midgard_user</h2>

<h3>Properties of an object</h3>

<ul><li><p>guid/uuid - read only object's identifier
guid/uuid property should be unique per table and mandatory for proper authentication.</p></li>
<li><p>login - string which identifies user (username/nick)
non unique string with allowed empty one</p></li>
<li><p>password - stored in text/blob column so any data can be written to
non unique string with allowed empty one</p></li>
<li><p>person - guid/uuid, a reference to midgard_person object 
non unique guid or uuid</p></li>
<li><p>is_admin - admin flag
boolean value which marks user as admin</p></li>
<li><p>type - user defined field which holds integer value</p>

<p>If more properties are needed, a new MgdSchema class which extends midgard_user should be created.</p></li>
</ul><h3>Methods</h3>

<ul><li><p>array query(array properties)
Fetch midgard_user object(s) using given properties as query constraints.
If all properties match, object(s) is(are) returned from database.</p>

<p>Example, get all particular user accounts:</p>

<p>$tokens = array("login" =&gt; "john", "type" =&gt; MYAPP_AUTH_TYPE_CONST);
$objects = midgard_user::query($tokens);</p>

<p>if (empty($objects))
    print "No account for user 'john'";</p></li>
<li><p>boolean register(void)
Creates new midgard_user objects' record in database.</p></li>
<li><p>boolean update(void)
Updates midgard_user object's record in database.</p>

<p>Example:</p>

<p>$user = new midgard_user();
$user-&gt;login = "john";
$user-&gt;password = "";</p>

<p>if ($user-&gt;register())
    print "Created new account for user 'john'";</p></li>
<li><p>midgard_person get_person(void);
Returns midgard_person object associated (if any) with midgard_user instance.</p></li>
<li><p>boolean login(void)
Login shall associate midgard_user object with midgard_connection, which shall emit 'auth-changed' signal and set proper access error code. User without guid set shall be considered invalid, 'auth-changed' signal shall not be emited and proper access error code shall be set. Only midgard_connection shall be responsible for setting error codes and signal emission.</p></li>
<li><p>boolean logout(void)
Logout shall unset already associated midgard_user object. midgard_connection shall emit 'auth-changed' signal if associated with any midgard_user. No error code shall be set by midgard_connection.</p></li>
</ul><h3>Query object(s)</h3>

<p>By default midgard_user should not be accesible with query builder, however if new MgdSchema class which extends midgard_user is defined, it should be queryable with query builder or collector.</p>

<h1>Authentication</h1>

<p>Authentication should be done with 'login' and 'logout' methods of midgard_user class.
 Midgard core will accept any midgard_user which logs in as long as it's fetched from database.
 It's up to the application if given midgard_user is valid or not.
 Read only guid/uuid property will be always set internally by core and used as "fetched from database" marker.</p>

<p>Once object is fetched from database, it can be stored (serialized) in file or as memcached key for later reuse.
 midgard_connection's get_user() method will provide pointer to actually logged in user.</p>

<h1>Authentication state stack</h1>

<p>midgard_connection shall hold authenticated users in a stack. Every successful login method invoked by  midgard_user object shall add new user to the top of the stack, while its logout method shall remove user from the top of the stack.</p>

<p>midgard_user can be removed from top of the stack in two cases:</p>

<ul><li>midgard_user logout method is invoked explicitly</li>
<li>midgard_user object is destroyed</li>
</ul><p>In latter case, Midgard core will invoke logout method in user's destructor.</p>

<p>It's application specific to logout users in proper order. Midgard core will return false for logout method, and will throw unconditional warning if there's attempt to logout a user which hasn't been logged in recently (it's not on top of the stack). Midgard language bindings should raise exception in such case, if it's only possible.</p>

<h1>MgdSchema objects and metadata</h1>

<p>It's up to the application if user holds a reference to midgard_person object. If current user doesn't have a reference to midgard_person object (via guid or uuid), core won't raise any warning or error. In such case empty string will be used instead of person's identifier for MgdSchema objects' metadata properties like creator or revisor.</p>

<h1>Legacy authentication</h1>

<p>Legacy authentication will be implemented as class which extends midgard_user. To avoid bulk updates of legacy accounts, this class will register any account using midgard_user routines on the fly. Which means, new user account will be created (for legacy one) as soon as first authentication attempt is made. This could also clear username and password from midgard_person record transparently.</p>

<h1>Midgard root and Midgard domain 0 (SG0)</h1>

<p>Implementation shall not allow any midgard_auth derived class to login in as Midgard root user or into sitegroup 0.</p>
]]></content>
        <summary type="html"><![CDATA[
<h1>Revision History</h1>

<ul><li>2009-06-14, created by Alexey Zakhlestin</li>
<li>2009-07-06, major updates by Piotr Pokora</li>
<li>2009-07-23, major updates which include ideas from developers forum by Piotr Pokora</li>
</ul><h1>Background</h1>

<p>Current Midgard's authentication system uses several hardcoded scenarios and doesn't reflect needs of modern web-world. This mRFC focuses mostly on implementation part, as it's impossible to describe idea for any single authentication mechanism.</p>

<h2>References</h2>

<ul><li>http://trac.midgard-project.org/ticket/1199</li>
<li>http://trac.midgard-project.org/ticket/1037</li>
<li>http://trac.midgard-project.org/ticket/1036</li>
<li>http://www.midgard-project.org/discussion/developer-forum/midgard_authentication_implementation_proposal/</li>
<li>http://www.midgard-project.org/discussion/developer-forum/new_auth-system_mrfc/</li>
</ul><h1>Needs</h1>

<p>Midgard needs modular authentication system which would allow developers to implement various authentication schemes for their needs. Midgard core shall provide abstraction layer API for any authentication type provided on any level and written with any language for which Midgard core provides bindings. Any new authentication type shall not require additional routines to be written in core or on language bindings level.</p>

<p>It should be possible to use it for implementing at least the following:</p>

<ul><li>Username and password stored in Midgard itself</li>
<li>Username in Midgard, password via PAM</li>
<li>Apache-based authentication where Apache gives us the username (Kerberos for instance)</li>
<li>Apache-based authentication where Apache passes us a token we must authenticate with (http://www.gpgauth.com/ for instance)</li>
<li>Delegated authentication and/or registration (Shibboleth, Facebook Connect, OpenID)</li>
<li>Token-based authentication (OAuth)</li>
</ul><h1>Implementation</h1>

<p>Basic idea is to provide routines which would be very similar to already known Midgard "Trusted" auth type. Midgard core shall implement midgard_auth and midgard_user classes.</p>

<h2>midgard_user</h2>

<h3>Properties of an object</h3>

<ul><li><p>guid/uuid - read only object's identifier
guid/uuid property should be unique per table and mandatory for proper authentication.</p></li>
<li><p>login - string which identifies user (username/nick)
non unique string with allowed empty one</p></li>
<li><p>password - stored in text/blob column so any data can be written to
non unique string with allowed empty one</p></li>
<li><p>person - guid/uuid, a reference to midgard_person object 
non unique guid or uuid</p></li>
<li><p>is_admin - admin flag
boolean value which marks user as admin</p></li>
<li><p>type - user defined field which holds integer value</p>

<p>If more properties are needed, a new MgdSchema class which extends midgard_user should be created.</p></li>
</ul><h3>Methods</h3>

<ul><li><p>array query(array properties)
Fetch midgard_user object(s) using given properties as query constraints.
If all properties match, object(s) is(are) returned from database.</p>

<p>Example, get all particular user accounts:</p>

<p>$tokens = array("login" =&gt; "john", "type" =&gt; MYAPP_AUTH_TYPE_CONST);
$objects = midgard_user::query($tokens);</p>

<p>if (empty($objects))
    print "No account for user 'john'";</p></li>
<li><p>boolean register(void)
Creates new midgard_user objects' record in database.</p></li>
<li><p>boolean update(void)
Updates midgard_user object's record in database.</p>

<p>Example:</p>

<p>$user = new midgard_user();
$user-&gt;login = "john";
$user-&gt;password = "";</p>

<p>if ($user-&gt;register())
    print "Created new account for user 'john'";</p></li>
<li><p>midgard_person get_person(void);
Returns midgard_person object associated (if any) with midgard_user instance.</p></li>
<li><p>boolean login(void)
Login shall associate midgard_user object with midgard_connection, which shall emit 'auth-changed' signal and set proper access error code. User without guid set shall be considered invalid, 'auth-changed' signal shall not be emited and proper access error code shall be set. Only midgard_connection shall be responsible for setting error codes and signal emission.</p></li>
<li><p>boolean logout(void)
Logout shall unset already associated midgard_user object. midgard_connection shall emit 'auth-changed' signal if associated with any midgard_user. No error code shall be set by midgard_connection.</p></li>
</ul><h3>Query object(s)</h3>

<p>By default midgard_user should not be accesible with query builder, however if new MgdSchema class which extends midgard_user is defined, it should be queryable with query builder or collector.</p>

<h1>Authentication</h1>

<p>Authentication should be done with 'login' and 'logout' methods of midgard_user class.
 Midgard core will accept any midgard_user which logs in as long as it's fetched from database.
 It's up to the application if given midgard_user is valid or not.
 Read only guid/uuid property will be always set internally by core and used as "fetched from database" marker.</p>

<p>Once object is fetched from database, it can be stored (serialized) in file or as memcached key for later reuse.
 midgard_connection's get_user() method will provide pointer to actually logged in user.</p>

<h1>Authentication state stack</h1>

<p>midgard_connection shall hold authenticated users in a stack. Every successful login method invoked by  midgard_user object shall add new user to the top of the stack, while its logout method shall remove user from the top of the stack.</p>

<p>midgard_user can be removed from top of the stack in two cases:</p>

<ul><li>midgard_user logout method is invoked explicitly</li>
<li>midgard_user object is destroyed</li>
</ul><p>In latter case, Midgard core will invoke logout method in user's destructor.</p>

<p>It's application specific to logout users in proper order. Midgard core will return false for logout method, and will throw unconditional warning if there's attempt to logout a user which hasn't been logged in recently (it's not on top of the stack). Midgard language bindings should raise exception in such case, if it's only possible.</p>

<h1>MgdSchema objects and metadata</h1>

<p>It's up to the application if user holds a reference to midgard_person object. If current user doesn't have a reference to midgard_person object (via guid or uuid), core won't raise any warning or error. In such case empty string will be used instead of person's identifier for MgdSchema objects' metadata properties like creator or revisor.</p>

<h1>Legacy authentication</h1>

<p>Legacy authentication will be implemented as class which extends midgard_user. To avoid bulk updates of legacy accounts, this class will register any account using midgard_user routines on the fly. Which means, new user account will be created (for legacy one) as soon as first authentication attempt is made. This could also clear username and password from midgard_person record transparently.</p>

<h1>Midgard root and Midgard domain 0 (SG0)</h1>

<p>Implementation shall not allow any midgard_auth derived class to login in as Midgard root user or into sitegroup 0.</p>
]]></summary>
    </entry>
    <entry>
        <title>(Mjölnir) MgdSchema ACLs</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0044/"/>
        <published>2009-06-10T13:24:37+00:00</published>
        <updated>2009-06-10T13:24:37+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-0bdd19d855c211debf08614dddc9ffeaffea</id>
        <author>
            <name>rambo@nemein.com (Eero af Heurlin)</name>
        </author>
        <content type="html"><![CDATA[
<h1>Introduction</h1>

<p>The idea is to allow component developers specify more fine-grained access-control that works on gObject level, these can be set per property and both on the MgdSchema XML file and on API level.</p>

<h1>Controls</h1>

<h2>Read</h2>

<p>Whether property can be read, can be used for write-only properties on mgdschema level (passwords etc) or to restict access to private data when access to the whole object should not be restricted (from example disallow read of event title but allow read of the dates)</p>

<h2>Write</h2>

<p>Whether property can be written to, if user does not have write privileges for the object we can flag all properties as not writable and get extra layer of safety.</p>

<h1>MgdSchema level</h1>

<p>On MgdSchema two new parameters to the property are added "read" and "write", both default to "true".</p>

<h1>API Level</h1>

<p>Here we can change a true to false but not vice versa, ie we can add <em>additional</em> restrictions but not remove existing ones, these are added per object instance, for example using the following syntax:</p>

<pre><code>$object-&gt;add_acl('property', 'write', false);
</code></pre>

<p>Trying to change an existing ACL setting from false to true will throw an exception.</p>

<h1>Use cases</h1>

<h2>Private events</h2>

<p>We get signal of an 'event' object being instantiated and we see that this event has 'private' property set to true but the current user is not the creator of the event, so we deny read on event title and some other properties we consider to containt private data.</p>
]]></content>
        <summary type="html"><![CDATA[
<h1>Introduction</h1>

<p>The idea is to allow component developers specify more fine-grained access-control that works on gObject level, these can be set per property and both on the MgdSchema XML file and on API level.</p>

<h1>Controls</h1>

<h2>Read</h2>

<p>Whether property can be read, can be used for write-only properties on mgdschema level (passwords etc) or to restict access to private data when access to the whole object should not be restricted (from example disallow read of event title but allow read of the dates)</p>

<h2>Write</h2>

<p>Whether property can be written to, if user does not have write privileges for the object we can flag all properties as not writable and get extra layer of safety.</p>

<h1>MgdSchema level</h1>

<p>On MgdSchema two new parameters to the property are added "read" and "write", both default to "true".</p>

<h1>API Level</h1>

<p>Here we can change a true to false but not vice versa, ie we can add <em>additional</em> restrictions but not remove existing ones, these are added per object instance, for example using the following syntax:</p>

<pre><code>$object-&gt;add_acl('property', 'write', false);
</code></pre>

<p>Trying to change an existing ACL setting from false to true will throw an exception.</p>

<h1>Use cases</h1>

<h2>Private events</h2>

<p>We get signal of an 'event' object being instantiated and we see that this event has 'private' property set to true but the current user is not the creator of the event, so we deny read on event title and some other properties we consider to containt private data.</p>
]]></summary>
    </entry>
    <entry>
        <title>Midgard2 deployment model</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0043/"/>
        <published>2009-05-26T17:36:06+00:00</published>
        <updated>2009-05-26T17:36:06+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-b12c6fa44a1b11deb30dc58e18bcb680b680</id>
        <author>
            <name>henri.bergius@iki.fi (Henri Bergius)</name>
        </author>
        <content type="html"><![CDATA[
<h2>Background</h2>

<p>With Midgard1, especially since the introduction of filesystem-based MidCOM, the  deployment model of applications has been quite lacking. In the history of Midgard we have had two deployment models:</p>

<ul><li><p>Everything served as a repligard XML file, including both content and the application itself (OpenPSA 1.x, Aegir, VMUC, midHoo)</p></li>
<li><p>Components installed via PEAR, templates and configuration via FileSync (OpenPSA 2)</p></li>
</ul><p>Both of these models lack some features we need from a deployment system:</p>

<ul><li>Versioning of a Midgard application</li>
<li>Separation of components from configuration to support component reuse</li>
<li>Easy team collaboration through quick set-up and tear-down of application instances</li>
<li>Possibility to either include content with the application or keep it separate</li>
</ul><h2>Terminology</h2>

<ul><li><p>Application: a Midgard-powered web site (combination of components, a page hierarchy, templates and configuration)</p></li>
<li><p>Bucket: a repository containing replication XML files of Midgard data, and a manifest file listing necessary components and their versions. Bucket can be either a Amazon S3 bucket or a git repository</p></li>
<li><p>Component: a MidCOM component providing its own manifest, and potentially routes, templates, MgdSchema definitions and Python-based helper processes</p></li>
</ul><h2>Usage scenarios</h2>

<h3>CMS site deployment</h3>

<p>Alice wants to build her new website with Midgard. She has a Mac laptop, and her ISP has set up a Linux virtual server.</p>

<p>To get started, she downloads the Midgard App Builder and runs it. She instructs the App Builder to set up an empty Midgard application, with only the base MidCOM components installed.</p>

<p>Then she starts her work: she installs the components she needs for the site, converts her XHTML templates to TAL and configures the site structure by using Midgard's on-site administrative tools.</p>

<p>She also sets up a git repository and instructs Midgard to synchronize all changes using that repository as the application bucket.</p>

<p>When the site is ready for launch, she logs on to the Linux server and runs midgard2-setup, providing it with the URL of her application bucket. The Midgard setup tool installs the same set of components that she had on her laptop, imports the site data and sets up a virtual host.</p>

<p>The she tests the site on the actual server and launches it. As the server is monitoring changes to the application bucket, she can later update the website either on the server or on her laptop's local installation. This is useful as she often likes to blog while traveling.</p>

<h3>Making updates to customer's CMS-based site</h3>

<p>Bob has a customer that has been running a Midgard-powered site for two years now. They contacted him and asked for some layout changes to the site. Since editing a live site is a bad idea, Bob decides to do the changes on a test server.</p>

<p>First he checks if the customer already has their site in an application bucket. But as the site is old, they don't. So he creates an empty bucket to the company version control system and instructs the Midgard installation on the live server to export its data there.</p>

<p>When the whole site is in the bucket together with component information he then logs on to a development server. On the server he already has some other Midgard applications running. In order to not disturb them he decides to set up a new database.</p>

<p>To do this he writes a new Midgard configuration file specifying custom locations for the MgdSchemas, and a new database name. Then he runs midgard2-setup, giving it the name of the configuration file and the URL to the customer's application bucket.</p>

<p>midgard2-setup installs a local copy of the site, exactly like the one running on customer's server. If Bob had been in a hurry, he could have told midgard2-setup to skip installing some slower parts, like for example file attachments.</p>

<p>Now he logs to the copy of the website running on the development server and starts to work.</p>

<p>When the layout changes are done, he then instructs Midgard to export the changes to the customer's application bucket. Then he logs to the live server, and there instructs Midgard to import changes from the bucket. That done, the layout changes are live.</p>

<h3>End-user application distribution</h3>

<p>Charlie has built a simple but powerful web-based CRM solution that can be run on the desktop. He wants to start distributing it to his customers, with Mac OS X as the main target platform.</p>

<p>To do this, he creates a new github repository that will server as the application bucket. Then he exports his local installation of the application there, skipping some particular MgdSchema types like "customer" that contain his test data.</p>

<p>After this is done, he fires up Midgard App Builder and tells it to create a new application based on the bucket stored on github. This will result in a clean installation of Charlie's CRM app.</p>

<p>Now he packages that as a .dmg file, publishes it and starts marketing his application. Users who can install and use it just like they would any native Mac OS X app, even though it actually runs Midgard and MidCOM on the background.</p>

<p>When he later releases a new version of the application, he does this by publishing updated component versions and creating an updated manifest file that he then pushes into the application bucket on github.</p>

<p>Users of the CRM application will get automatically notified of the new version as their installations check the github repository periodically for changes. Updating the application is as simple as either running midgard2-setup on the command line, or clicking a button in the application interface itself.</p>

<h3>Team collaboration</h3>

<p>Dexter and Emily are both working in a company providing a social website based on Midgard. They're both developers working on different aspects of the web service.</p>

<p>TODO</p>

<h2>Packaging</h2>

<h3>MidCOM components</h3>

<p>In Midgard2, MidCOM components are going to be released via git repositories instead of PEAR packaging. A stable release is made by merging changes from development branches into a stable branch, tagging it and pushing to a repository server. In this sense, <code>midcom_core</code> is also a component as it follows exactly the same model.</p>

<p>Component manifest may list components (repository URL and branch or release tag) the component depends on.</p>

<h3>Midgard buckets</h3>

<p>Midgard applications are stored in "Buckets", which can be either git repositories or S3 buckets (other repositories, like WebDAV shares, may also be supported). The bucket contains a manifest file listing the components used by the application, and a collection of Midgard replication XML files grouped by their schema type.</p>

<p>Example bucket layout:</p>

<pre><code>mybucket/
    manifest.yml
    midgard_person/
        e0d837d091c511dba90a8ba58d0b46d346d3.xml
    midgard_page
        e27c3c8a91c511dbb4287d806e4281ab81ab.xml
        e28b76a091c511dbb4287d806e4281ab81ab.xml
    ...
</code></pre>

<h2>Tools needed</h2>

<h3>midgard2-installer</h3>

<p>Tool that handles installation and updating of MidCOM components. When installing a new component, a local git checkout of the component is made (using the given branch or tag), the possible MgdSchemas shipped with the component are installed to Midgard, and the component itself is symlinked to its correct place.</p>

<h3>midgard2-setup</h3>

<p>Tool that handles setting up a new Midgard application. It checkouts a given Midgard bucket to the local system, installs the components specified in the bucket manifest (using midgard2-installer routines specified above), and then proceeds to import the Midgard replication XML files in the bucket.</p>

<p>Once components are in place and data has been imported, it then sets up an appropriate virtual host for serving the Midgard application. Once this is done, the Midgard application should be up-and-running and accessible via a browser.</p>

<p>midgard2-setup can either use an existing Midgard configuration file, or set up a new one with sane defaults (based on platform).</p>

<h3>Midgard App Builder</h3>

<p>Midgard App Builder is a tool based on midgard2 and the Fluid site-specific browser. It makes it possible to easily create and install Midgard applications as self-contained Mac OS X .app packages.</p>

<p>When a Midgard application has been created with App Builder, it will resemble a normal OS X application. Starting it by double-clicking the .app file will start midgard2, lighttpd and d-bus on the background and will open the Midgard application inside a Fluid site-specific browser window. Fluid is based on WebKit and provides many additional javascript APIs that enable applications to behave more like native OS X apps. For instance, they can bounce the dock icon or raise Growl notifications.</p>

<p>When creating a new Midgard application, App Builder should do the normal midgard2-setup tasks (installing the base data from a bucket). After this the fully running Midgard application can then be packaged as a .dmg image that any Mac user will be able to install easily. However, the Midgard bucket subscription on the background will still provide easy update of the base data, for when instance a new release of OpenPSA is made.</p>

<p>Similar tools like Midgard App Builder may be created for other platforms when we have more experiences with real-world usage.</p>

<h3>Amazon EC2 image</h3>

<p>Midgard would be much more cloud-ready if we provided an EC2 image with preinstalled Midgard. When started up, it would connect to a configured bucket and import the application from there.</p>

<p>Then the EC2 node would be completely ready for business. This would make scaling up websites very easy. However, much software needs to be written to make the kind of cloud setup described in an earlier blog post possible:</p>

<p><a href="http://bergie.iki.fi/blog/midgard2-future_in_the_clouds/">http://bergie.iki.fi/blog/midgard2-future_in_the_clouds/</a></p>

<h2>Potential issues</h2>

<h3>Order of importing objects</h3>

<p>Midgard's replication tools require dependencies (objects referenced to via linked fields) to exist in database before objects can be imported. This means that the installer tool must construct a dependency chain and install objects in correct order.</p>

<p>One way to do this is to try importing all objects in sequence. If importing an object fails, move it to the end of the queue and try again later. Repeat until queue is empty. But there may be more optimal solutions to this too.</p>

<p>If a dependency fails to be found completely, we could populate a "skeleton object" into the database. The skeleton object would be completely empty but have the correct GUID, allowing it to be "updated" when the correct object is later being imported.</p>

<h3>Keeping Midgard itself up-to-date</h3>

<p>Packaging and installation of Midgard (and related software like Python, PHP and Lighttpd) is outside the scope of this document.</p>

<p>On Linux systems they can be installed and updated through native package management tools.</p>

<p>Midgard App Builder makes this slightly trickier, as the .app package will contain both Midgard and the actual database. It might be good if Midgard applications generated through App Builder could somehow move their database under user's home directory after initial run. This would make updating Midgard applications on OS X as easy as any native app, as users could just copy a new version of the .app package on top of the existing one and their data would remain intact.</p>

<h2>Afterword</h2>

<p>The idea here is the result of much frustration in Midgard's current deployment model. It is partly inspired by discussions in recent Gatherings, and partly by Edd Dumbill's <a href="http://times.usefulinc.com/2008/06/16-ops-now">We're all ops people now</a> blog post.</p>

<p>The initial version was written on a rather choppy Austrian Arrows flight from Copenhagen to Vienna, while the plane was working its way around some thunderstorms near Berlin.</p>
]]></content>
        <summary type="html"><![CDATA[
<h2>Background</h2>

<p>With Midgard1, especially since the introduction of filesystem-based MidCOM, the  deployment model of applications has been quite lacking. In the history of Midgard we have had two deployment models:</p>

<ul><li><p>Everything served as a repligard XML file, including both content and the application itself (OpenPSA 1.x, Aegir, VMUC, midHoo)</p></li>
<li><p>Components installed via PEAR, templates and configuration via FileSync (OpenPSA 2)</p></li>
</ul><p>Both of these models lack some features we need from a deployment system:</p>

<ul><li>Versioning of a Midgard application</li>
<li>Separation of components from configuration to support component reuse</li>
<li>Easy team collaboration through quick set-up and tear-down of application instances</li>
<li>Possibility to either include content with the application or keep it separate</li>
</ul><h2>Terminology</h2>

<ul><li><p>Application: a Midgard-powered web site (combination of components, a page hierarchy, templates and configuration)</p></li>
<li><p>Bucket: a repository containing replication XML files of Midgard data, and a manifest file listing necessary components and their versions. Bucket can be either a Amazon S3 bucket or a git repository</p></li>
<li><p>Component: a MidCOM component providing its own manifest, and potentially routes, templates, MgdSchema definitions and Python-based helper processes</p></li>
</ul><h2>Usage scenarios</h2>

<h3>CMS site deployment</h3>

<p>Alice wants to build her new website with Midgard. She has a Mac laptop, and her ISP has set up a Linux virtual server.</p>

<p>To get started, she downloads the Midgard App Builder and runs it. She instructs the App Builder to set up an empty Midgard application, with only the base MidCOM components installed.</p>

<p>Then she starts her work: she installs the components she needs for the site, converts her XHTML templates to TAL and configures the site structure by using Midgard's on-site administrative tools.</p>

<p>She also sets up a git repository and instructs Midgard to synchronize all changes using that repository as the application bucket.</p>

<p>When the site is ready for launch, she logs on to the Linux server and runs midgard2-setup, providing it with the URL of her application bucket. The Midgard setup tool installs the same set of components that she had on her laptop, imports the site data and sets up a virtual host.</p>

<p>The she tests the site on the actual server and launches it. As the server is monitoring changes to the application bucket, she can later update the website either on the server or on her laptop's local installation. This is useful as she often likes to blog while traveling.</p>

<h3>Making updates to customer's CMS-based site</h3>

<p>Bob has a customer that has been running a Midgard-powered site for two years now. They contacted him and asked for some layout changes to the site. Since editing a live site is a bad idea, Bob decides to do the changes on a test server.</p>

<p>First he checks if the customer already has their site in an application bucket. But as the site is old, they don't. So he creates an empty bucket to the company version control system and instructs the Midgard installation on the live server to export its data there.</p>

<p>When the whole site is in the bucket together with component information he then logs on to a development server. On the server he already has some other Midgard applications running. In order to not disturb them he decides to set up a new database.</p>

<p>To do this he writes a new Midgard configuration file specifying custom locations for the MgdSchemas, and a new database name. Then he runs midgard2-setup, giving it the name of the configuration file and the URL to the customer's application bucket.</p>

<p>midgard2-setup installs a local copy of the site, exactly like the one running on customer's server. If Bob had been in a hurry, he could have told midgard2-setup to skip installing some slower parts, like for example file attachments.</p>

<p>Now he logs to the copy of the website running on the development server and starts to work.</p>

<p>When the layout changes are done, he then instructs Midgard to export the changes to the customer's application bucket. Then he logs to the live server, and there instructs Midgard to import changes from the bucket. That done, the layout changes are live.</p>

<h3>End-user application distribution</h3>

<p>Charlie has built a simple but powerful web-based CRM solution that can be run on the desktop. He wants to start distributing it to his customers, with Mac OS X as the main target platform.</p>

<p>To do this, he creates a new github repository that will server as the application bucket. Then he exports his local installation of the application there, skipping some particular MgdSchema types like "customer" that contain his test data.</p>

<p>After this is done, he fires up Midgard App Builder and tells it to create a new application based on the bucket stored on github. This will result in a clean installation of Charlie's CRM app.</p>

<p>Now he packages that as a .dmg file, publishes it and starts marketing his application. Users who can install and use it just like they would any native Mac OS X app, even though it actually runs Midgard and MidCOM on the background.</p>

<p>When he later releases a new version of the application, he does this by publishing updated component versions and creating an updated manifest file that he then pushes into the application bucket on github.</p>

<p>Users of the CRM application will get automatically notified of the new version as their installations check the github repository periodically for changes. Updating the application is as simple as either running midgard2-setup on the command line, or clicking a button in the application interface itself.</p>

<h3>Team collaboration</h3>

<p>Dexter and Emily are both working in a company providing a social website based on Midgard. They're both developers working on different aspects of the web service.</p>

<p>TODO</p>

<h2>Packaging</h2>

<h3>MidCOM components</h3>

<p>In Midgard2, MidCOM components are going to be released via git repositories instead of PEAR packaging. A stable release is made by merging changes from development branches into a stable branch, tagging it and pushing to a repository server. In this sense, <code>midcom_core</code> is also a component as it follows exactly the same model.</p>

<p>Component manifest may list components (repository URL and branch or release tag) the component depends on.</p>

<h3>Midgard buckets</h3>

<p>Midgard applications are stored in "Buckets", which can be either git repositories or S3 buckets (other repositories, like WebDAV shares, may also be supported). The bucket contains a manifest file listing the components used by the application, and a collection of Midgard replication XML files grouped by their schema type.</p>

<p>Example bucket layout:</p>

<pre><code>mybucket/
    manifest.yml
    midgard_person/
        e0d837d091c511dba90a8ba58d0b46d346d3.xml
    midgard_page
        e27c3c8a91c511dbb4287d806e4281ab81ab.xml
        e28b76a091c511dbb4287d806e4281ab81ab.xml
    ...
</code></pre>

<h2>Tools needed</h2>

<h3>midgard2-installer</h3>

<p>Tool that handles installation and updating of MidCOM components. When installing a new component, a local git checkout of the component is made (using the given branch or tag), the possible MgdSchemas shipped with the component are installed to Midgard, and the component itself is symlinked to its correct place.</p>

<h3>midgard2-setup</h3>

<p>Tool that handles setting up a new Midgard application. It checkouts a given Midgard bucket to the local system, installs the components specified in the bucket manifest (using midgard2-installer routines specified above), and then proceeds to import the Midgard replication XML files in the bucket.</p>

<p>Once components are in place and data has been imported, it then sets up an appropriate virtual host for serving the Midgard application. Once this is done, the Midgard application should be up-and-running and accessible via a browser.</p>

<p>midgard2-setup can either use an existing Midgard configuration file, or set up a new one with sane defaults (based on platform).</p>

<h3>Midgard App Builder</h3>

<p>Midgard App Builder is a tool based on midgard2 and the Fluid site-specific browser. It makes it possible to easily create and install Midgard applications as self-contained Mac OS X .app packages.</p>

<p>When a Midgard application has been created with App Builder, it will resemble a normal OS X application. Starting it by double-clicking the .app file will start midgard2, lighttpd and d-bus on the background and will open the Midgard application inside a Fluid site-specific browser window. Fluid is based on WebKit and provides many additional javascript APIs that enable applications to behave more like native OS X apps. For instance, they can bounce the dock icon or raise Growl notifications.</p>

<p>When creating a new Midgard application, App Builder should do the normal midgard2-setup tasks (installing the base data from a bucket). After this the fully running Midgard application can then be packaged as a .dmg image that any Mac user will be able to install easily. However, the Midgard bucket subscription on the background will still provide easy update of the base data, for when instance a new release of OpenPSA is made.</p>

<p>Similar tools like Midgard App Builder may be created for other platforms when we have more experiences with real-world usage.</p>

<h3>Amazon EC2 image</h3>

<p>Midgard would be much more cloud-ready if we provided an EC2 image with preinstalled Midgard. When started up, it would connect to a configured bucket and import the application from there.</p>

<p>Then the EC2 node would be completely ready for business. This would make scaling up websites very easy. However, much software needs to be written to make the kind of cloud setup described in an earlier blog post possible:</p>

<p><a href="http://bergie.iki.fi/blog/midgard2-future_in_the_clouds/">http://bergie.iki.fi/blog/midgard2-future_in_the_clouds/</a></p>

<h2>Potential issues</h2>

<h3>Order of importing objects</h3>

<p>Midgard's replication tools require dependencies (objects referenced to via linked fields) to exist in database before objects can be imported. This means that the installer tool must construct a dependency chain and install objects in correct order.</p>

<p>One way to do this is to try importing all objects in sequence. If importing an object fails, move it to the end of the queue and try again later. Repeat until queue is empty. But there may be more optimal solutions to this too.</p>

<p>If a dependency fails to be found completely, we could populate a "skeleton object" into the database. The skeleton object would be completely empty but have the correct GUID, allowing it to be "updated" when the correct object is later being imported.</p>

<h3>Keeping Midgard itself up-to-date</h3>

<p>Packaging and installation of Midgard (and related software like Python, PHP and Lighttpd) is outside the scope of this document.</p>

<p>On Linux systems they can be installed and updated through native package management tools.</p>

<p>Midgard App Builder makes this slightly trickier, as the .app package will contain both Midgard and the actual database. It might be good if Midgard applications generated through App Builder could somehow move their database under user's home directory after initial run. This would make updating Midgard applications on OS X as easy as any native app, as users could just copy a new version of the .app package on top of the existing one and their data would remain intact.</p>

<h2>Afterword</h2>

<p>The idea here is the result of much frustration in Midgard's current deployment model. It is partly inspired by discussions in recent Gatherings, and partly by Edd Dumbill's <a href="http://times.usefulinc.com/2008/06/16-ops-now">We're all ops people now</a> blog post.</p>

<p>The initial version was written on a rather choppy Austrian Arrows flight from Copenhagen to Vienna, while the plane was working its way around some thunderstorms near Berlin.</p>
]]></summary>
    </entry>
    <entry>
        <title>(Ratatosk) Workspaces</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0042/"/>
        <published>2009-05-10T18:43:21+00:00</published>
        <updated>2009-05-10T18:43:21+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-6f955f823d9211deb416a346ee136acd6acd</id>
        <author>
            <name>rambo@nemein.com (Eero af Heurlin)</name>
        </author>
        <content type="html"><![CDATA[
<h1>Concept</h1>

<h2>Introduction</h2>

<p>Workspaces is generalized combination of the concepts of SiteGroups and MultiLang, workspaces can be used to replace either or both if so desired on application level and core will be simplified by having only support for the general idea of workspaces.</p>

<p>Workspaces are a tree, they have a local ID (not exposed to developers), a name which must be unique on the current tree level and optionally parent, to set a workspace application calls <code>midgard_connection::set_workspace('/path/to/my/workspace')</code>, workspaces can have record extensions and/or they can be extended via MgdSchema inheritance.</p>

<p>Objects on closer to the root of the tree are inherited towards leaves (read privileges apply), if an object is edited on higher (as in towards leaves) level a copy is made (the copies are full objects on their own, with separate metadata).</p>

<p>Replication is workspace agnostic.</p>

<h2>Identifiers</h2>

<p>Objects will always have identifiers:</p>

<ol><li>Local DB id, this is process/thread transient and will be on API level abstracted as opaque midgard_reference object</li>
<li>Global Midgard identifier, like the classic GUID</li>
<li>UUID, this is Universally Unique for the specific object "instance" in specific workspace.</li>
</ol><h2>Instantiating objects</h2>

<p>Objects can be instantiated via a midgard_reference object in the following ways:</p>

<ol><li>Pass the reference as argument to object class constructor</li>
<li>Pass the reference as argument to midgard_object::get()</li>
<li>Call the get() method on the reference (&lt;- PONDER: is this usefull or neccessary ?)</li>
</ol><p>Objects can be instantiated with their identifier in the following ways:</p>

<ol><li>Pass the identifier as argument to midgard_object::get()</li>
<li>Pass the identifier as argument to object class constructor</li>
</ol><p>In both cases core checks if the object has intance in the current workspace, if not it checks the parent etc untill it reaches root, if at any level it encounters an object instance that has read privilege denied it stops checking and throws "access denied" exception, this means that if we have object instances on level 1 and 2 and level 1 has read allowed and level two does not, then on any level above 1 user will not see the object.</p>

<p>Finally a specific instance of object can be instantiated via it's UUID in the following ways:</p>

<ol><li>Create new midgard_reference object by passing the UUID to constructor and instantiate as via reference</li>
<li>Pass the UUID as argument to midgard_object::get()</li>
<li>Pass the UUID as argument to object class constructor</li>
</ol><p>Cases 2 and 3 basically do 1 transparently. However this way also respects the workspace tree so that if we have UUID '113' in workspace '/foo' and our current workspace is '/baz' we cannot see the object exists, if our workspace was '/foo/bar/baz' we would get the object in workspace '/foo' even if object with same identifier exists in '/foo/bar/baz'.</p>

<h2>Replication</h2>

<p>Replication is workspace agnostic, however it's forbidden to replicate between workspaces in the same database as UUIDs may not clash.</p>

<h3>Serialize/export</h3>

<p>Replication works on object "instances", ie. serializing object instance from workspace '/foo/bar' will not include also the instance from workspace '/foo'.</p>

<p>No workspace info is passed in the serialized data.</p>

<h3>Unserialize/import</h3>

<p>For UUIDs that do not yet exist in the database this is simple: importing creates a new copy in the current connection workspace.</p>

<p>If the connection workspace is '/foo/bar/baz' and UUID already exists on '/foo' level then the '/foo' level is updated on import.</p>

<p>If the connection workspace is '/foo/bar/baz' and UUID already exists on '/bar' tree then an error is thrown.</p>

<h1>Use cases</h1>

<p>With properly thought out conventions and thinking about the stacking when implementing these, all of the following could be stacked on top of each other so you could have multiple companies with multilingual staging/live sites.</p>

<p>Basically it boils down to what the implementation considers "root" workspace.</p>

<h2>Sitegroup emulation</h2>

<p>For hosting multiple sites of different companies with different needs and data structures using separate databases is probably more efficient or at the very least logically cleaner.</p>

<p>However for application hosting where all customers use mostly the same MgdSchemas workspaces can be used to neatly separate and share data, for example the might be a workspace tree like the following:</p>

<ul><li>Huge enterprise

<ul><li>Main company</li>
<li>Another company</li>
<li>And another</li>
</ul></li>
<li>Company not related to huge enterprise</li>
</ul><p>Here the huge enterprise and the unrelated company are unaware of each other, data shared across whole enterprise can be created to the first level workspace</p>

<p>For security we should probably have a second argument to set_workspace() which forbids changing the workspace to above/outside the given workspace, so if we say <code>set_workspace('/my_company', true)</code> after that <code>set_workspace('/another_company')</code> should fail but <code>set_workspace('/my_company/fi')</code> should not (provided the workspace exists...), similarly if <code>set_workspace('/my_enterprise/my_company', true)</code> has been called call to <code>set_workspace('/my_enterprise')</code> should fail.</p>

<h2>Multilang emulation</h2>

<p>CMS application could handle multi-lingual content by defining that by convention it will look for workspace named for example by locale naming conventions 'fi_FI' for Finnish localized content, core would provide 'fallback language' if the workspaces are organized in the order of '/fallback/preferred_language', this could be a longer path as well for example '/en_US/fi_FI/fi_SV' so we prefer Finnish-swedish but fall back to Finnish if unavailable and finally fall back to english.</p>

<p>User interface locale info could be stored as record extension(s) to the workspace object.</p>

<h2>Staging/Live</h2>

<p>One could have live site use workspace '/My-site' and the staging site use workspace '/My-site/staging' and on publish to live just overwrite the '/My-site' instance of the object with data from the staging instance.</p>

<p>Deletes instead of being done at the same time is from staging (like with the current replication based system) could wait for example re-approval of the parent.</p>

<h1>Corner cases</h1>

<h2>Copying</h2>

<h3>How to copy objects</h3>

<p>Do we use the update() method to create a copy in the current workspace or do we use a separate method to create the copy ? The con with the update() -approach is that it's "magick", the advantage that component developers do not need to have special handlers.</p>

<h3>Copying to parent workspace</h3>

<p>What happens if we have object with identifier X in '/foo/bar' but not in '/foo' and we want to copy it to '/foo', ie. how to achieve this ?</p>

<p>If we had separate copy method giving the path would be obvious solution. with the update() approach I suppose there is need to change workspace (and if changing workspace above current one is forbidden the separate copy method should fail too).</p>

<h2>Attachments and record extensions</h2>

<p>How should these be handled by core when object is copied from workspace to another ?</p>

<h3>Idea 1: Record extensions copied on copy, attachments not.</h3>

<p>Staging/live and/or Multilang applications/helpers handle copying/fallback for attachments.</p>

<h3>Idea 2: Only object copied</h3>

<p>This is simpler for core and is less "magick" but makes the the required helpers more complicated. Also it can be argued that the record extensions are more part of the object than the attachments.</p>
]]></content>
        <summary type="html"><![CDATA[
<h1>Concept</h1>

<h2>Introduction</h2>

<p>Workspaces is generalized combination of the concepts of SiteGroups and MultiLang, workspaces can be used to replace either or both if so desired on application level and core will be simplified by having only support for the general idea of workspaces.</p>

<p>Workspaces are a tree, they have a local ID (not exposed to developers), a name which must be unique on the current tree level and optionally parent, to set a workspace application calls <code>midgard_connection::set_workspace('/path/to/my/workspace')</code>, workspaces can have record extensions and/or they can be extended via MgdSchema inheritance.</p>

<p>Objects on closer to the root of the tree are inherited towards leaves (read privileges apply), if an object is edited on higher (as in towards leaves) level a copy is made (the copies are full objects on their own, with separate metadata).</p>

<p>Replication is workspace agnostic.</p>

<h2>Identifiers</h2>

<p>Objects will always have identifiers:</p>

<ol><li>Local DB id, this is process/thread transient and will be on API level abstracted as opaque midgard_reference object</li>
<li>Global Midgard identifier, like the classic GUID</li>
<li>UUID, this is Universally Unique for the specific object "instance" in specific workspace.</li>
</ol><h2>Instantiating objects</h2>

<p>Objects can be instantiated via a midgard_reference object in the following ways:</p>

<ol><li>Pass the reference as argument to object class constructor</li>
<li>Pass the reference as argument to midgard_object::get()</li>
<li>Call the get() method on the reference (&lt;- PONDER: is this usefull or neccessary ?)</li>
</ol><p>Objects can be instantiated with their identifier in the following ways:</p>

<ol><li>Pass the identifier as argument to midgard_object::get()</li>
<li>Pass the identifier as argument to object class constructor</li>
</ol><p>In both cases core checks if the object has intance in the current workspace, if not it checks the parent etc untill it reaches root, if at any level it encounters an object instance that has read privilege denied it stops checking and throws "access denied" exception, this means that if we have object instances on level 1 and 2 and level 1 has read allowed and level two does not, then on any level above 1 user will not see the object.</p>

<p>Finally a specific instance of object can be instantiated via it's UUID in the following ways:</p>

<ol><li>Create new midgard_reference object by passing the UUID to constructor and instantiate as via reference</li>
<li>Pass the UUID as argument to midgard_object::get()</li>
<li>Pass the UUID as argument to object class constructor</li>
</ol><p>Cases 2 and 3 basically do 1 transparently. However this way also respects the workspace tree so that if we have UUID '113' in workspace '/foo' and our current workspace is '/baz' we cannot see the object exists, if our workspace was '/foo/bar/baz' we would get the object in workspace '/foo' even if object with same identifier exists in '/foo/bar/baz'.</p>

<h2>Replication</h2>

<p>Replication is workspace agnostic, however it's forbidden to replicate between workspaces in the same database as UUIDs may not clash.</p>

<h3>Serialize/export</h3>

<p>Replication works on object "instances", ie. serializing object instance from workspace '/foo/bar' will not include also the instance from workspace '/foo'.</p>

<p>No workspace info is passed in the serialized data.</p>

<h3>Unserialize/import</h3>

<p>For UUIDs that do not yet exist in the database this is simple: importing creates a new copy in the current connection workspace.</p>

<p>If the connection workspace is '/foo/bar/baz' and UUID already exists on '/foo' level then the '/foo' level is updated on import.</p>

<p>If the connection workspace is '/foo/bar/baz' and UUID already exists on '/bar' tree then an error is thrown.</p>

<h1>Use cases</h1>

<p>With properly thought out conventions and thinking about the stacking when implementing these, all of the following could be stacked on top of each other so you could have multiple companies with multilingual staging/live sites.</p>

<p>Basically it boils down to what the implementation considers "root" workspace.</p>

<h2>Sitegroup emulation</h2>

<p>For hosting multiple sites of different companies with different needs and data structures using separate databases is probably more efficient or at the very least logically cleaner.</p>

<p>However for application hosting where all customers use mostly the same MgdSchemas workspaces can be used to neatly separate and share data, for example the might be a workspace tree like the following:</p>

<ul><li>Huge enterprise

<ul><li>Main company</li>
<li>Another company</li>
<li>And another</li>
</ul></li>
<li>Company not related to huge enterprise</li>
</ul><p>Here the huge enterprise and the unrelated company are unaware of each other, data shared across whole enterprise can be created to the first level workspace</p>

<p>For security we should probably have a second argument to set_workspace() which forbids changing the workspace to above/outside the given workspace, so if we say <code>set_workspace('/my_company', true)</code> after that <code>set_workspace('/another_company')</code> should fail but <code>set_workspace('/my_company/fi')</code> should not (provided the workspace exists...), similarly if <code>set_workspace('/my_enterprise/my_company', true)</code> has been called call to <code>set_workspace('/my_enterprise')</code> should fail.</p>

<h2>Multilang emulation</h2>

<p>CMS application could handle multi-lingual content by defining that by convention it will look for workspace named for example by locale naming conventions 'fi_FI' for Finnish localized content, core would provide 'fallback language' if the workspaces are organized in the order of '/fallback/preferred_language', this could be a longer path as well for example '/en_US/fi_FI/fi_SV' so we prefer Finnish-swedish but fall back to Finnish if unavailable and finally fall back to english.</p>

<p>User interface locale info could be stored as record extension(s) to the workspace object.</p>

<h2>Staging/Live</h2>

<p>One could have live site use workspace '/My-site' and the staging site use workspace '/My-site/staging' and on publish to live just overwrite the '/My-site' instance of the object with data from the staging instance.</p>

<p>Deletes instead of being done at the same time is from staging (like with the current replication based system) could wait for example re-approval of the parent.</p>

<h1>Corner cases</h1>

<h2>Copying</h2>

<h3>How to copy objects</h3>

<p>Do we use the update() method to create a copy in the current workspace or do we use a separate method to create the copy ? The con with the update() -approach is that it's "magick", the advantage that component developers do not need to have special handlers.</p>

<h3>Copying to parent workspace</h3>

<p>What happens if we have object with identifier X in '/foo/bar' but not in '/foo' and we want to copy it to '/foo', ie. how to achieve this ?</p>

<p>If we had separate copy method giving the path would be obvious solution. with the update() approach I suppose there is need to change workspace (and if changing workspace above current one is forbidden the separate copy method should fail too).</p>

<h2>Attachments and record extensions</h2>

<p>How should these be handled by core when object is copied from workspace to another ?</p>

<h3>Idea 1: Record extensions copied on copy, attachments not.</h3>

<p>Staging/live and/or Multilang applications/helpers handle copying/fallback for attachments.</p>

<h3>Idea 2: Only object copied</h3>

<p>This is simpler for core and is less "magick" but makes the the required helpers more complicated. Also it can be argued that the record extensions are more part of the object than the attachments.</p>
]]></summary>
    </entry>
    <entry>
        <title>Database views</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0041/"/>
        <published>2009-05-06T11:19:14+00:00</published>
        <updated>2009-05-06T11:19:14+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-baf10a283a2f11debfbb016986ae44604460</id>
        <author>
            <name>piotrek.pokora@gmail.com (Piotr Pokora)</name>
        </author>
        <content type="html"><![CDATA[
<h2>Revision history</h2>

<ul><li>2009-05-06 - created by Piotr Pokora</li>
<li>2009-05-06 - added query notes by Piotr Pokora</li>
<li>2009-05-06 - fixed condition example by Piotr Pokora</li>
<li>2009-06-05 - Changed table scope information by Piotr Pokora</li>
<li>2010-01-21 - Described metadata class usage by Piotr Pokora</li>
</ul><h2>Background</h2>

<p>Database views implementation should provide flexible way to creating database joins of any type. Views shall be represented by special, abstract midgard_view class. User defined views shall be registered as midgard_view derived classes. Such, shall be available as any other typical classes, and database access shall be encapsulated and completely hidden for them.</p>

<h2>View declaration</h2>

<p>Views shall be declared in xml files. View element shall have only one attribute with its name definition. Any other attributes (e.g. with table name) shall not be allowed and considered as explicit error.
View shall be defined with reserved word <strong>view</strong> with reserved <strong>name</strong> attribute.
Implementation shall be responsible for checking name uniqueness. Which means, an explicit error should be raised if view name is already registered as any other class.</p>

<pre><code>&lt;view name="groups_with_coord" /&gt;
</code></pre>

<h2>Table scope</h2>

<p>Table scope, used in FROM SQL part, shall be configured by property's attribute of view.
Reserved words <strong>table</strong> or <strong>class</strong> shall be defined, and application shall raise error if none of them is found as defined attribute. <strong>table</strong> attribute shall take precedence, and if not found, <strong>class</strong> shall be taken into account. A special <strong>class</strong> attribute defines implicitly table which is defined for given class.</p>

<pre><code>&lt;view name="groups_with_coord" table="grp_table"/&gt;
</code></pre>

<h2>View properties</h2>

<p>Implementation shall allow user, to register view properties. These should represent database view fields (columns). Special, reserved word 'property' shall be used to register view property (and thus, field). A reserved, and mandatory word <strong>use</strong> shall be used as allowed property's element attribute. Such attribute's value shall define class name, and its property which shall be used as database data source. Both shall be separated by semicolon.</p>

<pre><code>&lt;property name="guid" use="midgard_group:guid" /&gt;
</code></pre>

<p>Optionaly, property element could have description defined as child element. Description shall be defined with reserved word <strong>description</strong> and with mandatory, reserved <strong>value</strong> named atribute.</p>

<pre><code>&lt;property name="guid" use="midgard_group:guid"&gt;
    &lt;decription value="Stores value of a guid which identifies group" /&gt;
&lt;/property&gt;
</code></pre>

<h2>Metadata properties</h2>

<p>User shall be allowed to include metadata properties in a view which is registered. Reserved <strong>metadata</strong> word shall be used with class and property name to explicitly set metadata column as view's property's storage. Such shall be defined as custom view property, with special dot separator <strong>'.'</strong> used between metadata keyword and its property name.</p>

<pre><code>&lt;property name="created" use="midgard_group:metadata.created" /&gt;
</code></pre>

<p>Metadata keyword doesn't describe particular metadata class which is registered as any class' one. User shall be aware of specific metadata class which should be taken into account. Explicit error shall be thrown, if class, which we register view's property for, doesn't have metadata or its metadata doesn't have defined property.</p>

<p>(Note: adding metadata properties is valid since 9.09.2 version)</p>

<h2>Registering view</h2>

<p>Views shall be registered during application startup. Midgard unified configuration file shall provide a special key to define path to directory, with view xml files. midgard_view derived classes shall be registered after all user defined MgdSchema classes has been registered. After such step, views shall be created in database.</p>

<h2>Join scope</h2>

<p>Reserved, <strong>join</strong> named element shall define database join. There shall be no limit how many joins could be done per database view.  Join type, shall be defined with reserved 'type' attribute. A value for such attribute shall be one of reserved ones:</p>

<ul><li><strong>inner</strong></li>
<li><strong>self</strong></li>
<li><strong>left</strong></li>
<li><strong>left outer</strong></li>
<li><strong>right</strong></li>
<li><strong>right outer</strong></li>
</ul><p><strong>class</strong> named and reserved attribute shall define which, (already defined) class' table is joined in a view.
As an alternative, table can be defined explicitly using reserved word <strong>table</strong>.</p>

<pre><code>&lt;join type="left" class="midgard_member" /&gt;
</code></pre>

<p>Implementation shall raise error, if given class is not yet registered.</p>

<h3>Join condition</h3>

<p>To assure join condition, a special, reserved word <strong>condition</strong> shall be used as join element's child one.
For such, two attributes shall be used: <strong>left</strong> and <strong>right</strong>. A value for both shall be class name and its property separated by semicolon.</p>

<pre><code>&lt;join type="left" class="midgard_member"&gt;
    &lt;condition left="midgard_group:id" right="midgard_member:gid" /&gt;
&lt;/join&gt;
</code></pre>

<h2>Constraints</h2>

<p>Optionaly, view definition could have constraints elements to limit records selected from database.
This shall be defined with reserved word <strong>constraint</strong> and with allowed, reserved attributes:</p>

<ul><li><strong>property</strong> - Class name and its property separated by semicolon</li>
<li><strong>operator</strong> - An SQL operator, the same which is allowed in midgard_query_builder.</li>
<li><strong>value</strong> -  Any, user defined value.</li>
<li><strong>value_type</strong></li>
</ul><p>Only <strong>value_type</strong> shall be optional. This shall define value type, and shall accept the same value types which are accepted in MgdSchema xml files.</p>

<pre><code>&lt;constraint property="midgard_group:owner" operator="&gt;" value="0" value_type="unsigned integer" /&gt;
</code></pre>

<h2>Managing view</h2>

<p>Midgard core shall provide midgard_view abstract class implementation. Such, shall allow programmer:</p>

<ul><li>Create view in database if it doesn't exist</li>
<li>Remove view from database if it exists</li>
<li>Check if database view exists</li>
</ul><p>Every database view represented by midgard_view derived class shall be considered read-only.</p>

<h2>Sitegroup context</h2>

<p>midgard_view implementation shall guaranteed sitegroup context. This shall be resolved by implicit constraints or joins usage.</p>

<ol><li><p>An implicit left join shall be added to every view. Such join shall provide condition, where equality of sitegroup fields is assured.</p></li>
<li><p>An implicit constraint shall be added to every view. Such constraint shall limit selected records to these, for which sitegroup field's value is equal to current application sitegroup.</p></li>
</ol><h2>Query views</h2>

<p>Midgard core shall implement views such way to allow query them with midgard_query_builder or midgard_collector. Optionally midgard_view derived classes shall be usable also with midgard_reflection_property or midgard_replicator. For the latter, only serialization shall be allowed.</p>
]]></content>
        <summary type="html"><![CDATA[
<h2>Revision history</h2>

<ul><li>2009-05-06 - created by Piotr Pokora</li>
<li>2009-05-06 - added query notes by Piotr Pokora</li>
<li>2009-05-06 - fixed condition example by Piotr Pokora</li>
<li>2009-06-05 - Changed table scope information by Piotr Pokora</li>
<li>2010-01-21 - Described metadata class usage by Piotr Pokora</li>
</ul><h2>Background</h2>

<p>Database views implementation should provide flexible way to creating database joins of any type. Views shall be represented by special, abstract midgard_view class. User defined views shall be registered as midgard_view derived classes. Such, shall be available as any other typical classes, and database access shall be encapsulated and completely hidden for them.</p>

<h2>View declaration</h2>

<p>Views shall be declared in xml files. View element shall have only one attribute with its name definition. Any other attributes (e.g. with table name) shall not be allowed and considered as explicit error.
View shall be defined with reserved word <strong>view</strong> with reserved <strong>name</strong> attribute.
Implementation shall be responsible for checking name uniqueness. Which means, an explicit error should be raised if view name is already registered as any other class.</p>

<pre><code>&lt;view name="groups_with_coord" /&gt;
</code></pre>

<h2>Table scope</h2>

<p>Table scope, used in FROM SQL part, shall be configured by property's attribute of view.
Reserved words <strong>table</strong> or <strong>class</strong> shall be defined, and application shall raise error if none of them is found as defined attribute. <strong>table</strong> attribute shall take precedence, and if not found, <strong>class</strong> shall be taken into account. A special <strong>class</strong> attribute defines implicitly table which is defined for given class.</p>

<pre><code>&lt;view name="groups_with_coord" table="grp_table"/&gt;
</code></pre>

<h2>View properties</h2>

<p>Implementation shall allow user, to register view properties. These should represent database view fields (columns). Special, reserved word 'property' shall be used to register view property (and thus, field). A reserved, and mandatory word <strong>use</strong> shall be used as allowed property's element attribute. Such attribute's value shall define class name, and its property which shall be used as database data source. Both shall be separated by semicolon.</p>

<pre><code>&lt;property name="guid" use="midgard_group:guid" /&gt;
</code></pre>

<p>Optionaly, property element could have description defined as child element. Description shall be defined with reserved word <strong>description</strong> and with mandatory, reserved <strong>value</strong> named atribute.</p>

<pre><code>&lt;property name="guid" use="midgard_group:guid"&gt;
    &lt;decription value="Stores value of a guid which identifies group" /&gt;
&lt;/property&gt;
</code></pre>

<h2>Metadata properties</h2>

<p>User shall be allowed to include metadata properties in a view which is registered. Reserved <strong>metadata</strong> word shall be used with class and property name to explicitly set metadata column as view's property's storage. Such shall be defined as custom view property, with special dot separator <strong>'.'</strong> used between metadata keyword and its property name.</p>

<pre><code>&lt;property name="created" use="midgard_group:metadata.created" /&gt;
</code></pre>

<p>Metadata keyword doesn't describe particular metadata class which is registered as any class' one. User shall be aware of specific metadata class which should be taken into account. Explicit error shall be thrown, if class, which we register view's property for, doesn't have metadata or its metadata doesn't have defined property.</p>

<p>(Note: adding metadata properties is valid since 9.09.2 version)</p>

<h2>Registering view</h2>

<p>Views shall be registered during application startup. Midgard unified configuration file shall provide a special key to define path to directory, with view xml files. midgard_view derived classes shall be registered after all user defined MgdSchema classes has been registered. After such step, views shall be created in database.</p>

<h2>Join scope</h2>

<p>Reserved, <strong>join</strong> named element shall define database join. There shall be no limit how many joins could be done per database view.  Join type, shall be defined with reserved 'type' attribute. A value for such attribute shall be one of reserved ones:</p>

<ul><li><strong>inner</strong></li>
<li><strong>self</strong></li>
<li><strong>left</strong></li>
<li><strong>left outer</strong></li>
<li><strong>right</strong></li>
<li><strong>right outer</strong></li>
</ul><p><strong>class</strong> named and reserved attribute shall define which, (already defined) class' table is joined in a view.
As an alternative, table can be defined explicitly using reserved word <strong>table</strong>.</p>

<pre><code>&lt;join type="left" class="midgard_member" /&gt;
</code></pre>

<p>Implementation shall raise error, if given class is not yet registered.</p>

<h3>Join condition</h3>

<p>To assure join condition, a special, reserved word <strong>condition</strong> shall be used as join element's child one.
For such, two attributes shall be used: <strong>left</strong> and <strong>right</strong>. A value for both shall be class name and its property separated by semicolon.</p>

<pre><code>&lt;join type="left" class="midgard_member"&gt;
    &lt;condition left="midgard_group:id" right="midgard_member:gid" /&gt;
&lt;/join&gt;
</code></pre>

<h2>Constraints</h2>

<p>Optionaly, view definition could have constraints elements to limit records selected from database.
This shall be defined with reserved word <strong>constraint</strong> and with allowed, reserved attributes:</p>

<ul><li><strong>property</strong> - Class name and its property separated by semicolon</li>
<li><strong>operator</strong> - An SQL operator, the same which is allowed in midgard_query_builder.</li>
<li><strong>value</strong> -  Any, user defined value.</li>
<li><strong>value_type</strong></li>
</ul><p>Only <strong>value_type</strong> shall be optional. This shall define value type, and shall accept the same value types which are accepted in MgdSchema xml files.</p>

<pre><code>&lt;constraint property="midgard_group:owner" operator="&gt;" value="0" value_type="unsigned integer" /&gt;
</code></pre>

<h2>Managing view</h2>

<p>Midgard core shall provide midgard_view abstract class implementation. Such, shall allow programmer:</p>

<ul><li>Create view in database if it doesn't exist</li>
<li>Remove view from database if it exists</li>
<li>Check if database view exists</li>
</ul><p>Every database view represented by midgard_view derived class shall be considered read-only.</p>

<h2>Sitegroup context</h2>

<p>midgard_view implementation shall guaranteed sitegroup context. This shall be resolved by implicit constraints or joins usage.</p>

<ol><li><p>An implicit left join shall be added to every view. Such join shall provide condition, where equality of sitegroup fields is assured.</p></li>
<li><p>An implicit constraint shall be added to every view. Such constraint shall limit selected records to these, for which sitegroup field's value is equal to current application sitegroup.</p></li>
</ol><h2>Query views</h2>

<p>Midgard core shall implement views such way to allow query them with midgard_query_builder or midgard_collector. Optionally midgard_view derived classes shall be usable also with midgard_reflection_property or midgard_replicator. For the latter, only serialization shall be allowed.</p>
]]></summary>
    </entry>
    <entry>
        <title>Extending MgdSchema classes</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0040/"/>
        <published>2009-05-04T11:07:39+00:00</published>
        <updated>2009-05-04T11:07:39+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-c83655ac389b11dead4f1b4b282165366536</id>
        <author>
            <name>piotrek.pokora@gmail.com (Piotr Pokora)</name>
        </author>
        <content type="html"><![CDATA[
<p>Extending MgdSchema classes</p>

<h2>Revision history</h2>

<ul><li>2009-05-04 created by Piotr Pokora</li>
</ul><h2>Background</h2>

<p>Midgard core shall provide possibility to extend existing and already declared MgdSchema classes or copy their data.
Two most important cases shall be taken into account in core's implementation:</p>

<ul><li>Extending MgdSchema classes</li>
<li>Copy from Mgdschema classes</li>
</ul><p>In this mRFC, Extending or copy MgdSchema class means extending class' on database storage layer.</p>

<h2>Extending MgdSchema classes</h2>

<p>Extending shall be declared in MgdSchema file with reserved word 'extends'.</p>

<pre><code>&lt;type name="my_note" extends="my_document"&gt;
</code></pre>

<p>Such inheritance shall add parent's properties to derived type without any need to define them for new type explicitly.
Parent's (from which new class extend) properties shall be shared between classes and used as the same storage fields on database layer. In this case, Midgard core shall not make database fields (and especially guids or any other object identifiers) distinction. This should be covered by application which depends on MgdSchema extended classes. Also database integrity (used for replication for example) should be resolved on application level. Metadata shall be shared between classes. In other words, object's property (database field) shall be accessible from parent's class and derived class instance.</p>

<p>TODO: Should we allow multiple child classes?</p>

<h2>Copy from MgdSchema classes</h2>

<p>Copying shall be declared in MgdSchema file with reserved word 'copy'.</p>

<pre><code>&lt;type name="my_note" copy="my_document"&gt;
</code></pre>

<p>In such case, a deep copy shall be made. Midgard core shall register parent's properties, exactly the same way as they were declared explicitly in MgdSchema file. There shall be no shared properties available and copied properties shall have own fields created in child's class storage.</p>

<h2>Name uniqueness</h2>

<p>Properties' name uniqueness shall be implemented explicitly, which means there shall be no implicit or magic implementation which allow to overwrite property being already registered. Any duplicated property name shall be considered an application error.</p>
]]></content>
        <summary type="html"><![CDATA[
<p>Extending MgdSchema classes</p>

<h2>Revision history</h2>

<ul><li>2009-05-04 created by Piotr Pokora</li>
</ul><h2>Background</h2>

<p>Midgard core shall provide possibility to extend existing and already declared MgdSchema classes or copy their data.
Two most important cases shall be taken into account in core's implementation:</p>

<ul><li>Extending MgdSchema classes</li>
<li>Copy from Mgdschema classes</li>
</ul><p>In this mRFC, Extending or copy MgdSchema class means extending class' on database storage layer.</p>

<h2>Extending MgdSchema classes</h2>

<p>Extending shall be declared in MgdSchema file with reserved word 'extends'.</p>

<pre><code>&lt;type name="my_note" extends="my_document"&gt;
</code></pre>

<p>Such inheritance shall add parent's properties to derived type without any need to define them for new type explicitly.
Parent's (from which new class extend) properties shall be shared between classes and used as the same storage fields on database layer. In this case, Midgard core shall not make database fields (and especially guids or any other object identifiers) distinction. This should be covered by application which depends on MgdSchema extended classes. Also database integrity (used for replication for example) should be resolved on application level. Metadata shall be shared between classes. In other words, object's property (database field) shall be accessible from parent's class and derived class instance.</p>

<p>TODO: Should we allow multiple child classes?</p>

<h2>Copy from MgdSchema classes</h2>

<p>Copying shall be declared in MgdSchema file with reserved word 'copy'.</p>

<pre><code>&lt;type name="my_note" copy="my_document"&gt;
</code></pre>

<p>In such case, a deep copy shall be made. Midgard core shall register parent's properties, exactly the same way as they were declared explicitly in MgdSchema file. There shall be no shared properties available and copied properties shall have own fields created in child's class storage.</p>

<h2>Name uniqueness</h2>

<p>Properties' name uniqueness shall be implemented explicitly, which means there shall be no implicit or magic implementation which allow to overwrite property being already registered. Any duplicated property name shall be considered an application error.</p>
]]></summary>
    </entry>
    <entry>
        <title>MidCOM Component Documentation requirements</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0039/"/>
        <published>2008-12-05T10:56:51+00:00</published>
        <updated>2008-12-05T10:56:51+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-6bc6ce24c2bb11dda07df9140277f92bf92b</id>
        <author>
            <name>olga@olga.pl (Marcin Sołtysiak)</name>
        </author>
        <content type="html"><![CDATA[
<h2>Revision history</h2>

<ul><li>2008-12-03 Created by Marcin Sołtysiak</li>
<li>2008-12-23 Updated by Marcin Sołtysiak</li>
<li>2009-01-06 Updated by Marcin Sołtysiak</li>
</ul><h2>Background</h2>

<p>This document describes Midgard rules for creating and maintaining required MidCOM Components Documentation.</p>

<h2>Terminology</h2>

<ul><li><strong>help file</strong> - text file stored in 'documentation' folder in components skeleton. Help file follows the pattern {subject}.{lang}.txt, where {subject} is a brief keyword and {lang} id 2-char ISO language code. Some {subject}s can follow separate rules if required.</li>
<li><strong>subject</strong> - a keyword describing content of help item. </li>
</ul><h2>MidCOM Component Documentation Rules</h2>

<ul><li>Component Documentation is required element that has to be in place before Component can be released officially along with any Midgard Release.</li>
<li>Component Documentation is subject for approval before Release.</li>
<li>Component Documentation <strong>help_files</strong> must be provided in as many languages as possible assuming English version is mandatory.</li>
<li><p>Component Documentation must cover the following areas:</p>

<ul><li>General Introduction briefly describing Component's purpose</li>
<li>Style elements list and description, if applicable.</li>
<li>Midgard Schema objects properties description included in mgdschema.xml file (English only), if applicable</li>
<li>Routes brief and full descriptions, if applicable</li>
<li>URL Methods - standalone scripts launched from <em>exec</em> component folder, if applicable</li>
</ul></li>
<li><p>Component Documentation must be formatted using Markdown style</p></li>
</ul><h3>General Introduction</h3>

<p>General introduction describes component purpose and should be brief but same time should explain the basic operations in a simple non-techie way. User oriented approach should be a main focus in that part of documentation. Introduction shall outline what input component expects, what tasks it does and what output it sends e.g.:</p>

<pre><code>net.nehmer.blog is a newsticker or blog management component. It operates on midgard_article objects stored in midgard_topic container. Component 
provides a variety of listing modes including RRS feeds. It also can read RSS from external sources.
</code></pre>

<h3>Help topics</h3>

<p>Each <strong>help_file</strong> stands for separate help topic. Upon list of <strong>help_files</strong> a Table of Contents is created on the fly and attached to Introduction page. Help topics are sorted alphabetically by <strong>help_file</strong> name therefore it is wise to prepend a filename with a number eg.</p>

<pre><code>01_concept.en.txt
02_advanced_tasks.en.txt
</code></pre>

<p>Each <strong>help_file</strong> must begin with a help topic title that will be taken as <strong>subject</strong> for Table of Contents and navigation. It is advised that help topic title is formatted as Markdown Header 1 eg.:</p>

<pre><code>My component help topic
---
</code></pre>

<h3>Style elements list</h3>

<p>Every Component that uses styling engine needs to provide a detailed instruction on every style element used. The instruction must contain usage guideliens along with available Component output data and some customization hints.</p>

<pre><code>Article display index

&lt;(index-start)&gt; begins the article index, &lt;(index-item)&gt; displays an individual article and &lt;(index-end)&gt; ends the index. If there are no articles, &lt;(index-empty)&gt; is shown between &lt;(index-start)&gt; and &lt;(index-end)&gt; instead.
</code></pre>

<p>Style elements documentation must be midcom.admin.styleeditor compatible.</p>

<h3>Midgard Schema objects properties description</h3>

<p>Starting from version 8.9.3 MgdSchema provides  node, a child to  node in schema file. Component documentation must include descriptions for all relevant properties so that everyone knows what is the property storage type and purpose. It shall also tell about linkage to other MgdSchema classes.</p>

<pre><code>    &lt;property name="relation" type="integer" index="yes"&gt;
        &lt;description&gt;
        Relation options:

- 10: Entry is made at location
- 20: Entry is about location
- 30: Entry is located at location
        &lt;/description&gt;
    &lt;/property&gt;
</code></pre>

<h3>Handlers / URL Routes help</h3>

<p>Components that can handle URL routes must provide help on all handlers. There should be a help file containing detailed help. Detailed part is also available from current view, floating toolbar 'Help' menu.</p>

<pre><code>    // Handle /list/random/&lt;username|count&gt;/
    $this-&gt;_request_switch['photostream_list_random_count'] = array
    (
        'handler' =&gt; array ('org_routamc_photostream_handler_list', 'random'),
        'fixed_args' =&gt; array('random'),
        'variable_args' =&gt; 1,
    );
</code></pre>

<p>For the handler above, Component must provide:</p>

<ul><li>'handlers_{$handler_id}.lang.txt' file containing detailed description about controller operation and view provided by handler eg. file handlers_photostream_list_random_count.en.txt.</li>
</ul><h3>URL Methods</h3>

<p>URL Methods are standalone scripts that live in <em>exec</em> component folder. URL Methods are launched by running /midcom-exec-{component}/{urlmethod}.php URL.</p>

<p>Documentation on URL Methods is generated in list form:</p>

<pre><code>/midcom-exec-{component}/{urlmethod}.php
    urlmethod_{urlmethod}
</code></pre>

<p>eg.</p>

<pre><code>/midcom-exec-org.routamc.photostream/import_filesystem_folder.php
    urlmethod_import_filesystem_folder
</code></pre>

<p>Localization database must contain urlmethod_{urlmethod} identifier and corresponding {urlmethod}.{lang}.txt must exist in <em>documentation</em> folder</p>
]]></content>
        <summary type="html"><![CDATA[
<h2>Revision history</h2>

<ul><li>2008-12-03 Created by Marcin Sołtysiak</li>
<li>2008-12-23 Updated by Marcin Sołtysiak</li>
<li>2009-01-06 Updated by Marcin Sołtysiak</li>
</ul><h2>Background</h2>

<p>This document describes Midgard rules for creating and maintaining required MidCOM Components Documentation.</p>

<h2>Terminology</h2>

<ul><li><strong>help file</strong> - text file stored in 'documentation' folder in components skeleton. Help file follows the pattern {subject}.{lang}.txt, where {subject} is a brief keyword and {lang} id 2-char ISO language code. Some {subject}s can follow separate rules if required.</li>
<li><strong>subject</strong> - a keyword describing content of help item. </li>
</ul><h2>MidCOM Component Documentation Rules</h2>

<ul><li>Component Documentation is required element that has to be in place before Component can be released officially along with any Midgard Release.</li>
<li>Component Documentation is subject for approval before Release.</li>
<li>Component Documentation <strong>help_files</strong> must be provided in as many languages as possible assuming English version is mandatory.</li>
<li><p>Component Documentation must cover the following areas:</p>

<ul><li>General Introduction briefly describing Component's purpose</li>
<li>Style elements list and description, if applicable.</li>
<li>Midgard Schema objects properties description included in mgdschema.xml file (English only), if applicable</li>
<li>Routes brief and full descriptions, if applicable</li>
<li>URL Methods - standalone scripts launched from <em>exec</em> component folder, if applicable</li>
</ul></li>
<li><p>Component Documentation must be formatted using Markdown style</p></li>
</ul><h3>General Introduction</h3>

<p>General introduction describes component purpose and should be brief but same time should explain the basic operations in a simple non-techie way. User oriented approach should be a main focus in that part of documentation. Introduction shall outline what input component expects, what tasks it does and what output it sends e.g.:</p>

<pre><code>net.nehmer.blog is a newsticker or blog management component. It operates on midgard_article objects stored in midgard_topic container. Component 
provides a variety of listing modes including RRS feeds. It also can read RSS from external sources.
</code></pre>

<h3>Help topics</h3>

<p>Each <strong>help_file</strong> stands for separate help topic. Upon list of <strong>help_files</strong> a Table of Contents is created on the fly and attached to Introduction page. Help topics are sorted alphabetically by <strong>help_file</strong> name therefore it is wise to prepend a filename with a number eg.</p>

<pre><code>01_concept.en.txt
02_advanced_tasks.en.txt
</code></pre>

<p>Each <strong>help_file</strong> must begin with a help topic title that will be taken as <strong>subject</strong> for Table of Contents and navigation. It is advised that help topic title is formatted as Markdown Header 1 eg.:</p>

<pre><code>My component help topic
---
</code></pre>

<h3>Style elements list</h3>

<p>Every Component that uses styling engine needs to provide a detailed instruction on every style element used. The instruction must contain usage guideliens along with available Component output data and some customization hints.</p>

<pre><code>Article display index

&lt;(index-start)&gt; begins the article index, &lt;(index-item)&gt; displays an individual article and &lt;(index-end)&gt; ends the index. If there are no articles, &lt;(index-empty)&gt; is shown between &lt;(index-start)&gt; and &lt;(index-end)&gt; instead.
</code></pre>

<p>Style elements documentation must be midcom.admin.styleeditor compatible.</p>

<h3>Midgard Schema objects properties description</h3>

<p>Starting from version 8.9.3 MgdSchema provides  node, a child to  node in schema file. Component documentation must include descriptions for all relevant properties so that everyone knows what is the property storage type and purpose. It shall also tell about linkage to other MgdSchema classes.</p>

<pre><code>    &lt;property name="relation" type="integer" index="yes"&gt;
        &lt;description&gt;
        Relation options:

- 10: Entry is made at location
- 20: Entry is about location
- 30: Entry is located at location
        &lt;/description&gt;
    &lt;/property&gt;
</code></pre>

<h3>Handlers / URL Routes help</h3>

<p>Components that can handle URL routes must provide help on all handlers. There should be a help file containing detailed help. Detailed part is also available from current view, floating toolbar 'Help' menu.</p>

<pre><code>    // Handle /list/random/&lt;username|count&gt;/
    $this-&gt;_request_switch['photostream_list_random_count'] = array
    (
        'handler' =&gt; array ('org_routamc_photostream_handler_list', 'random'),
        'fixed_args' =&gt; array('random'),
        'variable_args' =&gt; 1,
    );
</code></pre>

<p>For the handler above, Component must provide:</p>

<ul><li>'handlers_{$handler_id}.lang.txt' file containing detailed description about controller operation and view provided by handler eg. file handlers_photostream_list_random_count.en.txt.</li>
</ul><h3>URL Methods</h3>

<p>URL Methods are standalone scripts that live in <em>exec</em> component folder. URL Methods are launched by running /midcom-exec-{component}/{urlmethod}.php URL.</p>

<p>Documentation on URL Methods is generated in list form:</p>

<pre><code>/midcom-exec-{component}/{urlmethod}.php
    urlmethod_{urlmethod}
</code></pre>

<p>eg.</p>

<pre><code>/midcom-exec-org.routamc.photostream/import_filesystem_folder.php
    urlmethod_import_filesystem_folder
</code></pre>

<p>Localization database must contain urlmethod_{urlmethod} identifier and corresponding {urlmethod}.{lang}.txt must exist in <em>documentation</em> folder</p>
]]></summary>
    </entry>
    <entry>
        <title>Midgard D-Bus identifiers</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0038/"/>
        <published>2008-04-30T09:51:50+00:00</published>
        <updated>2008-04-30T09:51:50+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-0e7044e8169b11dda66def9f4bf5a56ba56b</id>
        <author>
            <name>piotrek.pokora@gmail.com (Piotr Pokora)</name>
        </author>
        <content type="html"><![CDATA[
<h1>Revision history</h1>

<ul><li>2008-04-30, created by Piotr Pokora</li>
<li>2008-05-26, clarified message content ( Piotr Pokora )</li>
<li>2009-04-16, added sitegroup guid to path ( Piotr Pokora ) </li>
</ul><h1>Background</h1>

<p>As D-Bus allows to create self, freely defined paths for objects, it might be confusing to send messages to other objects without any knowledge about their particular paths. This document defines D-Bus messages and objects' paths, at which instances has been created.</p>

<p>'midgard_article' class name is used in every example below.</p>

<h1>Main Bus name</h1>

<ul><li><strong>org.midgardproject</strong> - the main Midgard D-Bus service name </li>
<li><strong>/org/midgardproject</strong> - the main Midgard D-Bus service path</li>
</ul><h1>Services</h1>

<p>Services objects can be created by any application as long as they conform to this mRFC.</p>

<h1>Clients</h1>

<p>Clients objects can be created by any application as long as they conform to this mRFC.
For asynchronous massages, Midgard API shall provide automatic messages for main I/0 operations.</p>

<h1>Database identifier</h1>

<p>To limit possible collisions and provide clear and safe services' and clients' identifiers, guid of the current sitegroup is appended to main service's path. Midgard API implementation should not require to append such guid by application, and path with configuration name should be created automatically.</p>

<p>For example, if application is running in some particular sitegroup context, the base path for services and clients shall look like this:</p>

<pre><code>/org/midgardproject/1de0f4967e7ac080f4911debfa73b76220858805880
</code></pre>

<p>Midgard application should not be aware of sitegroup guid as both service and client will be created for the same base path. Midgard API for D-Bus should require only module or class names.</p>

<p>Sitegroup (domain) <em>0</em> is a special exception and <em>SG0</em> string is used instead of sitegroup's guid.</p>

<h1>Module or class identifier</h1>

<p>Services' paths should be created with classes' names, and if possible with module's or feature's names to separate services objects. For example all user defined MgdSchema classes should be created for 'MgdSchema' path. Class method should be appended to path to finally identify service's name.</p>

<p>This document must define clear path's method name, if class' real method name can not be appended to path or any other name suits better.</p>

<h2>MgdSchema</h2>

<p>Services for MgdSchema should be created at path with following tokens:</p>

<ul><li>mgdschema</li>
<li>class name</li>
<li>method name</li>
</ul><p>Every mgdschema class' service or client shall be initialized with the same convention.</p>

<h3>Create</h3>

<p>'create' shall be appended to object's path.</p>

<pre><code>/mgdschema/midgard_article/create
</code></pre>

<p>On success, Midgard API shall send asynchronous message to object at path.</p>

<h3>Update</h3>

<p>'update' shall be appended to object's path</p>

<pre><code>/mgdschema/midgard_article/update
</code></pre>

<p>On success, Midgard API shall send asynchronous message to object at path.</p>

<h3>Delete</h3>

<p>'delete' shall be appended to object's path</p>

<pre><code>/mgdschema/midgard_article/delete
</code></pre>

<p>On success, Midgard API shall send asynchronous message to object at path.</p>

<h3>Purge</h3>

<p>'purge' shall be appended to object's path</p>

<pre><code>/mgdschema/midgard_article/purge
</code></pre>

<p>On success, Midgard API shall send asynchronous message to object at path.</p>

<h3>Get</h3>

<p>'get' shall be appended to object's path for one of these methods:</p>

<ul><li>constructor</li>
<li>get_by_guid</li>
<li>get_by_id</li>
<li>get_by_path</li>
<li><p>get_parent</p>

<p>/mgdschema/midgard_article/get</p></li>
</ul><p>Midgard API implementation will send asynchronous messages in above cases, only if object is successfully retrieved from database.</p>

<h2>Replication</h2>

<p>Services for replication should be created at path with following tokens:</p>

<ul><li>replication</li>
<li>class name</li>
<li>operation</li>
</ul><h3>Import</h3>

<pre><code>/replication/midgard_article/import
</code></pre>

<h3>Export</h3>

<pre><code>/replication/midgard_article/export
</code></pre>

<h1>Messages</h1>

<p>Messages sent to Midgard D-Bus services should contain:</p>

<ul><li>Serialized object as xml data</li>
</ul><h1>References</h1>

<ul><li>http://dbus.freedesktop.org/doc/dbus-tutorial.html</li>
</ul>]]></content>
        <summary type="html"><![CDATA[
<h1>Revision history</h1>

<ul><li>2008-04-30, created by Piotr Pokora</li>
<li>2008-05-26, clarified message content ( Piotr Pokora )</li>
<li>2009-04-16, added sitegroup guid to path ( Piotr Pokora ) </li>
</ul><h1>Background</h1>

<p>As D-Bus allows to create self, freely defined paths for objects, it might be confusing to send messages to other objects without any knowledge about their particular paths. This document defines D-Bus messages and objects' paths, at which instances has been created.</p>

<p>'midgard_article' class name is used in every example below.</p>

<h1>Main Bus name</h1>

<ul><li><strong>org.midgardproject</strong> - the main Midgard D-Bus service name </li>
<li><strong>/org/midgardproject</strong> - the main Midgard D-Bus service path</li>
</ul><h1>Services</h1>

<p>Services objects can be created by any application as long as they conform to this mRFC.</p>

<h1>Clients</h1>

<p>Clients objects can be created by any application as long as they conform to this mRFC.
For asynchronous massages, Midgard API shall provide automatic messages for main I/0 operations.</p>

<h1>Database identifier</h1>

<p>To limit possible collisions and provide clear and safe services' and clients' identifiers, guid of the current sitegroup is appended to main service's path. Midgard API implementation should not require to append such guid by application, and path with configuration name should be created automatically.</p>

<p>For example, if application is running in some particular sitegroup context, the base path for services and clients shall look like this:</p>

<pre><code>/org/midgardproject/1de0f4967e7ac080f4911debfa73b76220858805880
</code></pre>

<p>Midgard application should not be aware of sitegroup guid as both service and client will be created for the same base path. Midgard API for D-Bus should require only module or class names.</p>

<p>Sitegroup (domain) <em>0</em> is a special exception and <em>SG0</em> string is used instead of sitegroup's guid.</p>

<h1>Module or class identifier</h1>

<p>Services' paths should be created with classes' names, and if possible with module's or feature's names to separate services objects. For example all user defined MgdSchema classes should be created for 'MgdSchema' path. Class method should be appended to path to finally identify service's name.</p>

<p>This document must define clear path's method name, if class' real method name can not be appended to path or any other name suits better.</p>

<h2>MgdSchema</h2>

<p>Services for MgdSchema should be created at path with following tokens:</p>

<ul><li>mgdschema</li>
<li>class name</li>
<li>method name</li>
</ul><p>Every mgdschema class' service or client shall be initialized with the same convention.</p>

<h3>Create</h3>

<p>'create' shall be appended to object's path.</p>

<pre><code>/mgdschema/midgard_article/create
</code></pre>

<p>On success, Midgard API shall send asynchronous message to object at path.</p>

<h3>Update</h3>

<p>'update' shall be appended to object's path</p>

<pre><code>/mgdschema/midgard_article/update
</code></pre>

<p>On success, Midgard API shall send asynchronous message to object at path.</p>

<h3>Delete</h3>

<p>'delete' shall be appended to object's path</p>

<pre><code>/mgdschema/midgard_article/delete
</code></pre>

<p>On success, Midgard API shall send asynchronous message to object at path.</p>

<h3>Purge</h3>

<p>'purge' shall be appended to object's path</p>

<pre><code>/mgdschema/midgard_article/purge
</code></pre>

<p>On success, Midgard API shall send asynchronous message to object at path.</p>

<h3>Get</h3>

<p>'get' shall be appended to object's path for one of these methods:</p>

<ul><li>constructor</li>
<li>get_by_guid</li>
<li>get_by_id</li>
<li>get_by_path</li>
<li><p>get_parent</p>

<p>/mgdschema/midgard_article/get</p></li>
</ul><p>Midgard API implementation will send asynchronous messages in above cases, only if object is successfully retrieved from database.</p>

<h2>Replication</h2>

<p>Services for replication should be created at path with following tokens:</p>

<ul><li>replication</li>
<li>class name</li>
<li>operation</li>
</ul><h3>Import</h3>

<pre><code>/replication/midgard_article/import
</code></pre>

<h3>Export</h3>

<pre><code>/replication/midgard_article/export
</code></pre>

<h1>Messages</h1>

<p>Messages sent to Midgard D-Bus services should contain:</p>

<ul><li>Serialized object as xml data</li>
</ul><h1>References</h1>

<ul><li>http://dbus.freedesktop.org/doc/dbus-tutorial.html</li>
</ul>]]></summary>
    </entry>
    <entry>
        <title>Name uniqueness</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0037/"/>
        <published>2007-12-05T15:50:36+00:00</published>
        <updated>2007-12-05T15:50:36+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-d22e5bd8a34911dc9eece5f35230a5a7a5a7</id>
        <author>
            <name>piotrek.pokora@gmail.com (Piotr Pokora)</name>
        </author>
        <content type="html"><![CDATA[
<h1>Revision history</h1>

<p>2007-12-05 Created by Piotr Pokora</p>

<h1>Background</h1>

<p>This document describes Midgard objects' name uniqueness, scope of uniqueness and configuration possibilities. It is also part of Midgard Tree functionality.</p>

<h1>Terminology</h1>

<p>Whenever <strong>name</strong> word is used in this document it refers to object property registered with MgdSchema and configured to be unique in particular scope.</p>

<h1>Name uniqueness</h1>

<p>Unique name should be a property of any type, however it's recommended to use string type with unique names. Name should be configured in Midgard Schema xml file and there should be only one unique name defined per class ( type ). Name should be configured only for classes which may be represented in Midgard Tree. For any other class, unique name should be ignored.</p>

<p>Reserved configuration attribute which defines unique name itself, doesn't qualifies a class ( for which name belongs to) as Midgard Tree enabled.</p>

<p>Name uniqueness should not be supported by underlying database storage provider, unless such functionality would not break sitegroup or Midgard Tree specifications.</p>

<h1>Configuration</h1>

<p>Unique name should be configured only with reserved <strong>unique</strong> attribute(s) in xml file.
A value for the given attribute should define 3 different scopes of uniquness:</p>

<ul><li>parent</li>
</ul><p>It guarantees a name is unique in scope of parent type object's identifier.</p>

<ul><li>self</li>
</ul><p>It guarantees a name is unique in scope of the same type object's identifier.</p>

<ul><li>both</li>
</ul><p>It guarantees a name is unique in scope of the same and parent type object's identifier.</p>

<h2>Examples</h2>

<pre><code>&lt;property name="title" unique="both"&gt;
&lt;property name="name" unique="parent"&gt;
</code></pre>

<p><strong>OR</strong>
 Unique name should be configured only with reserved <strong>unique</strong> and <strong>scope</strong> attribute(s) in xml file.</p>

<h2>Examples</h2>

<pre><code>&lt;property name="title" unique="yes" unique_scope="both"&gt;
&lt;property name="name" unique="yes" unique_scope="self"&gt;
</code></pre>

<h2>TODO</h2>

<p>Describe parent name uniqueness enforce when value is set to 'both'.</p>

<h1>References:</h1>

<ol><li><a href="http://www.midgard-project.org/documentation/mgdschema/">MgdSchema documentation</a></li>
</ol>]]></content>
        <summary type="html"><![CDATA[
<h1>Revision history</h1>

<p>2007-12-05 Created by Piotr Pokora</p>

<h1>Background</h1>

<p>This document describes Midgard objects' name uniqueness, scope of uniqueness and configuration possibilities. It is also part of Midgard Tree functionality.</p>

<h1>Terminology</h1>

<p>Whenever <strong>name</strong> word is used in this document it refers to object property registered with MgdSchema and configured to be unique in particular scope.</p>

<h1>Name uniqueness</h1>

<p>Unique name should be a property of any type, however it's recommended to use string type with unique names. Name should be configured in Midgard Schema xml file and there should be only one unique name defined per class ( type ). Name should be configured only for classes which may be represented in Midgard Tree. For any other class, unique name should be ignored.</p>

<p>Reserved configuration attribute which defines unique name itself, doesn't qualifies a class ( for which name belongs to) as Midgard Tree enabled.</p>

<p>Name uniqueness should not be supported by underlying database storage provider, unless such functionality would not break sitegroup or Midgard Tree specifications.</p>

<h1>Configuration</h1>

<p>Unique name should be configured only with reserved <strong>unique</strong> attribute(s) in xml file.
A value for the given attribute should define 3 different scopes of uniquness:</p>

<ul><li>parent</li>
</ul><p>It guarantees a name is unique in scope of parent type object's identifier.</p>

<ul><li>self</li>
</ul><p>It guarantees a name is unique in scope of the same type object's identifier.</p>

<ul><li>both</li>
</ul><p>It guarantees a name is unique in scope of the same and parent type object's identifier.</p>

<h2>Examples</h2>

<pre><code>&lt;property name="title" unique="both"&gt;
&lt;property name="name" unique="parent"&gt;
</code></pre>

<p><strong>OR</strong>
 Unique name should be configured only with reserved <strong>unique</strong> and <strong>scope</strong> attribute(s) in xml file.</p>

<h2>Examples</h2>

<pre><code>&lt;property name="title" unique="yes" unique_scope="both"&gt;
&lt;property name="name" unique="yes" unique_scope="self"&gt;
</code></pre>

<h2>TODO</h2>

<p>Describe parent name uniqueness enforce when value is set to 'both'.</p>

<h1>References:</h1>

<ol><li><a href="http://www.midgard-project.org/documentation/mgdschema/">MgdSchema documentation</a></li>
</ol>]]></summary>
    </entry>
    <entry>
        <title>Administrative modules for Asgard</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0036/"/>
        <published>2007-07-24T12:34:56+00:00</published>
        <updated>2007-07-24T12:34:56+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-4941cf4239e211dcbeae0b511a09f898f898</id>
        <author>
            <name>henri.bergius@iki.fi (Henri Bergius)</name>
        </author>
        <content type="html"><![CDATA[
<p>Asgard is the administrative interface used for Midgard CMS. By default it provides a comprehensive object browser and management tool.</p>

<p>It is possible to extend the Asgard functionality by adding other modules to the system.</p>

<h2>Request handler plugin setup</h2>

<p>Components wishing to operate as Asgard plugins must have a class that registers plugin handler classes to the request switch. This is defined in component manifest via:</p>

<pre><code>'customdata' =&gt; array
(
    'asgard_plugin' =&gt; array
    (
        'class' =&gt; 'net_example_adminmodule_request',
        'src' =&gt; 'file:/net/example/adminmodule/request.php',
        'name' =&gt; 'Example admin',
        'config' =&gt; null,
    ),
),
</code></pre>

<p>The actual class must have a method <code>get_plugin_handlers()</code> that returns a <em>request switch</em> array and initiates the Asgard library:</p>

<pre><code>function get_plugin_handlers()
{
    $_MIDCOM-&gt;load_library('midgard.admin.asgard');
    $_MIDCOM-&gt;auth-&gt;require_valid_user();
    return Array
    (
        'index' =&gt; Array
        (
            'handler' =&gt; array('net_example_adminmodule_handler_main', 'main'),
        ),
    );
}
</code></pre>

<p><strong>Note:</strong> There must be handler for a view without arguments as this will be the screen users enter when choosing the module from Asgard navigation.</p>

<h2>Handler class</h2>

<p>The handler class must populate some data used by Asgard.</p>

<h3>Handle phase</h3>

<p>During the handle phase the plugin must register itself to Asgard:</p>

<pre><code>$my_title = $_MIDCOM-&gt;i18n-&gt;get_string('example admin plugin', 'net.example.adminplugin');
midgard_admin_asgard_plugin::prepare_plugin($my_title, &amp;$data);
</code></pre>

<h3>Show phase</h3>

<p>During show phase the element must show Asgard's elements around its own content:</p>

<pre><code>midcom_show_style('midgard_admin_asgard_header');
midcom_show_style('midgard_admin_asgard_middle');

// Show plugin's own output

midcom_show_style('midgard_admin_asgard_footer');
</code></pre>
]]></content>
        <summary type="html"><![CDATA[
<p>Asgard is the administrative interface used for Midgard CMS. By default it provides a comprehensive object browser and management tool.</p>

<p>It is possible to extend the Asgard functionality by adding other modules to the system.</p>

<h2>Request handler plugin setup</h2>

<p>Components wishing to operate as Asgard plugins must have a class that registers plugin handler classes to the request switch. This is defined in component manifest via:</p>

<pre><code>'customdata' =&gt; array
(
    'asgard_plugin' =&gt; array
    (
        'class' =&gt; 'net_example_adminmodule_request',
        'src' =&gt; 'file:/net/example/adminmodule/request.php',
        'name' =&gt; 'Example admin',
        'config' =&gt; null,
    ),
),
</code></pre>

<p>The actual class must have a method <code>get_plugin_handlers()</code> that returns a <em>request switch</em> array and initiates the Asgard library:</p>

<pre><code>function get_plugin_handlers()
{
    $_MIDCOM-&gt;load_library('midgard.admin.asgard');
    $_MIDCOM-&gt;auth-&gt;require_valid_user();
    return Array
    (
        'index' =&gt; Array
        (
            'handler' =&gt; array('net_example_adminmodule_handler_main', 'main'),
        ),
    );
}
</code></pre>

<p><strong>Note:</strong> There must be handler for a view without arguments as this will be the screen users enter when choosing the module from Asgard navigation.</p>

<h2>Handler class</h2>

<p>The handler class must populate some data used by Asgard.</p>

<h3>Handle phase</h3>

<p>During the handle phase the plugin must register itself to Asgard:</p>

<pre><code>$my_title = $_MIDCOM-&gt;i18n-&gt;get_string('example admin plugin', 'net.example.adminplugin');
midgard_admin_asgard_plugin::prepare_plugin($my_title, &amp;$data);
</code></pre>

<h3>Show phase</h3>

<p>During show phase the element must show Asgard's elements around its own content:</p>

<pre><code>midcom_show_style('midgard_admin_asgard_header');
midcom_show_style('midgard_admin_asgard_middle');

// Show plugin's own output

midcom_show_style('midgard_admin_asgard_footer');
</code></pre>
]]></summary>
    </entry>
    <entry>
        <title>On-demand service loading for MidCOM</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0035/"/>
        <published>2007-07-19T21:24:20+00:00</published>
        <updated>2007-07-19T21:24:20+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-69ab5e80363e11dc8e75233b98e980308030</id>
        <author>
            <name>henri.bergius@iki.fi (Henri Bergius)</name>
        </author>
        <content type="html"><![CDATA[
<p>This is a proposal for moving service and library loading infrastructure in MidCOM 3 to a more on-demand service oriented model.</p>

<h2>Background</h2>

<p>Currently MidCOM loads a huge number of libraries and services for each request, requiring large amounts of file accesses and PHP parsing. Most of the services loaded are however not really used in a typical request, and so can be seen as being loaded "just in case".</p>

<p>The belief is that this makes the MidCOM environment heavier and more difficult to understand. This proposal outlines how MidCOM could migrate from the current model to a model where services would be loaded when they are used for the first time.</p>

<h2>MidCOM service loader</h2>

<p>A new class <code>midcom_helper_serviceloader</code> needs to be defined to act as the access point to the MidCOM service system. It will be instantiated as <code>$_MIDCOM-&gt;serviceloader</code> at MidCOM start-up.</p>

<p>The service loader should provide two public methods:</p>

<pre><code>boolean can_load($service)
</code></pre>

<p>Method for checking if a particular service is available on the system. This would enable components to deal with missing requirements or other situations where some functionality is not available more cleanly.</p>

<pre><code>object load($service)
</code></pre>

<p>Method for instantiating an implementation of a particular service.</p>

<h2>Inversion of control</h2>

<p>An additional benefit of the service loader model is that MidCOM's services can start following the Inversion of Control design pattern.</p>

<p>This means that services are defined by their interface classes, but actual implementation of a service can be chosen by site administrator. This will enable us to easily try and swap between various ways of doing things.</p>

<p><strong>Example:</strong> URL name generation can be moved to a <code>midcom_core_service_urlgenerator</code> service. Since the default URL name generator shipping with MidCOM does not deal particularly well with the Georgian language, a web developer deploying Midgard in Georgia can write their own service implementation and just swap that to be used in site configuration.</p>

<pre><code>$GLOBALS['midcom_config_local']['service_midcom_core_service_urlgenerator'] = 'ge_convert_urlgenerator';
</code></pre>

<h2>Performance</h2>

<p>The two-tiered approach of having interface and implementation separately means that two files have to be loaded for each service. This causes a slight performance hit when compared to current approach of one file per service.</p>

<p>However, it is believed that the benefit of loading services only when they're needed and being able to change service implementations on configuration level easily offsets this.</p>

<h2>Related tasks</h2>

<p>The actual service loader and an URL generator service have already been implemented as an experiment in MidCOM trunk. If this proposal is accepted, all services and "helper libraries" in MidCOM need to be refactored to the new model and components switched to use them.</p>

<p>As this is a big task, the proposal is to switch services to the new model one-by-one, starting from libraries that are used in only few places.</p>

<p>As of 2007-07-19, MidCOM loads 57 files in the <code>midcom.php</code>, with many of them potentially loading sub-dependencies. Most of these could be moved to on-demand handling or removed by the separately proposed DBA rewrite.</p>
]]></content>
        <summary type="html"><![CDATA[
<p>This is a proposal for moving service and library loading infrastructure in MidCOM 3 to a more on-demand service oriented model.</p>

<h2>Background</h2>

<p>Currently MidCOM loads a huge number of libraries and services for each request, requiring large amounts of file accesses and PHP parsing. Most of the services loaded are however not really used in a typical request, and so can be seen as being loaded "just in case".</p>

<p>The belief is that this makes the MidCOM environment heavier and more difficult to understand. This proposal outlines how MidCOM could migrate from the current model to a model where services would be loaded when they are used for the first time.</p>

<h2>MidCOM service loader</h2>

<p>A new class <code>midcom_helper_serviceloader</code> needs to be defined to act as the access point to the MidCOM service system. It will be instantiated as <code>$_MIDCOM-&gt;serviceloader</code> at MidCOM start-up.</p>

<p>The service loader should provide two public methods:</p>

<pre><code>boolean can_load($service)
</code></pre>

<p>Method for checking if a particular service is available on the system. This would enable components to deal with missing requirements or other situations where some functionality is not available more cleanly.</p>

<pre><code>object load($service)
</code></pre>

<p>Method for instantiating an implementation of a particular service.</p>

<h2>Inversion of control</h2>

<p>An additional benefit of the service loader model is that MidCOM's services can start following the Inversion of Control design pattern.</p>

<p>This means that services are defined by their interface classes, but actual implementation of a service can be chosen by site administrator. This will enable us to easily try and swap between various ways of doing things.</p>

<p><strong>Example:</strong> URL name generation can be moved to a <code>midcom_core_service_urlgenerator</code> service. Since the default URL name generator shipping with MidCOM does not deal particularly well with the Georgian language, a web developer deploying Midgard in Georgia can write their own service implementation and just swap that to be used in site configuration.</p>

<pre><code>$GLOBALS['midcom_config_local']['service_midcom_core_service_urlgenerator'] = 'ge_convert_urlgenerator';
</code></pre>

<h2>Performance</h2>

<p>The two-tiered approach of having interface and implementation separately means that two files have to be loaded for each service. This causes a slight performance hit when compared to current approach of one file per service.</p>

<p>However, it is believed that the benefit of loading services only when they're needed and being able to change service implementations on configuration level easily offsets this.</p>

<h2>Related tasks</h2>

<p>The actual service loader and an URL generator service have already been implemented as an experiment in MidCOM trunk. If this proposal is accepted, all services and "helper libraries" in MidCOM need to be refactored to the new model and components switched to use them.</p>

<p>As this is a big task, the proposal is to switch services to the new model one-by-one, starting from libraries that are used in only few places.</p>

<p>As of 2007-07-19, MidCOM loads 57 files in the <code>midcom.php</code>, with many of them potentially loading sub-dependencies. Most of these could be moved to on-demand handling or removed by the separately proposed DBA rewrite.</p>
]]></summary>
    </entry>
    <entry>
        <title>General Membership</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0034/"/>
        <published>2007-07-05T11:33:37+00:00</published>
        <updated>2007-07-05T11:33:37+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-9230d33e2aeb11dc8ffb796102bd70a070a0</id>
        <author>
            <name>piotrek.pokora@gmail.com (Piotr Pokora)</name>
        </author>
        <content type="html"><![CDATA[
<h1>Revision history</h1>

<p>2007-07-05 Created by Piotr Pokora</p>

<h1>Background</h1>

<p>Generic membership describes the basic way to group any MidgardSchema ( MgdSchema ) type ( class ) as an member of any other type registered in Midgard application. This mRFC also describes known Midgard functionality to group midgard_persons objects as a members of midgard_group one, and capabilities of membership introspection.</p>

<h1>Member owner type</h1>

<p>The type which groups other types. 
One type ( class ) can not group objects of the same type.</p>

<h1>Member type</h1>

<p>The type which belongs to owner group.
One type ( class ) can not belongs to group of the same type.</p>

<h1>Membership type</h1>

<p>The type which holds required information ( like owner or member identifier ) for members and owners.</p>

<h1>MidgardSchema definition</h1>

<p>Membership information shall be defined in xml schema file as a type properties and attributes and
particular introspection capabilities shall be implemented on API level.
Membership shall be always defined for member type and never for owner type.</p>

<p>Minimal information should contain:</p>

<ul><li>Member owner type name</li>
<li>Membership type name</li>
<li>Property and (or) field names which should be used for membership links</li>
</ul><h2>Example</h2>

<pre><code>&lt;type name="midgard_person" table="person" parentfield="creator"&gt;
    &lt;membership name="midgard_member" owner="midgard_group" &gt;
</code></pre>

<h1>Membership introspection</h1>

<p>Membership implementation should allow to retrieve following information:</p>

<h2>Member owner type</h2>

<ul><li>If type has members</li>
<li>What type name(s) are members of owner type</li>
<li>Fetch all members</li>
</ul><h2>Member type</h2>

<ul><li>If type is a member</li>
<li>What type is an owner of member type's </li>
</ul><h1>Member creation and deletion</h1>

<p>In general, members should be created with particular membership type implementation, to avoid direct and random database access. Membership type should always create or delete member for given member and owner type.</p>
]]></content>
        <summary type="html"><![CDATA[
<h1>Revision history</h1>

<p>2007-07-05 Created by Piotr Pokora</p>

<h1>Background</h1>

<p>Generic membership describes the basic way to group any MidgardSchema ( MgdSchema ) type ( class ) as an member of any other type registered in Midgard application. This mRFC also describes known Midgard functionality to group midgard_persons objects as a members of midgard_group one, and capabilities of membership introspection.</p>

<h1>Member owner type</h1>

<p>The type which groups other types. 
One type ( class ) can not group objects of the same type.</p>

<h1>Member type</h1>

<p>The type which belongs to owner group.
One type ( class ) can not belongs to group of the same type.</p>

<h1>Membership type</h1>

<p>The type which holds required information ( like owner or member identifier ) for members and owners.</p>

<h1>MidgardSchema definition</h1>

<p>Membership information shall be defined in xml schema file as a type properties and attributes and
particular introspection capabilities shall be implemented on API level.
Membership shall be always defined for member type and never for owner type.</p>

<p>Minimal information should contain:</p>

<ul><li>Member owner type name</li>
<li>Membership type name</li>
<li>Property and (or) field names which should be used for membership links</li>
</ul><h2>Example</h2>

<pre><code>&lt;type name="midgard_person" table="person" parentfield="creator"&gt;
    &lt;membership name="midgard_member" owner="midgard_group" &gt;
</code></pre>

<h1>Membership introspection</h1>

<p>Membership implementation should allow to retrieve following information:</p>

<h2>Member owner type</h2>

<ul><li>If type has members</li>
<li>What type name(s) are members of owner type</li>
<li>Fetch all members</li>
</ul><h2>Member type</h2>

<ul><li>If type is a member</li>
<li>What type is an owner of member type's </li>
</ul><h1>Member creation and deletion</h1>

<p>In general, members should be created with particular membership type implementation, to avoid direct and random database access. Membership type should always create or delete member for given member and owner type.</p>
]]></summary>
    </entry>
    <entry>
        <title>Midgard Object serialization</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0033/"/>
        <published>2006-09-18T13:16:29+00:00</published>
        <updated>2006-09-18T13:16:29+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-12c0c7a12f2cf7d302ca4f21489753c2</id>
        <content type="html"><![CDATA[
<h1>Revision history</h1>

<ul><li>2006-09-22 Updated by Piotr Pokora, added fixed 'midgard_object' root element to xml schema</li>
</ul><h1>Background</h1>

<p>This mRFC describes xml file format which should be used for objects' replication, and for data exchange between Midgard and other systems. It is impossible to define xml file format for every type registered in Midgard type system , however this mRFC focuses on minimal xml schema <a href="http://www.w3.org/TR/xmlschema-0/">(2)</a> file which should describe serialized Midgard object.
Xml file with serialized Midgard Object should contain Midgard namespace, Midgard Object type name, optionally its guid and lang which identify object and common metadata.</p>

<h1>Namespace</h1>

<p>Midgard namespace should be defined as: 
__http://www.midgard-project.org/midgard_object/1.8__</p>

<p>( Optionally namespace could define Midgard version for which given xml file can be used )</p>

<h1>MidgardObject</h1>

<p>Midgard type should be defined as complexType identified by name of string type. Optionally 'guid' and 'lang' atributes could be used to identify Midgard Object. Guid attribute if used should be at least 28 and at most 80 characters long <a href="http://www.midgard-project.org/development/mrfc/0018.html">(1)</a>. Lang <a href="http://www.loc.gov/standards/iso639-2/index.html">(3)</a> attribute should be 2 letter language code name and define available languages enumeration.</p>

<p>For better understanding and connectivity , midgard-core should have implemented functionality to create xml schema file for any type registered in Midgard Schema. Additionally this implementation should create languages enumeration for all available languages <a href="http://www.loc.gov/standards/iso639-2/index.html">(3)</a> in Midgard environment. Every Midgard object's property should be defined as element type with optional attributes.</p>

<h1>Multilingual data</h1>

<p>If serialized object is multilingual Midgard type and more than one language is used for such object , all language content objects should be serialized and stored in one xml file. In such case deserialization implementation should return array of multilingual objects, and lang attribute's value should be mandatory set in xml file.</p>

<h1>Parameters and attachments</h1>

<p>Optionally , object's paramaters ( registered as standalone midgard_parameter type ) and object's attachments ( registered as standalone midgard_attachment type ) could be serialized and stored in object's xml file.</p>

<h1>Minimal XML schema file:</h1>

<p>&lt;?xml version="1.0"?&gt;
   <br /><br /><br /></p>

<h1>Example:</h1>

<pre><code> &lt;?xml version="1.0" encoding="UTF-8"?&gt;
 &lt;midgard_object xmlns="http://www.midgard-project.org/midgard_object/1.8"&gt;
   &lt;midgard_article guid="26b621b938c4aea0e021d4baae69d6ab" lang="en"&gt;
     &lt;metadata&gt;
       &lt;creator&gt;&lt;/creator&gt;
       &lt;created&gt;1999-05-07 18:04:04&lt;/created&gt;
       &lt;revisor&gt;&lt;/revisor&gt;
       &lt;revised&gt;2006-09-10 09:28:08&lt;/revised&gt;
       &lt;revision&gt;1&lt;/revision&gt;
       &lt;locker&gt;&lt;/locker&gt;
       &lt;locked&gt;1999-08-17 16:01:32&lt;/locked&gt;
       &lt;approver&gt;&lt;/approver&gt;
       &lt;approved&gt;&lt;/approved&gt;
       &lt;authors&gt;f6b665f1984503790ed91f39b11b5392&lt;/authors&gt;
       &lt;owner&gt;&lt;/owner&gt;
       &lt;schedulestart&gt;&lt;/schedulestart&gt;
       &lt;scheduleend&gt;&lt;/scheduleend&gt;
       &lt;hidden&gt;0&lt;/hidden&gt;
       &lt;navnoentry&gt;0&lt;/navnoentry&gt;
       &lt;size&gt;481&lt;/size&gt;
       &lt;published&gt;1999-05-07 18:04:04&lt;/published&gt;
       &lt;score&gt;0&lt;/score&gt;
       &lt;imported&gt;&lt;/imported&gt;
       &lt;exported&gt;2006-09-14 12:37:40+0000&lt;/exported&gt;
       &lt;deleted&gt;0&lt;/deleted&gt;
     &lt;/metadata&gt;
     &lt;action&gt;&lt;/action&gt;
     &lt;id&gt;2&lt;/id&gt;
     &lt;created&gt;1999-05-07 18:04:04&lt;/created&gt;
     &lt;revisor&gt;f6b665f1984503790ed91f39b11b5392&lt;/revisor&gt;
     &lt;score&gt;0&lt;/score&gt;
     &lt;title&gt;Host Administration&lt;/title&gt;
     &lt;abstract&gt;Midgard host and directory management
 &lt;/abstract&gt;
     &lt;locker&gt;f6b665f1984503790ed91f39b11b5392&lt;/locker&gt;
     &lt;caldays&gt;0&lt;/caldays&gt;
     &lt;approved&gt;&lt;/approved&gt;
     &lt;calstart&gt;0000-00-00&lt;/calstart&gt;
     &lt;content&gt;&lt;p&gt;
 Use the host administration tool to create and maintain the       structure and functionality of your web sites. Use the layout adminstration tool for controlling the appearance of the site and the content administration tool for the dynamic content of the site.   &lt;/content&gt;
     &lt;icon&gt;0&lt;/icon&gt;
     &lt;type&gt;0&lt;/type&gt;
     &lt;creator&gt;f6b665f1984503790ed91f39b11b53922&lt;/creator&gt;
     &lt;revised&gt;&lt;/revised&gt;
     &lt;approver&gt;0&lt;/approver&gt;
     &lt;extra1&gt;&lt;/extra1&gt;
     &lt;name&gt;&lt;/name&gt;
     &lt;author&gt;f6b665f1984503790ed91f39b11b5392&lt;/author&gt;
     &lt;url&gt;&lt;/url&gt;
     &lt;contentauthor&gt;1&lt;/contentauthor&gt;
     &lt;contentcreated&gt;1999-05-07 18:04:04&lt;/contentcreated&gt;
     &lt;print&gt;0&lt;/print&gt;
     &lt;extra2&gt;&lt;/extra2&gt;
     &lt;view&gt;0&lt;/view&gt;
     &lt;extra3&gt;&lt;/extra3&gt;
     &lt;revision&gt;0&lt;/revision&gt;
     &lt;sid&gt;2&lt;/sid&gt;
     &lt;locked&gt;1999-08-17 16:01:32&lt;/locked&gt;
     &lt;up&gt;d0099a92c1018461bc6e33cd0a1c435b&lt;/up&gt;
   &lt;/midgard_article&gt;
 &lt;/midgard_object&gt;
</code></pre>

<h1>References:</h1>

<ul><li>http://www.midgard-project.org/development/mrfc/0018.html</li>
<li>http://www.w3.org/TR/xmlschema-0/</li>
<li>http://www.loc.gov/standards/iso639-2/index.html</li>
</ul>]]></content>
        <summary type="html"><![CDATA[
<h1>Revision history</h1>

<ul><li>2006-09-22 Updated by Piotr Pokora, added fixed 'midgard_object' root element to xml schema</li>
</ul><h1>Background</h1>

<p>This mRFC describes xml file format which should be used for objects' replication, and for data exchange between Midgard and other systems. It is impossible to define xml file format for every type registered in Midgard type system , however this mRFC focuses on minimal xml schema <a href="http://www.w3.org/TR/xmlschema-0/">(2)</a> file which should describe serialized Midgard object.
Xml file with serialized Midgard Object should contain Midgard namespace, Midgard Object type name, optionally its guid and lang which identify object and common metadata.</p>

<h1>Namespace</h1>

<p>Midgard namespace should be defined as: 
__http://www.midgard-project.org/midgard_object/1.8__</p>

<p>( Optionally namespace could define Midgard version for which given xml file can be used )</p>

<h1>MidgardObject</h1>

<p>Midgard type should be defined as complexType identified by name of string type. Optionally 'guid' and 'lang' atributes could be used to identify Midgard Object. Guid attribute if used should be at least 28 and at most 80 characters long <a href="http://www.midgard-project.org/development/mrfc/0018.html">(1)</a>. Lang <a href="http://www.loc.gov/standards/iso639-2/index.html">(3)</a> attribute should be 2 letter language code name and define available languages enumeration.</p>

<p>For better understanding and connectivity , midgard-core should have implemented functionality to create xml schema file for any type registered in Midgard Schema. Additionally this implementation should create languages enumeration for all available languages <a href="http://www.loc.gov/standards/iso639-2/index.html">(3)</a> in Midgard environment. Every Midgard object's property should be defined as element type with optional attributes.</p>

<h1>Multilingual data</h1>

<p>If serialized object is multilingual Midgard type and more than one language is used for such object , all language content objects should be serialized and stored in one xml file. In such case deserialization implementation should return array of multilingual objects, and lang attribute's value should be mandatory set in xml file.</p>

<h1>Parameters and attachments</h1>

<p>Optionally , object's paramaters ( registered as standalone midgard_parameter type ) and object's attachments ( registered as standalone midgard_attachment type ) could be serialized and stored in object's xml file.</p>

<h1>Minimal XML schema file:</h1>

<p>&lt;?xml version="1.0"?&gt;
   <br /><br /><br /></p>

<h1>Example:</h1>

<pre><code> &lt;?xml version="1.0" encoding="UTF-8"?&gt;
 &lt;midgard_object xmlns="http://www.midgard-project.org/midgard_object/1.8"&gt;
   &lt;midgard_article guid="26b621b938c4aea0e021d4baae69d6ab" lang="en"&gt;
     &lt;metadata&gt;
       &lt;creator&gt;&lt;/creator&gt;
       &lt;created&gt;1999-05-07 18:04:04&lt;/created&gt;
       &lt;revisor&gt;&lt;/revisor&gt;
       &lt;revised&gt;2006-09-10 09:28:08&lt;/revised&gt;
       &lt;revision&gt;1&lt;/revision&gt;
       &lt;locker&gt;&lt;/locker&gt;
       &lt;locked&gt;1999-08-17 16:01:32&lt;/locked&gt;
       &lt;approver&gt;&lt;/approver&gt;
       &lt;approved&gt;&lt;/approved&gt;
       &lt;authors&gt;f6b665f1984503790ed91f39b11b5392&lt;/authors&gt;
       &lt;owner&gt;&lt;/owner&gt;
       &lt;schedulestart&gt;&lt;/schedulestart&gt;
       &lt;scheduleend&gt;&lt;/scheduleend&gt;
       &lt;hidden&gt;0&lt;/hidden&gt;
       &lt;navnoentry&gt;0&lt;/navnoentry&gt;
       &lt;size&gt;481&lt;/size&gt;
       &lt;published&gt;1999-05-07 18:04:04&lt;/published&gt;
       &lt;score&gt;0&lt;/score&gt;
       &lt;imported&gt;&lt;/imported&gt;
       &lt;exported&gt;2006-09-14 12:37:40+0000&lt;/exported&gt;
       &lt;deleted&gt;0&lt;/deleted&gt;
     &lt;/metadata&gt;
     &lt;action&gt;&lt;/action&gt;
     &lt;id&gt;2&lt;/id&gt;
     &lt;created&gt;1999-05-07 18:04:04&lt;/created&gt;
     &lt;revisor&gt;f6b665f1984503790ed91f39b11b5392&lt;/revisor&gt;
     &lt;score&gt;0&lt;/score&gt;
     &lt;title&gt;Host Administration&lt;/title&gt;
     &lt;abstract&gt;Midgard host and directory management
 &lt;/abstract&gt;
     &lt;locker&gt;f6b665f1984503790ed91f39b11b5392&lt;/locker&gt;
     &lt;caldays&gt;0&lt;/caldays&gt;
     &lt;approved&gt;&lt;/approved&gt;
     &lt;calstart&gt;0000-00-00&lt;/calstart&gt;
     &lt;content&gt;&lt;p&gt;
 Use the host administration tool to create and maintain the       structure and functionality of your web sites. Use the layout adminstration tool for controlling the appearance of the site and the content administration tool for the dynamic content of the site.   &lt;/content&gt;
     &lt;icon&gt;0&lt;/icon&gt;
     &lt;type&gt;0&lt;/type&gt;
     &lt;creator&gt;f6b665f1984503790ed91f39b11b53922&lt;/creator&gt;
     &lt;revised&gt;&lt;/revised&gt;
     &lt;approver&gt;0&lt;/approver&gt;
     &lt;extra1&gt;&lt;/extra1&gt;
     &lt;name&gt;&lt;/name&gt;
     &lt;author&gt;f6b665f1984503790ed91f39b11b5392&lt;/author&gt;
     &lt;url&gt;&lt;/url&gt;
     &lt;contentauthor&gt;1&lt;/contentauthor&gt;
     &lt;contentcreated&gt;1999-05-07 18:04:04&lt;/contentcreated&gt;
     &lt;print&gt;0&lt;/print&gt;
     &lt;extra2&gt;&lt;/extra2&gt;
     &lt;view&gt;0&lt;/view&gt;
     &lt;extra3&gt;&lt;/extra3&gt;
     &lt;revision&gt;0&lt;/revision&gt;
     &lt;sid&gt;2&lt;/sid&gt;
     &lt;locked&gt;1999-08-17 16:01:32&lt;/locked&gt;
     &lt;up&gt;d0099a92c1018461bc6e33cd0a1c435b&lt;/up&gt;
   &lt;/midgard_article&gt;
 &lt;/midgard_object&gt;
</code></pre>

<h1>References:</h1>

<ul><li>http://www.midgard-project.org/development/mrfc/0018.html</li>
<li>http://www.w3.org/TR/xmlschema-0/</li>
<li>http://www.loc.gov/standards/iso639-2/index.html</li>
</ul>]]></summary>
    </entry>
    <entry>
        <title>Multilingual MidCOM</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0032/"/>
        <published>2006-07-26T14:55:44+00:00</published>
        <updated>2006-07-26T14:55:44+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-2ce647c080dd10a0a862fe43746ce3a3</id>
        <content type="html"><![CDATA[
<p>This proposal outlines how multilingual sites should be managed in the MidCOM framework utilizing the MultiLang features of Midgard 1.8. This mRFC been submitted to the Midgard Community for discussion and approval under the Creative Commons Attribution-ShareAlike license.</p>

<h2>Multilingual sites</h2>

<p>Midgard's base of power is Europe where there are many languages and many organizations operating across language barriers. This makes it very important to support easy management of multilingual sites.</p>

<p>Traditionally there have been two different types of multilingual sites:</p>

<ul><li><strong>Sites in multiple languages:</strong> These are sites that contain approximately same information in each language, either mandated by law or by organization's desire to reach different language audiences</li>
<li><strong>Multiple language versions of site:</strong> These sites can contain very different content structures targeted at domestic and foreign markets, or based on some other differentiation</li>
</ul><p>This proposal focuses on the first of these two. Multiple language versions of a site are better managed using separate content trees for each site than using MultiLang features.</p>

<h2>MultiLang background</h2>

<p>Right from the beginnings of the project, Midgard has had a strong international focus. Multibyte character set support landed in Midgard already in October 1999 in order to support managing sites in languages like Russian and Chinese. UTF-8 was made the default character set for Midgard in the 1.6 series.</p>

<p>However, in addition to character sets, also translation of actual content was needed. <a href="http://www.midgard-project.org/midcom-permalink-a22d4e60eaa3ebcf3ac425856df2dc13">MultiLingual Midgard</a> was presented as <a href="http://midgard.dataflow.ch/">a patch</a> by David Schmitter from DataFlow in Switzerland in May 2003, and entered Midgard proper for the 1.5.0 release.</p>

<p>This made the Midgard content formats support different translations of content, but besides DataFlow's proprietary <a href="http://www.dataflow-solutions.ch/products/webinone/">WebInOne</a> publishing tool, no Midgard authoring interface has actually added MultiLang support.</p>

<p>The reason for not supporting MultiLang has mostly been the difficulty of integrating good translation workflow, and unclear PHP-level programming APIs for it. The APIs have now however matured enough with integration to MgdSchema and <a href="http://www.midgard-project.org/midcom-permalink-7d3914b74c189137e500088a64d55403">Query Builder</a> tools so that supporting MultiLingual content cleanly is finally possible.</p>

<h2>Implementation into MidCOM</h2>

<p>Here is a description on how MultiLang should be implemented into the Midgard Component Framework. The aim here is to make creating and maintaining multilingual sites easy without having to impose changes into MidCOM components.</p>

<h3>Choosing languages used on site</h3>

<p>Webite's language selections (languages available for the site and the default language) are stored in the MidCOM configuration array.</p>

<p>The language selections can be made using Site Wizard for better convenience</p>

<h3>Language selection for content</h3>

<p>Languages would be selected using the <code>$argv[0]</code> prefix of the site, i.e. Finnish version of "About us" would reside in <code>/fi/about</code>. This can be implemented in a centralized fashion by modifying MidCOM's URL parser and making it call the corresponding <a href="http://www.midgard-project.org/midcom-permalink-c731d33b1ece522121099a63c800c729">MidCOM i18n service</a> <code>set_language</code> method for changing language.</p>

<p>In addition to the per-language URLs, there would be the "language neutral" URL for each object. This would redirect user to appropriate URL based on their browser language selection, i.e. <code>/about</code> would redirect me to <code>/de/about</code> for German language users.</p>

<h3>Navigation building and object instantiation</h3>

<p>Language versions of site should obviously show only the contents translated to their languages in navigation and content listings (like news lists for instance). Since MidCOM has a centralized wrapper for Query Builder, the DBA can easily add the language constraint into all DB queries transparently. This means components don't have to do any language-based processing to show only Norwegian news items.</p>

<p>Similarly, when an object is instantiated (<code>get_by_guid</code> etc), DBA should check if the <code>$object-&gt;lang</code> is the current language and if not fail the instantiation.</p>

<p>MidCOM should contain a specific "translation to this language not found" error  message that could be triggered if requested object is not available in current language. This error message could contain links to the existing language versions.</p>

<h3>Content editing</h3>

<p>Since editing MidCOM content now happens on-site and there are language prefixes available, switching editing views between languages is just a matter of changing the site prefix.</p>

<p>However, there should be some facilities for showing to translators what has been changes in the "default language" contents of an object so they know what to translate. This relates to RCS version control services in MidCOM.</p>

<h3>Content language vs. UI language</h3>

<p>MidCOM's i18n service has already been modified so that user interface language can be different from actual content language. Many multilingual organizations prefer to run their software in a common language to ease documentation and training.</p>

<h3>Different language versions</h3>

<p>The information on different language versions of an object must be available so that MidCOM's metadata system can populate links to the different translations.</p>

<h2>API-level requirements</h2>

<p>Here is a list of requirements from the MultiLang implementation in Midgard Core that are needed for this mRFC:</p>

<ul><li>The <code>midgard_language</code> objects must be available for regular Query Builder operations, and must contain a <code>locale</code> field with the appropriate UNIX system locale</li>
<li>When <code>mgd_set_lang(X)</code> has been called, all object update/create/delete operations must apply to the content of that particular language</li>
<li><code>$object-&gt;get_languages()</code> must return list of languages the object is available for</li>
<li>Each language version must contain a revision timestamp to help with translation workflow</li>
<li>When <code>set_lang</code> has been called for Query Builder, it must only return objects that are in that particular language, no <em>lang0</em> objects</li>
</ul>]]></content>
        <summary type="html"><![CDATA[
<p>This proposal outlines how multilingual sites should be managed in the MidCOM framework utilizing the MultiLang features of Midgard 1.8. This mRFC been submitted to the Midgard Community for discussion and approval under the Creative Commons Attribution-ShareAlike license.</p>

<h2>Multilingual sites</h2>

<p>Midgard's base of power is Europe where there are many languages and many organizations operating across language barriers. This makes it very important to support easy management of multilingual sites.</p>

<p>Traditionally there have been two different types of multilingual sites:</p>

<ul><li><strong>Sites in multiple languages:</strong> These are sites that contain approximately same information in each language, either mandated by law or by organization's desire to reach different language audiences</li>
<li><strong>Multiple language versions of site:</strong> These sites can contain very different content structures targeted at domestic and foreign markets, or based on some other differentiation</li>
</ul><p>This proposal focuses on the first of these two. Multiple language versions of a site are better managed using separate content trees for each site than using MultiLang features.</p>

<h2>MultiLang background</h2>

<p>Right from the beginnings of the project, Midgard has had a strong international focus. Multibyte character set support landed in Midgard already in October 1999 in order to support managing sites in languages like Russian and Chinese. UTF-8 was made the default character set for Midgard in the 1.6 series.</p>

<p>However, in addition to character sets, also translation of actual content was needed. <a href="http://www.midgard-project.org/midcom-permalink-a22d4e60eaa3ebcf3ac425856df2dc13">MultiLingual Midgard</a> was presented as <a href="http://midgard.dataflow.ch/">a patch</a> by David Schmitter from DataFlow in Switzerland in May 2003, and entered Midgard proper for the 1.5.0 release.</p>

<p>This made the Midgard content formats support different translations of content, but besides DataFlow's proprietary <a href="http://www.dataflow-solutions.ch/products/webinone/">WebInOne</a> publishing tool, no Midgard authoring interface has actually added MultiLang support.</p>

<p>The reason for not supporting MultiLang has mostly been the difficulty of integrating good translation workflow, and unclear PHP-level programming APIs for it. The APIs have now however matured enough with integration to MgdSchema and <a href="http://www.midgard-project.org/midcom-permalink-7d3914b74c189137e500088a64d55403">Query Builder</a> tools so that supporting MultiLingual content cleanly is finally possible.</p>

<h2>Implementation into MidCOM</h2>

<p>Here is a description on how MultiLang should be implemented into the Midgard Component Framework. The aim here is to make creating and maintaining multilingual sites easy without having to impose changes into MidCOM components.</p>

<h3>Choosing languages used on site</h3>

<p>Webite's language selections (languages available for the site and the default language) are stored in the MidCOM configuration array.</p>

<p>The language selections can be made using Site Wizard for better convenience</p>

<h3>Language selection for content</h3>

<p>Languages would be selected using the <code>$argv[0]</code> prefix of the site, i.e. Finnish version of "About us" would reside in <code>/fi/about</code>. This can be implemented in a centralized fashion by modifying MidCOM's URL parser and making it call the corresponding <a href="http://www.midgard-project.org/midcom-permalink-c731d33b1ece522121099a63c800c729">MidCOM i18n service</a> <code>set_language</code> method for changing language.</p>

<p>In addition to the per-language URLs, there would be the "language neutral" URL for each object. This would redirect user to appropriate URL based on their browser language selection, i.e. <code>/about</code> would redirect me to <code>/de/about</code> for German language users.</p>

<h3>Navigation building and object instantiation</h3>

<p>Language versions of site should obviously show only the contents translated to their languages in navigation and content listings (like news lists for instance). Since MidCOM has a centralized wrapper for Query Builder, the DBA can easily add the language constraint into all DB queries transparently. This means components don't have to do any language-based processing to show only Norwegian news items.</p>

<p>Similarly, when an object is instantiated (<code>get_by_guid</code> etc), DBA should check if the <code>$object-&gt;lang</code> is the current language and if not fail the instantiation.</p>

<p>MidCOM should contain a specific "translation to this language not found" error  message that could be triggered if requested object is not available in current language. This error message could contain links to the existing language versions.</p>

<h3>Content editing</h3>

<p>Since editing MidCOM content now happens on-site and there are language prefixes available, switching editing views between languages is just a matter of changing the site prefix.</p>

<p>However, there should be some facilities for showing to translators what has been changes in the "default language" contents of an object so they know what to translate. This relates to RCS version control services in MidCOM.</p>

<h3>Content language vs. UI language</h3>

<p>MidCOM's i18n service has already been modified so that user interface language can be different from actual content language. Many multilingual organizations prefer to run their software in a common language to ease documentation and training.</p>

<h3>Different language versions</h3>

<p>The information on different language versions of an object must be available so that MidCOM's metadata system can populate links to the different translations.</p>

<h2>API-level requirements</h2>

<p>Here is a list of requirements from the MultiLang implementation in Midgard Core that are needed for this mRFC:</p>

<ul><li>The <code>midgard_language</code> objects must be available for regular Query Builder operations, and must contain a <code>locale</code> field with the appropriate UNIX system locale</li>
<li>When <code>mgd_set_lang(X)</code> has been called, all object update/create/delete operations must apply to the content of that particular language</li>
<li><code>$object-&gt;get_languages()</code> must return list of languages the object is available for</li>
<li>Each language version must contain a revision timestamp to help with translation workflow</li>
<li>When <code>set_lang</code> has been called for Query Builder, it must only return objects that are in that particular language, no <em>lang0</em> objects</li>
</ul>]]></summary>
    </entry>
    <entry>
        <title>MidgardApacheCache</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0031/"/>
        <published>2006-06-14T16:46:23+00:00</published>
        <updated>2006-06-14T16:46:23+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-f39ef5aac462e34a806b6a0008a889d0</id>
        <content type="html"><![CDATA[
<p>MidgardApacheCache</p>

<h1>Revision history</h1>

<ul><li>2006-06-14 Created by Piotr Pokora</li>
</ul><h1>Background</h1>

<p>Cache approaches:</p>

<ul><li>data reusability</li>
<li>limit the need to query the same objects with every request</li>
<li>cache objects which are queried with the same data with every request</li>
</ul><h1>Implementation</h1>

<p>MidgardApacheCache should extend base MidgardCache class, and should be optimized 
for any midgard extension which is used in Apache module environment.
MidgardCache base class should be assigned as private member of MidgardConnection
and thus connection handler object could be responsible for managing internal's core
objects references counts.</p>

<p>MidgardApacheCache when instanciated should return UUID which should be available 
during the whole application runtime. For Apache module, it means - as long as httpd
server is running.</p>

<p>There shouldn't be any method or function in implementation which should allow list 
all cache entries ( MidgardApacheCache instances ) available.</p>

<p>Retrieving MidgardApacheCache instance should be possible only with UUID representing
particular object instance and application which use cache object should be responsible 
to store this UUID.</p>

<h3>Example</h3>

<pre><code>&lt;?php

$application_cache_guid = "guid_string"; 

$cache = new midgard_apache_cache($application_cache_guid);
if(!$cache-&gt;exists())
    $application_cache_guid = $cache-&gt;create();
else 
    $cache-&gt;get();
?&gt;
</code></pre>

<p>The main purpose of MidgardApacheCache should be possibility to store objects , however
other types should be supported as well. Objects should be identified by guids in the same 
way as are identified and retrieved in typical Midgard applications.
Other types like arrays should be registered with unique names.</p>

<h3>Example</h3>

<pre><code>&lt;?php

$object = $cache-&gt;get_type_by_guid("object_guid_string");
$object-&gt;register("my_constant_array", $array_type);
$array = $object-&gt;get_type_by_name("my_constant_array");

?&gt;
</code></pre>

<p>MidgardApacheCache should implement such features:</p>

<ul><li>initialize cache</li>
<li>get cache object instance identified by UUID</li>
<li>add type to cache</li>
<li>update type in cache</li>
<li>get type from cache</li>
<li>remove type from cache</li>
</ul>]]></content>
        <summary type="html"><![CDATA[
<p>MidgardApacheCache</p>

<h1>Revision history</h1>

<ul><li>2006-06-14 Created by Piotr Pokora</li>
</ul><h1>Background</h1>

<p>Cache approaches:</p>

<ul><li>data reusability</li>
<li>limit the need to query the same objects with every request</li>
<li>cache objects which are queried with the same data with every request</li>
</ul><h1>Implementation</h1>

<p>MidgardApacheCache should extend base MidgardCache class, and should be optimized 
for any midgard extension which is used in Apache module environment.
MidgardCache base class should be assigned as private member of MidgardConnection
and thus connection handler object could be responsible for managing internal's core
objects references counts.</p>

<p>MidgardApacheCache when instanciated should return UUID which should be available 
during the whole application runtime. For Apache module, it means - as long as httpd
server is running.</p>

<p>There shouldn't be any method or function in implementation which should allow list 
all cache entries ( MidgardApacheCache instances ) available.</p>

<p>Retrieving MidgardApacheCache instance should be possible only with UUID representing
particular object instance and application which use cache object should be responsible 
to store this UUID.</p>

<h3>Example</h3>

<pre><code>&lt;?php

$application_cache_guid = "guid_string"; 

$cache = new midgard_apache_cache($application_cache_guid);
if(!$cache-&gt;exists())
    $application_cache_guid = $cache-&gt;create();
else 
    $cache-&gt;get();
?&gt;
</code></pre>

<p>The main purpose of MidgardApacheCache should be possibility to store objects , however
other types should be supported as well. Objects should be identified by guids in the same 
way as are identified and retrieved in typical Midgard applications.
Other types like arrays should be registered with unique names.</p>

<h3>Example</h3>

<pre><code>&lt;?php

$object = $cache-&gt;get_type_by_guid("object_guid_string");
$object-&gt;register("my_constant_array", $array_type);
$array = $object-&gt;get_type_by_name("my_constant_array");

?&gt;
</code></pre>

<p>MidgardApacheCache should implement such features:</p>

<ul><li>initialize cache</li>
<li>get cache object instance identified by UUID</li>
<li>add type to cache</li>
<li>update type in cache</li>
<li>get type from cache</li>
<li>remove type from cache</li>
</ul>]]></summary>
    </entry>
    <entry>
        <title>Midgard object replication</title>
        <link rel="alternate" type="text/html" href="http://www.midgard-project.org/development/mrfc/0030/"/>
        <published>2006-06-02T17:47:52+00:00</published>
        <updated>2006-06-02T17:47:52+00:00</updated>
        <id>http://www.midgard-project.org/midcom-permalink-b8a2c4d18d1566cf608c40f75774f96d</id>
        <content type="html"><![CDATA[
<h1>Revision history</h1>

<ul><li>2006-06-02 Created by Piotr Pokora </li>
<li>2006-06-17 Updated: possibility to delete and undelete 
objects </li>
<li>2006-06-19 (torben) Commented the MidCOM section, reset
the mRFC to draft status due to this.</li>
</ul><h1>Background</h1>

<p>This mRFC is a proposal for repligard functionality replacement , supported by midgard-core and by any language for which Midgard language bindings exist. As repligard supported Midgard database replication without any possibility to change its behaviour a lot , this mRFC focuses on object's records  replication , object exporting and object importing to or from any database storage. This mRFC also describes possibility to undelete and purge object's record(s).</p>

<p>Examples in this mRFC use PHP as scripting language.</p>

<h3>Example: exporting all newest objects example.</h3>

<pre><code>&lt;?php  

$exported_objects = array();
foreach ($_MIDGARD['types'] as $type =&gt; $type_id) {
    $qb = new midgardquerybuilder($type);
    $qb-&gt;add_constraint("metadata.created", "&gt;", $yesterday); 
$retval = $qb-&gt;execute();
    $exported_objects = array_merge($exported_objects, $retval);
}

foreach($exported_objects as $object){
    $object-&gt;export();
}   
?&gt;
</code></pre>

<h1>Midgard object metadata</h1>

<p>Every Midgard object's metadata class should have 'exported' and 'imported' members assigned as properties of midgard_metadata type. These two properties's values represented by corresponding database storage values should be settable only by midgard-core with particular methods.
Both properties must be MGD_TYPE_DATETIME type.</p>

<h1>Midgard object methods</h1>

<p>Midgard-core must support <strong>export</strong> and <strong>import</strong> methods for object's replication. Object's replication related metadata should be managed by basic methods: create, update, delete, undelete , purge, import, export.</p>

<h2>Create</h2>

<ul><li><strong>created</strong> , current datetime value must be set</li>
<li><strong>revised</strong>, current datetime value should be set </li>
<li><strong>imported</strong>, empty value must be set  </li>
<li><strong>exported</strong>, empty value must be set</li>
</ul><h2>Update</h2>

<ul><li><strong>created</strong>, value can not be set </li>
<li><strong>revised</strong>, current datetime value must be set </li>
<li><strong>imported</strong>, empty value must be set</li>
<li><strong>exported</strong>, empty value must be set</li>
</ul><h2>Import</h2>

<ul><li><strong>created</strong>, value can not be set if object's record exists in database
in any other case object's record must be created and metadata <strong>created</strong>
with current datetime value must be set </li>
<li><strong>revised</strong>, value shouldn't be set if object's record doesn't exists in database
in any other case metadata <strong>revised</strong> must be set with value of imported object's 
metadata <strong>revised</strong> value</li>
<li><strong>imported</strong>, current datetime value should be set</li>
<li><strong>exported</strong>, empty value must be set</li>
</ul><p>Object can be imported to database only if <strong>imported</strong> metadata property value of the object for which record in database exists is empty and its metadata <strong>revised</strong> property value is not newer
than the value of the same property of object which is to be imported.</p>

<h2>Export</h2>

<ul><li><strong>created</strong>, value can not be set</li>
<li><strong>revised</strong>, value can not be set</li>
<li><strong>imported</strong>, value can not be set</li>
<li><strong>exported</strong>, current datetime value must be set</li>
</ul><p>Object can be exported from database without any restriction. Application which exports objects defines what constraints are used to export object records.</p>

<h3>Example: exporting visible midgard_article records</h3>

<p>This example demonstrates how to export newest and not hidden midgard_article objects</p>

<pre><code>&lt;?php

$qb = new midgardquerybuilder("midgard_article");
$qb-&gt;add_constraint("metadata.created", "&gt;", $yesterday);
$qb-&gt;add_constraint("metadata.hidden", "=", FALSE);

/* Do not export objects which were created and exported for the last 24 hours */
$qb-&gt;add_constraint("metadata.exported", "=", "");

$retval = $qb-&gt;execute();

foreach($retval as $object){
    $object-&gt;export();
}   
?&gt;
</code></pre>

<h3>Delete</h3>

<ul><li><strong>created</strong>, value can not be set</li>
<li><strong>revised</strong>, current datetime value must be set</li>
<li><strong>imported</strong>, value can not be set</li>
<li><strong>exported</strong>, value can not be set</li>
<li><strong>metadata.deleted</strong>, value must be set.</li>
</ul><p>Object's record(s) can not be deleted from database when delete method is invoked. Instead , object's metadata delete property should be explicitly updated with correct delete value. For performance reason this value should be an integer type. This metadata property should be also used by midgard core as mandatory Midgard Query Builder's constraint added internally by Query Builder implementation.</p>

<h3>Undelete</h3>

<ul><li><strong>created</strong>, value can not be set</li>
<li><strong>revised</strong>, current datetime value must be set</li>
<li><strong>imported</strong>, value can not be set</li>
<li><strong>exported</strong>, value can not be set</li>
<li><strong>metadata.deleted</strong>, value must be (re)set to initial default state.</li>
</ul><h3>Purge</h3>

<p>When this method is invoked, midgard core should delete object's record(s) from database and should update repligard table. Following values should be set for corresponding record in repligard table:</p>

<ul><li>object's class name</li>
<li>object's guid</li>
<li>purge action should be set to TRUE value</li>
</ul><h2>Repligard table</h2>

<p>Repligard table must containt only object's guid and typename ( classname ) for which new object instance with particular guid can be created. Additionaly repligard table should contain information if object's record(s) was purged.</p>

<h3>Query deleted objects</h3>

<p>Midgard core should implement functionality which allows to query only  deleted objects. This functionality could be implemented with new  Midgard Query Builder method or with new Midgard type.</p>

<h2>Staging/live in MidCOM</h2>

<blockquote>
  <p>Missing topics: Data model, general service architecture,
  including the layers of the communication infrastucture.</p>
  
  <p>Torben</p>
</blockquote>

<p>Since replication interfaces are exposed to PHP level, the staging/live process can be handled in MidCOM space. This should make the simple replication scenarios like an article that is approved much faster, the system more fault tolerant due to the queue system, and finally the replication logic easier to tweak because it is entirely in PHP level.</p>

<p>There will be a midcom.helper.staginglive purecode component to handle the replication process.</p>

<blockquote>
  <p>This will have to be <code>midcom.services.replication</code>.</p>
  
  <p>Torben</p>
</blockquote>

<h3>Invoking replication</h3>

<p>The replication component will register UPDATE and DELETE watchers for <code>midcom_core_dbobject</code>. Since approvals are stored into Midgard metadata fields using <code>update()</code> method approval should be carried to this watcher.</p>

<blockquote>
  <p>Note, that you cannot register watches for 
  <code>midcom_core_dbobject</code>, as this class is not a base class
  for other DBA classes. It is more of a "mix-in" due to
  Limitations of the PHP OOP API. The correct definition 
  would be adding watches to all defined DBA classes by
  not limiting the watch to any class.</p>
  
  <p>Torben</p>
</blockquote>

<p>To catch objects updated or deleted outside MidCOM DBA the system will also provide a <code>cron</code> entry that will query through all MgdSchema types to see if there is something to replicate. This can be run relatively seldom, for example once per day.</p>

<blockquote>
  <p>This is not very precise. The criteria after which objects
  are marked for replication should be outlined.</p>
  
  <p>Torben</p>
</blockquote>

<h3>Export process</h3>

<p>The export watchers will execute an exporting method in the midcom.helper.staginglive interface class and provide it with the affected object as argument.</p>

<p>If approvals or scheduling are being used, the system will first check if the object itself is set to be visible. Otherwise visibility will be assumed.</p>

<p>If the object is visible, the same check will be done for its parent.</p>

<blockquote>
  <p>Note, that this can prohibit replication under certain
  circumstances: Assume that a topic and one of its articles
  are both changed. The article gets approved, the topic not.
  Replication of the article will then be delayed.</p>
  
  <p>Note as well, that there is another case, where you 
  actually need to be careful if you change the behavoir to
  cover the above special case: If the topic in question was
  newly created, it won't be available on the target server.</p>
  
  <p>Normally, the latter should be no problem if and only if
  only GUIDs are used for linking and, as such, ID mappings
  are not required. The legacy data structures do not yet
  do this. I very strongly suggest that this will be changed
  prior implementing this, even if this means that existing
  code (mainly QB lookups) have to be adapted to it.</p>
  
  <p>Torben</p>
</blockquote>

<p>If the parent is visible, the object will be marked for exporting. If the parent is not visible export is aborted and UI message "Object not exported because parent is not visible" sent to the user.</p>

<blockquote>
  <p>What happens later, when the parent gets cleared? Is the
  delayed object queued somewhere? This needs much more 
  detail.</p>
  
  <p>Torben</p>
</blockquote>

<p>Then the method will query the object's children and call the same method for them.</p>

<blockquote>
  <p>I assume that this is the fix for the above problem I 
  mentioned. The problem I see here is that you will often
  get large trees here, especially if you are at the top
  of the tree. Also you will have difficulties as you have
  to know all types which potentially have the object in
  question as a parent:</p>
  
  <p>Especially topics are tricky here, as several of the 
  components I wrote lately assign their data to topics,
  without actually using <code>midgard_article</code>. But groups
  or persons can easily reach a similar spread.</p>
  
  <p>Torben</p>
</blockquote>

<pre><code>TODO: Pseudocode for the exporting decision
</code></pre>

<blockquote>
  <p>I'd like to see this before +1'ing anything.</p>
  
  <p>Torben</p>
</blockquote>

<p>Finally the exported objects will be stored into replication queue and an <code>at</code> entry registered for running the replication next minute.</p>

<blockquote>
  <p>Is this wise? Or would it be more appropriate to have a 
  cron job doing it every X minutes to optimize / batch 
  the changes.</p>
  
  <p>Torben</p>
</blockquote>

<p>UI message "3 articles and 1 topic exported for replication" is sent to the user.</p>

<h3>Subscribers and replication queue</h3>

<p>Subscribers (Midgard sites to replicate to) are stored in the database. The subscriber entry contains the replication method used for that subscriber and address and authentication information required for the method.</p>

<p>When objects are exported, the export XML is stored into a <code>midcom_helper_staginglive_queue_entry</code> object for each subscriber.</p>

<blockquote>
  <p>Data duplication, the data model should be revised here.</p>
  
  <p>Torben</p>
</blockquote>

<p>Replication is launched by the <code>at</code> entry registered at export phase. The replication process goes through all subscribers, and tries to send the items of their queue to them using the defined method.</p>

<p>There can be multiple replication methods supported by the system. At first we will only implement a simple HTTP PUT (or POST) method sent to a MidCOM <code>exec</code> handler of the midcom.helper.staginglive component, authenticated using HTTP Basic Auth. Other methods could include Jabber/XMPP, DBE or even email.</p>

<blockquote>
  <p>Wouldn't some XML-RPC or other standardized remoting 
  mechanism be more appropriate then some proprietary
  solution?</p>
  
  <p>Torben</p>
</blockquote>

<p>Email could provide a high security replication solution where the exporting end would GPG encrypt and sign the email, then send it out as an email. The importing end would then read the email from the server, check its signature, decrypt it and import. This way the importing end could even be a mostly offline computer that would only connect to internet to receive the emails once per day (this is how FSF Europe's member registry works to protect privacy).</p>

<blockquote>
  <p>Consider using regular X.509 based encryption / signing
  instead of PGP. More standardized (almost as easy to use)
  and integrated into existing PKI infrastructures. This 
  should be available completly independant of the actual
  transport layer used, btw.</p>
  
  <p>Torben</p>
</blockquote>

<p>If the replication is successful, the queue entry is deleted. If not, the replication will be attempted again every hour using a <code>cron</code> entry.</p>

<blockquote>
  <p>Provide some fallback mechanism, similar to the SMTP 
  system. There should be a fixed number of retries, maybe
  with increased waiting periods after certain escalation
  levels.</p>
  
  <p>Also, it is recommended to flag entries as failed after
  a certain amount of retries have been reached.</p>
  
  <p>Failed connections to a subscriber should escalate as well,
  disabling the subscriber until the situation is resolved.
  Otherwise, there would be an easy DOS scenario when too 
  many replications pile up for a given subscriber.</p>
  
  <p>Torben</p>
</blockquote>

<h4>Subscription types</h4>

<p>In the initial implementation every object is replicated to every subscriber. At a later stage we can implement different subscription type handlers that will enable limiting the subscription to particular MgdSchema types, object trees or even particular query constraints.</p>

<p>Examples of subscription types would be "content in tree", "my tasks" or "all forum posts".</p>

<blockquote>
  <p>This is rather vague, especially since the neccessary 
  basic infrastructure to provide something like this is
  never mentioned above. Goes into the chapter "missing
  service architecture".</p>
  
  <p>Torben</p>
</blockquote>

<h3>Import process</h3>

<p>Import process will simply call the Midgard <code>import</code> method for each object in the imported XML file.</p>

<blockquote>
  <p>No sanity checks, nothing? I think there has to be a high
  level of bulletproofing when letting such replications in.</p>
  
  <p>Torben</p>
</blockquote>
]]></content>
        <summary type="html"><![CDATA[
<h1>Revision history</h1>

<ul><li>2006-06-02 Created by Piotr Pokora </li>
<li>2006-06-17 Updated: possibility to delete and undelete 
objects </li>
<li>2006-06-19 (torben) Commented the MidCOM section, reset
the mRFC to draft status due to this.</li>
</ul><h1>Background</h1>

<p>This mRFC is a proposal for repligard functionality replacement , supported by midgard-core and by any language for which Midgard language bindings exist. As repligard supported Midgard database replication without any possibility to change its behaviour a lot , this mRFC focuses on object's records  replication , object exporting and object importing to or from any database storage. This mRFC also describes possibility to undelete and purge object's record(s).</p>

<p>Examples in this mRFC use PHP as scripting language.</p>

<h3>Example: exporting all newest objects example.</h3>

<pre><code>&lt;?php  

$exported_objects = array();
foreach ($_MIDGARD['types'] as $type =&gt; $type_id) {
    $qb = new midgardquerybuilder($type);
    $qb-&gt;add_constraint("metadata.created", "&gt;", $yesterday); 
$retval = $qb-&gt;execute();
    $exported_objects = array_merge($exported_objects, $retval);
}

foreach($exported_objects as $object){
    $object-&gt;export();
}   
?&gt;
</code></pre>

<h1>Midgard object metadata</h1>

<p>Every Midgard object's metadata class should have 'exported' and 'imported' members assigned as properties of midgard_metadata type. These two properties's values represented by corresponding database storage values should be settable only by midgard-core with particular methods.
Both properties must be MGD_TYPE_DATETIME type.</p>

<h1>Midgard object methods</h1>

<p>Midgard-core must support <strong>export</strong> and <strong>import</strong> methods for object's replication. Object's replication related metadata should be managed by basic methods: create, update, delete, undelete , purge, import, export.</p>

<h2>Create</h2>

<ul><li><strong>created</strong> , current datetime value must be set</li>
<li><strong>revised</strong>, current datetime value should be set </li>
<li><strong>imported</strong>, empty value must be set  </li>
<li><strong>exported</strong>, empty value must be set</li>
</ul><h2>Update</h2>

<ul><li><strong>created</strong>, value can not be set </li>
<li><strong>revised</strong>, current datetime value must be set </li>
<li><strong>imported</strong>, empty value must be set</li>
<li><strong>exported</strong>, empty value must be set</li>
</ul><h2>Import</h2>

<ul><li><strong>created</strong>, value can not be set if object's record exists in database
in any other case object's record must be created and metadata <strong>created</strong>
with current datetime value must be set </li>
<li><strong>revised</strong>, value shouldn't be set if object's record doesn't exists in database
in any other case metadata <strong>revised</strong> must be set with value of imported object's 
metadata <strong>revised</strong> value</li>
<li><strong>imported</strong>, current datetime value should be set</li>
<li><strong>exported</strong>, empty value must be set</li>
</ul><p>Object can be imported to database only if <strong>imported</strong> metadata property value of the object for which record in database exists is empty and its metadata <strong>revised</strong> property value is not newer
than the value of the same property of object which is to be imported.</p>

<h2>Export</h2>

<ul><li><strong>created</strong>, value can not be set</li>
<li><strong>revised</strong>, value can not be set</li>
<li><strong>imported</strong>, value can not be set</li>
<li><strong>exported</strong>, current datetime value must be set</li>
</ul><p>Object can be exported from database without any restriction. Application which exports objects defines what constraints are used to export object records.</p>

<h3>Example: exporting visible midgard_article records</h3>

<p>This example demonstrates how to export newest and not hidden midgard_article objects</p>

<pre><code>&lt;?php

$qb = new midgardquerybuilder("midgard_article");
$qb-&gt;add_constraint("metadata.created", "&gt;", $yesterday);
$qb-&gt;add_constraint("metadata.hidden", "=", FALSE);

/* Do not export objects which were created and exported for the last 24 hours */
$qb-&gt;add_constraint("metadata.exported", "=", "");

$retval = $qb-&gt;execute();

foreach($retval as $object){
    $object-&gt;export();
}   
?&gt;
</code></pre>

<h3>Delete</h3>

<ul><li><strong>created</strong>, value can not be set</li>
<li><strong>revised</strong>, current datetime value must be set</li>
<li><strong>imported</strong>, value can not be set</li>
<li><strong>exported</strong>, value can not be set</li>
<li><strong>metadata.deleted</strong>, value must be set.</li>
</ul><p>Object's record(s) can not be deleted from database when delete method is invoked. Instead , object's metadata delete property should be explicitly updated with correct delete value. For performance reason this value should be an integer type. This metadata property should be also used by midgard core as mandatory Midgard Query Builder's constraint added internally by Query Builder implementation.</p>

<h3>Undelete</h3>

<ul><li><strong>created</strong>, value can not be set</li>
<li><strong>revised</strong>, current datetime value must be set</li>
<li><strong>imported</strong>, value can not be set</li>
<li><strong>exported</strong>, value can not be set</li>
<li><strong>metadata.deleted</strong>, value must be (re)set to initial default state.</li>
</ul><h3>Purge</h3>

<p>When this method is invoked, midgard core should delete object's record(s) from database and should update repligard table. Following values should be set for corresponding record in repligard table:</p>

<ul><li>object's class name</li>
<li>object's guid</li>
<li>purge action should be set to TRUE value</li>
</ul><h2>Repligard table</h2>

<p>Repligard table must containt only object's guid and typename ( classname ) for which new object instance with particular guid can be created. Additionaly repligard table should contain information if object's record(s) was purged.</p>

<h3>Query deleted objects</h3>

<p>Midgard core should implement functionality which allows to query only  deleted objects. This functionality could be implemented with new  Midgard Query Builder method or with new Midgard type.</p>

<h2>Staging/live in MidCOM</h2>

<blockquote>
  <p>Missing topics: Data model, general service architecture,
  including the layers of the communication infrastucture.</p>
  
  <p>Torben</p>
</blockquote>

<p>Since replication interfaces are exposed to PHP level, the staging/live process can be handled in MidCOM space. This should make the simple replication scenarios like an article that is approved much faster, the system more fault tolerant due to the queue system, and finally the replication logic easier to tweak because it is entirely in PHP level.</p>

<p>There will be a midcom.helper.staginglive purecode component to handle the replication process.</p>

<blockquote>
  <p>This will have to be <code>midcom.services.replication</code>.</p>
  
  <p>Torben</p>
</blockquote>

<h3>Invoking replication</h3>

<p>The replication component will register UPDATE and DELETE watchers for <code>midcom_core_dbobject</code>. Since approvals are stored into Midgard metadata fields using <code>update()</code> method approval should be carried to this watcher.</p>

<blockquote>
  <p>Note, that you cannot register watches for 
  <code>midcom_core_dbobject</code>, as this class is not a base class
  for other DBA classes. It is more of a "mix-in" due to
  Limitations of the PHP OOP API. The correct definition 
  would be adding watches to all defined DBA classes by
  not limiting the watch to any class.</p>
  
  <p>Torben</p>
</blockquote>

<p>To catch objects updated or deleted outside MidCOM DBA the system will also provide a <code>cron</code> entry that will query through all MgdSchema types to see if there is something to replicate. This can be run relatively seldom, for example once per day.</p>

<blockquote>
  <p>This is not very precise. The criteria after which objects
  are marked for replication should be outlined.</p>
  
  <p>Torben</p>
</blockquote>

<h3>Export process</h3>

<p>The export watchers will execute an exporting method in the midcom.helper.staginglive interface class and provide it with the affected object as argument.</p>

<p>If approvals or scheduling are being used, the system will first check if the object itself is set to be visible. Otherwise visibility will be assumed.</p>

<p>If the object is visible, the same check will be done for its parent.</p>

<blockquote>
  <p>Note, that this can prohibit replication under certain
  circumstances: Assume that a topic and one of its articles
  are both changed. The article gets approved, the topic not.
  Replication of the article will then be delayed.</p>
  
  <p>Note as well, that there is another case, where you 
  actually need to be careful if you change the behavoir to
  cover the above special case: If the topic in question was
  newly created, it won't be available on the target server.</p>
  
  <p>Normally, the latter should be no problem if and only if
  only GUIDs are used for linking and, as such, ID mappings
  are not required. The legacy data structures do not yet
  do this. I very strongly suggest that this will be changed
  prior implementing this, even if this means that existing
  code (mainly QB lookups) have to be adapted to it.</p>
  
  <p>Torben</p>
</blockquote>

<p>If the parent is visible, the object will be marked for exporting. If the parent is not visible export is aborted and UI message "Object not exported because parent is not visible" sent to the user.</p>

<blockquote>
  <p>What happens later, when the parent gets cleared? Is the
  delayed object queued somewhere? This needs much more 
  detail.</p>
  
  <p>Torben</p>
</blockquote>

<p>Then the method will query the object's children and call the same method for them.</p>

<blockquote>
  <p>I assume that this is the fix for the above problem I 
  mentioned. The problem I see here is that you will often
  get large trees here, especially if you are at the top
  of the tree. Also you will have difficulties as you have
  to know all types which potentially have the object in
  question as a parent:</p>
  
  <p>Especially topics are tricky here, as several of the 
  components I wrote lately assign their data to topics,
  without actually using <code>midgard_article</code>. But groups
  or persons can easily reach a similar spread.</p>
  
  <p>Torben</p>
</blockquote>

<pre><code>TODO: Pseudocode for the exporting decision
</code></pre>

<blockquote>
  <p>I'd like to see this before +1'ing anything.</p>
  
  <p>Torben</p>
</blockquote>

<p>Finally the exported objects will be stored into replication queue and an <code>at</code> entry registered for running the replication next minute.</p>

<blockquote>
  <p>Is this wise? Or would it be more appropriate to have a 
  cron job doing it every X minutes to optimize / batch 
  the changes.</p>
  
  <p>Torben</p>
</blockquote>

<p>UI message "3 articles and 1 topic exported for replication" is sent to the user.</p>

<h3>Subscribers and replication queue</h3>

<p>Subscribers (Midgard sites to replicate to) are stored in the database. The subscriber entry contains the replication method used for that subscriber and address and authentication information required for the method.</p>

<p>When objects are exported, the export XML is stored into a <code>midcom_helper_staginglive_queue_entry</code> object for each subscriber.</p>

<blockquote>
  <p>Data duplication, the data model should be revised here.</p>
  
  <p>Torben</p>
</blockquote>

<p>Replication is launched by the <code>at</code> entry registered at export phase. The replication process goes through all subscribers, and tries to send the items of their queue to them using the defined method.</p>

<p>There can be multiple replication methods supported by the system. At first we will only implement a simple HTTP PUT (or POST) method sent to a MidCOM <code>exec</code> handler of the midcom.helper.staginglive component, authenticated using HTTP Basic Auth. Other methods could include Jabber/XMPP, DBE or even email.</p>

<blockquote>
  <p>Wouldn't some XML-RPC or other standardized remoting 
  mechanism be more appropriate then some proprietary
  solution?</p>
  
  <p>Torben</p>
</blockquote>

<p>Email could provide a high security replication solution where the exporting end would GPG encrypt and sign the email, then send it out as an email. The importing end would then read the email from the server, check its signature, decrypt it and import. This way the importing end could even be a mostly offline computer that would only connect to internet to receive the emails once per day (this is how FSF Europe's member registry works to protect privacy).</p>

<blockquote>
  <p>Consider using regular X.509 based encryption / signing
  instead of PGP. More standardized (almost as easy to use)
  and integrated into existing PKI infrastructures. This 
  should be available completly independant of the actual
  transport layer used, btw.</p>
  
  <p>Torben</p>
</blockquote>

<p>If the replication is successful, the queue entry is deleted. If not, the replication will be attempted again every hour using a <code>cron</code> entry.</p>

<blockquote>
  <p>Provide some fallback mechanism, similar to the SMTP 
  system. There should be a fixed number of retries, maybe
  with increased waiting periods after certain escalation
  levels.</p>
  
  <p>Also, it is recommended to flag entries as failed after
  a certain amount of retries have been reached.</p>
  
  <p>Failed connections to a subscriber should escalate as well,
  disabling the subscriber until the situation is resolved.
  Otherwise, there would be an easy DOS scenario when too 
  many replications pile up for a given subscriber.</p>
  
  <p>Torben</p>
</blockquote>

<h4>Subscription types</h4>

<p>In the initial implementation every object is replicated to every subscriber. At a later stage we can implement different subscription type handlers that will enable limiting the subscription to particular MgdSchema types, object trees or even particular query constraints.</p>

<p>Examples of subscription types would be "content in tree", "my tasks" or "all forum posts".</p>

<blockquote>
  <p>This is rather vague, especially since the neccessary 
  basic infrastructure to provide something like this is
  never mentioned above. Goes into the chapter "missing
  service architecture".</p>
  
  <p>Torben</p>
</blockquote>

<h3>Import process</h3>

<p>Import process will simply call the Midgard <code>import</code> method for each object in the imported XML file.</p>

<blockquote>
  <p>No sanity checks, nothing? I think there has to be a high
  level of bulletproofing when letting such replications in.</p>
  
  <p>Torben</p>
</blockquote>
]]></summary>
    </entry>
</feed>

