<?xml version="1.0" encoding="iso-8859-15"?>
<!-- $Id$ -->
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
	<!ENTITY firstname "Pierre">
	<!ENTITY surname   "Pronchery">
	<!ENTITY email     "khorben@defora.org">
	<!ENTITY package   "DaPortal">
	<!ENTITY name      "daportal">
	<!ENTITY title     "DaPortal Programmer Manual">
	<!ENTITY purpose   "DaPortal internals">
]>
<article>
	<info>
		<title>&package; internals</title>
		<date>@DATE@</date>
		<productname>&package;</productname>
		<authorgroup>
			<author>
				<personname><firstname>&firstname;</firstname><surname>&surname;</surname></personname>
				<contrib>Code and documentation.</contrib>
				<address><email>&email;</email></address>
			</author>
		</authorgroup>
		<copyright>
			<year>2012</year>
			<year>2013</year>
			<year>2014</year>
			<year>2015</year>
			<holder>&firstname; &surname; &lt;&email;&gt;</holder>
		</copyright>
		<legalnotice>
			<para>This guide was written for the DeforaOS project (and may be used by
				others).</para>
			<para>Permission is granted to copy, distribute and/or modify this document
				under the terms of the GNU General Public License, Version 3 as published by
				the Free Software Foundation.</para>
		</legalnotice>
		<publisher><publishername>The DeforaOS Project</publishername></publisher>
	</info>
	<warning>
		<title>Warning: work in progress</title>
		<para>These notes are based on a development version of &package; 2.</para>
	</warning>
	<section>
		<title>Introduction notes</title>
		<section>
			<title>Where to find &package;</title>
			<para>First, make sure that you have downloaded the latest stable version of
				&package; 2. It can be found there: <ulink
					url="http://www.defora.org/os/project/download/12/DaPortal">http://www.defora.org/os/project/download/12/DaPortal</ulink>.
				This guide will assume the resulting archive to be called
				<filename>DaPortal.tar.gz</filename>.</para>
			<para>Alternatively, you may choose to track the development of &package;
				2, or any given branch from the Source Code Management system. Some
				instructions to do so can be found here: <ulink
					url="http://www.defora.org/os/project/download/12/DaPortal">http://www.defora.org/os/project/download/12/DaPortal</ulink>.</para>
		</section>
		<section>
			<title>Relevant documentation</title>
			<para>In this document, the reader is expected to be familiar with the
				installation of &package;. This process is documented in <ulink
					url="install.html">Installing DaPortal</ulink>, which contains important
				information about the organization of files and directories relevant to
				&package;.</para>
		</section>
	</section>
	<section>
		<title>Entry point</title>
		<para>&package; has a single entry-point for all of its applications, found
			in <filename>src/daportal.php</filename>. Its contents are simple enough to
			be reproduced here:</para>
		<programlisting><![CDATA[<?php
require_once('./system/autoload.php');
global $config;
$config = new Config();
$config->load('../daportal.conf');

if(($engine = Engine::attachDefault()) !== FALSE)
{
	$request = $engine->getRequest();
	$response = $engine->process($request);
	$engine->render($response);
}
unset($engine);

?>]]></programlisting>
		<para>First, the code reads configuration data from the <ulink
				url="daportal.conf.html"><filename>../daportal.conf</filename></ulink> file.
			This file is organized as an ini-style configuration file, with series of
			variables (one per line) found in separate sections. This file is currently
			used for most of the configureable aspects of &package;.</para>
		<para>Next, the <filename>engine.php</filename> file is loaded from the
			<filename>system</filename> sub-directory. This directory contains generic,
			library code that can freely be used by the different modules. After
			including this file:<orderedlist>
				<listitem><para>The relevant implementation of the
						<classname>Engine</classname> class is loaded,</para></listitem>
				<listitem><para>The user's request is determined and
						obtained,</para></listitem>
				<listitem><para>The output (or <quote>page</quote>) is rendered and
						delivered to the user.</para></listitem>
		</orderedlist></para>
		<para>Finally, the engine loaded is explicitely free'd; this was found to be
			necessary in some cases (like with the <classname>GtkEngine</classname>) as
			otherwise, some functionalities of PHP no longer work as expected while
			executing the engine's destructor routines.</para>
		<para>In the rest of this documentation, source files will be mentioned
			relatively to the <filename>src</filename> directory.</para>
	</section>
	<section>
		<title>Engine selection</title>
		<para>The actual processing engine for &package; is determined at run-time, or
			possibly enforced in the <filename>daportal.conf</filename> configuration
			file (through the <varname>backend</varname> variable in the
			<varname>[engine]</varname> section).</para>
		<para>When auto-detecting the engine, every PHP file found in the
			<filename>engines</filename> directory is loaded in sequence. The file is
			expected to provide a predictable class name, such as
			<classname>FileNameEngine</classname> for
			<filename>filename.php</filename>. It should implement the abstract
			<classname>Engine</classname> class.</para>
		<para>Two methods are used when detecting the adequate engine:<itemizedlist>
				<listitem><para><function>match()</function>: returns an integer value,
						representing a score at the relevance of the engine in the context
						detected (typically between 0 and 100)</para></listitem>
				<listitem><para><function>attach()</function>: returns a boolean value,
						<returnvalue>TRUE</returnvalue> in case of success or
						<returnvalue>FALSE</returnvalue> otherwise.</para></listitem>
		</itemizedlist></para>
		<para>This auto-detection methodology is found in multiple sub-systems of
			&package; (file formats, templates...).</para>
	</section>
	<section>
		<title>Processing requests</title>
		<section>
			<title>About requests</title>
			<para>Requests represent messages, typically sent from the end user and
				directed at a given part of the &package; installation. Requests can be
				created directly within the code, or obtained from user input (typically
				interpreted by the <classname>Engine</classname> instance).</para>
			<para>The following parameters define a request:<itemizedlist>
					<listitem><para><varname>module</varname>: the module to be selected to
							handle this request (required)</para></listitem>
					<listitem><para><varname>action</varname>: the action to be triggered
							within the given module (optional)</para></listitem>
					<listitem><para><varname>ID</varname> and <varname>title</varname>: both
							can be supplied independently, and their actual signification is up to
							the module (and action) selected;</para></listitem>
					<listitem><para>optionally, an arbitrary number of additional parameters,
							defined through a name and value.</para></listitem>
			</itemizedlist></para>
			<para>Requests implement the <classname>Request</classname> class defined in
				<filename>system/request.php</filename>. They are always processed through a
				specific <classname>Engine</classname> instance.</para>
		</section>
		<section>
			<title>Database</title>
			<para>The storage database is accessed through the processing engine, with
				the actual storage backend being loaded automatically when it is required.
				This typically happens when invoking the <function>getDatabase()</function>
				method of the <classname>Engine</classname> instance.</para>
			<para>Much like the main engine, the backend is selected as configured in the
				<varname>[database]</varname> section of the
				<filename>daportal.conf</filename> configuration file (or can be
				automatically detected in some cases). The different classes implementing
				the <classname>Database</classname> abstract class (described in
				<filename>system/database.php</filename>) are loaded from individual files,
				expected in the <filename>database</filename> directory.</para>
			<para>A limited implementation of the <classname>Database</classname> class,
				called <classname>DatabaseDummy</classname>, is returned by the engine when
				it was unable to attach a functional <classname>Database</classname>
				instance. It will simply fail to obtain any data.</para>
		</section>
		<section>
			<title>Authentication</title>
			<para>User authentication within &package; is also delegated to a distinct
				backend, as its proper operation typically depends on the actual
				<classname>Engine</classname> instance selected. These backends are expected
				in the <filename>auth</filename> sub-directory, and should implement the
				<classname>Auth</classname> class from <filename>system/auth.php</filename>.
				Auto-detection of the authentication backend to be loaded can be
				circumvented through the <varname>[auth]</varname> section of the
				<filename>daportal.conf</filename> configuration file.</para>
			<para>The credentials with &package; include the following
				information, much like found on a typical UNIX system:<itemizedlist>
					<listitem><para>a user ID: either the default value, 0 (meaning anonymous,
							least privileges) or a positive integer (actual users, with equal
							privileges by default)</para></listitem>
					<listitem><para>a username, which must be unique through the
							system;</para></listitem>
					<listitem><para>a group ID: defaulting to 0 (meaning nogroup), they can be
							used by modules to assign differing privileges, or otherwise
							distinguishing groups of users;</para></listitem>
					<listitem><para>a group name: the name of the default group of the
							user;</para></listitem>
					<listitem><para>an additional list of groups that the user may be part
							of;</para></listitem>
					<listitem><para>an administrative flag: it grants complete privileges to
							the current user, with the actual signification depending on the current
							module.</para></listitem>
			</itemizedlist></para>
		</section>
		<section>
			<title>Idempotence</title>
			<para>The concept of idempotence is also explicitly implemented (and
				hopefully enforced) throughout the code. Its actual meaning in the context
				of &package; is to prevent actions to be performed without the explicit
				consent of the user; this is the default for newly-created requests. It is
				up to each individual module to determine whether the current operation is
				<quote>safe</quote> in this regard or not.</para>
			<para>The main rationale behind this concept is to prevent CSRF attacks with
				session-based, disconnected authentication mechanisms (like when using
				cookies over HTTP). It is also worth mentioning that some requests may be
				set to expire over time for increased security.</para>
		</section>
	</section>
	<section>
		<title>Within modules</title>
		<section>
			<title>About modules</title>
			<para>Modules are the most essential part of the &package; engine: they
				implement the visible functionality to the end user, and provide the
				operation logic. Each module has a distinct folder inside the
				<filename>modules</filename> directory, where it should at least provide a
				<filename>module.php</filename> file; this file is automatically loaded by
				the <classname>Engine</classname> instance when required. It should
				implement the <classname>Module</classname> class, as defined in
				<filename>system/module.php</filename>.</para>
			<para>A few modules are provided by a stock installation of
				&package;, among which:<itemizedlist>
					<listitem><para><quote>user</quote>: assists with user registration,
							authentication, password resets and profile management;</para></listitem>
					<listitem><para><quote>admin</quote>: provides a user interface dedicated
							to administration duties;</para></listitem>
					<listitem><para><quote>article</quote>, <quote>news</quote>,
							<quote>wiki</quote>...: extend the abstract
							<classname>ContentModule</classname> in
							<filename>modules/content/module.php</filename>, declining some
							content-management functionality in differing contexts;</para></listitem>
					<listitem><para><quote>search</quote>: provides a generic way to search
							through the site's contents.</para></listitem>
				</itemizedlist></para>
				<para>In turn, these modules can be extended and altered
					individually.</para>
		</section>
		<section>
			<title>Calls</title>
			<para>The modules react to requests through calls, more precisely the
				<function>call()</function> public method of the
				<classname>Module</classname> class. The relevant
				<classname>Engine</classname> instance along with the request are passed to
				this method, which is then responsible for handling the request, given the
				resources provided by the <classname>Engine</classname>.</para>
			<para>Calls are divided into two categories: <emphasis>internal</emphasis>
				and <emphasis>public</emphasis>.</para>
			<para>Public calls are issued by users directly, and required to return
				instances of the <classname>Response</classname> object. Content is
				typically formatted and delivered back to the user by building pages through
				<classname>PageResponse</classname> objects, as described below in <xref
					linkend="pages"/>.</para>
			<para>Internal calls on the other hand are meant for inter-module
				communication, and can be used as an internal API. There are no restrictions
				on return values (or their type).</para>
		</section>
		<section>
			<title>Helpers</title>
			<para>Common functionality can be provided on demand to the modules,
				typically through the inclusion of specific files in the
				<filename>system</filename> directory. Some helpers are provided by a stock
				installation of &package;, among which:<itemizedlist>
					<listitem><para><quote>content</quote>: provides some functionality around
							the handling of content (creation, modification,
							deletion...)</para></listitem>
					<listitem><para><quote>locale</quote>: assists in the translation of the
							user interface (typically using the gettext PHP
							extension)</para></listitem>
					<listitem><para><quote>mail</quote>: helps sending
							e-mail;</para></listitem>
					<listitem><para><quote>user</quote>: to lookup and manage user
							information.</para></listitem>
			</itemizedlist></para>
			<para>Modules themselves may be organized so as to allow easier integration
				and alteration of functionality, particularly when inheriting them. This is
				typically performed through the introduction of helper functions, specific
				to the given module (which are therefore declared as protected). Their
				implementation details are specific to each and every module, although
				consistency is hopefully preserved among most.</para>
		</section>
		<section>
			<title>Internal requests</title>
			<para>Cooperation between modules is sometimes helpful, or even necessary:
				this should however be performed without exposing additional, undesired
				functionality to the end user. A special flag can therefore be applied to
				requests when sending them through an engine for processing: they are then
				considered internal, and can be adequately treated as such by the target
				module.</para>
		</section>
	</section>
	<section>
		<title>Output and rendering</title>
		<section id="pages">
			<title>Building pages</title>
			<para>The content generated through processing the requests is expected to be
				composed of a series of chained elements, called
				<classname>PageElement</classname>, each of which can also embed properties
				or other instances of <classname>PageElement</classname>. For clarity, an
				additional class, simply called <classname>Page</classname>, is also
				available and meant to represent a top-level element.</para>
			<para>Most importantly, each element has a given type, representing an
				expected layout or behavior when rendered. These types are largely inspired
				by graphical toolkits, such as Gtk+, and typically represent label widgets,
				file choosers, toolbars, menus, and so on.</para>
			<para>The <classname>PageElement</classname> and <classname>Page</classname>
				classes are both defined in the <filename>system/page.php</filename>
				file.</para>
		</section>
		<section>
			<title>Applying templates</title>
			<para>Single requests are expected to only output the data that is directly
				relevant to them; the final content delivered to the user may however
				require more information, additional cosmetics, or even some reformatting or
				editing. This is exactly the task of templates; again, they are found in the
				<filename>templates</filename> directory, and should implement the
				<classname>Template</classname> class, as defined in
				<filename>system/template.php</filename>.</para>
			<para>The template to choose can be determined by the engine at run-time, or
				can also be enforced within the <filename>daportal.conf</filename>
				configuration file, through the <varname>template</varname> section.</para>
		</section>
		<section>
			<title>File formats</title>
			<para>Rendering of the current page is the last step performed by the engine
				(if at all necessary) before delivering its contents to the end user.
				Indeed, some module calls may return data of any nature, like resources
				(such as file or stream descriptors). The <classname>Engine</classname>
				instance is then responsible for their proper handling.</para>
			<para>However, in the case of pages (or page elements) the contents may be
				formatted, transformed or otherwise converted in differing formats, as
				available through the <classname>Engine</classname> instance. This instance
				may use &package;'s own set of classes and routines to perform this, as
				provided by the <classname>Format</classname> and
				<classname>FormatElements</classname> classes in
				<filename>system/format.php</filename>, and then implemented in the
				<filename>formats</filename> directory.</para>
			<para>As usual within &package;, the choice of formatting backends and their
				respective preferences can be influenced through the
				<filename>daportal.conf</filename> configuration file, through the
				<varname>[format]</varname> set of sections. The difference here, is that
				backends can be specified per MIME type, as set through the
				<classname>Engine</classname> instance. This is illustrated here:</para>
			<programlisting><![CDATA[[format]
#this defines the default backend if nothing else matched
#backend=html
#backend=html5
backend=plain

[format::text/html]
#this defines the default backend for content explicitly set to be HTML
#backend=html
backend=html5

[format::html]
#preferences for the html backend
favicon=/favicon.png
]]></programlisting>
		<para>Again, the final decision on which rendering backend to choose can be
			enforced by the <classname>Engine</classname> instance.</para>
		</section>
	</section>
</article>
<!-- vim: set noet ts=1 sw=1 sts=1 tw=80: -->
