<chapter id="modules">
  <title>Modules</title>

  <section id="modules.introduction">
    <title>Introduction</title>
    <para>
      This section describes Phorum's module system. It is targeted at
      developers who want to do customization and extend the functionality
      of Phorum. Modules are the preferred way to archieve this.
    </para>
    <para>
      For much of this document, we will be talking about an example module
      "foo". Of course you will not name your module "foo", but something much
      more appropriate. If you're not familiar with the terms "foo" and "bar",
      you can visit <ulink url="http://en.wikipedia.org/wiki/Metasyntactic_variable">Wikipedia</ulink> to see why we chose them.

    </para>
    <para>
      <remark>TODO: Link to section once it's ready</remark>
      Be sure to read at least the CAUTIONS AND SECURITY ISSUES section,
      before making your own modules.
    </para>
  </section>

  <section id="modules.terminology">
    <title>Terminology</title>

    <section id="modules.modules">
      <title>Modules</title>
      <para>
        Modules are self contained pieces of software, that can be added to
        Phorum to change or extend its functionality. Modules can do this
        without having to change anything in the standard Phorum distribution
        files or database structure.
      </para>
      <para>
        The big advantage of modules this is that upgrading the Phorum code
        is easy (no file changes to redo after upgrading) and that modules
        can be easily uninstalled when needed.
      </para>
      <para>
        Installing a module means: drop the code in the Phorum mods directory,
        go to the admin "Modules" page, enable the module and enjoy!
        One additional thing that might be needed, is editing one or
        more template files to display data that is generated by the module.
      </para>
    </section>

    <section id="modules.hacks">
      <title>Hacks</title>
      <para>
        The moment it is neccessary to make changes to the standard Phorum
        distribution files or database structure to implement some kind of
        functionality, we are talking about a hack (even if the changes
        that have to be made are accompanied by a drop in module).
      </para>
      <para>
        Although there is nothing wrong with writing hacks, the Phorum team
        wants to urge you to try if you can write a module before resorting
        to a hack. Especially if you are going to publish your changes to
        the public. Modules are the preferred way of modifying Phorum
        functionality, because that will make both upgrading your distribution
        and having your modification adopted by others easier.
      </para>
    </section>

    <section id="modules.hooks">
      <title>Hooks</title>
      <para>
        The Phorum core and Phorum modules are interconnected through hooks.
        Hooks are points in the application where Phorum stops and runs
        its data through the modules that are configured to handle the
        hook. The modules can act upon and change this data.
      </para>
      <para>
        The following image visualizes what happens when Phorum reaches
        a hook point in the application, for which two modules ("foo" and
        "bar") have been configured.
      <literallayout><literal><![CDATA[
     Phorum
   Application
       (1)                                (1) Phorum is running.
        |                                 (2) Phorum reaches the
        |                                     hook named "some_hook".
        v           Phorum                (3) Phorum sends data to
    some_hook >----- data ------+             the module system.
       (2)            (3)       |         (4) The module "foo" is run.
                                v         (5) The module "bar" is run.
                       (4) module "foo"   (6) The Phorum data (which
                                |             might be modified by the
                                v             modules) is sent back
                       (5) module "bar"       to Phorum.
                                |         (7) Phorum continues running
     Phorum        Modified     |             with the modified data.
   Application <---- data ------+
       (7)            (6)
        |
        |
        v
]]></literal></literallayout>
      </para>
    </section>

    <section id="modules.hookfunctions">
      <title>Hook functions</title>
      <para>
        A module contains PHP functions that act as hook functions.
        Hook functions will receive some data from Phorum
        through their arguments and have to return the (possibly modified)
        data, which will then go either back to Phorum or to the input
        of another module which also handles the same hook
        (see <xref linkend="modules.hooks"/>).
        Based on this, the most basic (and useless) hook function you could
        write would look somewhat like this (see XXX for an explanation
        of the naming scheme that was used for the function):
        <programlisting><![CDATA[
function phorum_mod_foo_some_hook ($data) {
  return $data;
}]]></programlisting>
      </para>
      <para>
        The exact nature of the data that is sent to the hook functions
        depends solely on the hook that is run. See <xref linkend="hooks"/>
        for a description of all supported hooks, including a specification
        of the type of data that is sent.
      </para>
    </section>

  </section>

  <section id="modules.writingyourown">
    <title>Writing your own modules</title>

    <section id="module.writingyourownintro">
      <title>Introduction</title>
      This section will explain to you how to roll your own Phorum modules.
      We will start out by explaining some of the
      <xref linkend="modules.terminology" xrefstyle="template:terminology"/>
      that relates to modules. After that, we will explain a very important
      part modules: the <xref linkend="modules.moduleinfo"
      xrefstyle="template:module information"/>. This contains information
      for both Phorum (what hooks to run in what order, version dependancies)
      and module users (title, description and other interesting facts).
      From there on we will walk you through all the possibilities that
      modules have.
    </section>

    <section id="modules.moduleinfo">
      <title>Module information</title>
      <para>
        Module information is the glue between your module and Phorum.
        It provides information to Phorum about your module.
        Before we explain how to add this module information to your
        module, we will first explain what data can be put in there
        and how that data is formatted.
      </para>
      <para>
        Module information is formatted using lines of plain text. Each line
        contains a piece of information about the module. The general format
        for each of the lines in the module information is:
        <programlisting><![CDATA[ <key>: <value> ]]></programlisting>
        Empty lines are allowed between these key/value pairs.
        Below, you can find a list of the keys and values that can be
        used in the module information.
        <table id="modules.moduleinfokeys">
          <title>Keys and values in module information</title>
          <tgroup cols="2">
          <thead>
            <row>
              <entry>&lt;key&gt;</entry>
              <entry>&lt;value&gt;</entry>
            </row>
          </thead>
          <tbody>

            <row>
              <entry>
                <emphasis role="bold">title</emphasis>
              </entry>
              <entry>
                <para>
                  This is the title for the module that is displayed in the
                  "Modules" page of the admin interface.
                </para>
                <para>
                  Example:<sbr/>
                  <literal>title: Foo</literal>
                </para>
              </entry>
            </row>

            <row>
              <entry>
                <emphasis role="bold">desc</emphasis>
              </entry>
              <entry>
                <para>
                  This is the description that is displayed along with the
                  title in the admin interface, to give a little more
                  information about the module. Using HTML in the
                  &lt;value&gt; part is allowed.
                </para>
                <para>
                  Example:<sbr/>
                  <literal>desc: This is a very cool module to do stuff.</literal>
                </para>
              </entry>
            </row>

            <row>
              <entry>
                <emphasis role="bold">hook</emphasis>
              </entry>
              <entry>
                <para>
                  This describes which
                  <xref linkend="modules.hookfunctions"
                        xrefstyle="template:hook functions"/>
                  are called for which Phorum hooks. The value consists of
                  two fields, separated by a pipe "|" symbol. The first
                  field contains the name of the hook that this module is
                  hooking into. The second field contains the name of the
                  hook function that will be called for the hook.
                </para>
                <para>
                  Example:<sbr/>
                  <literal>hook: some_hook|phorum_mod_foo_some_hook</literal>
                </para>
              </entry>
            </row>

            <row>
              <entry>
                <emphasis role="bold">priority</emphasis>
              </entry>
              <entry>
                <para>
                  This can be used for changing priorities and dependancies
                  for modules and hooks. Possible values are (in order in
                  which they are processed):
                  <itemizedlist>
                    <listitem><literal>
                      run module before|after *
                    </literal></listitem>
                    <listitem><literal>
                      run module before|after &lt;other module name&gt;
                    </literal></listitem>
                    <listitem><literal>
                      run hook &lt;hook name&gt; before|after *
                    </literal></listitem>
                    <listitem><literal>
                      run hook &lt;hook name&gt; before|after &lt;other module name&gt;
                    </literal></listitem>
                  </itemizedlist>
                </para>
                <para>
                  Examples:<sbr/>

                  <para>
                    Run this module before all other modules:<sbr/>
                    <literal>
                      priority: run module before *
                    </literal>
                  </para>

                  <para>
                    Run this module before the bbcode module.<sbr/>
                    <literal>
                      priority: run module before bbcode
                    </literal>
                  </para>

                  <para>
                    Run the "format" hook for this module before the
                    "format" hook of the smileys module.<sbr/>
                    <literal>
                      priority: run hook format before smileys
                    </literal>
                  </para>

                  <para>
                    Run the "after_header" hook for this module after all
                    other "after_header" hooks.<sbr/>
                    <literal>
                      priority: run hook after_header after *
                    </literal>
                  </para>
                </para>

                <para>
                  The main difference between "run module" and "run hook"
                  is that "run module" will affect the priority for each
                  hook of the module and that "run hook" is used to
                  specifically change the priority of a single hook.
                  So to run all hooks for a module as early as possible,
                  but run the "foo" hook as late as possible and the
                  "bar" hook before the smileys mod, one could use the
                  following priority lines:
                </para>
                <para>
                  <literal>
                  priority: run module before *<sbr/>
                  priority: run hook foo after *<sbr/>
                  priority: run hook bar before smileys
                  </literal>
                </para>
              </entry>
            </row>

            <row>
              <entry>
                <emphasis role="bold">require_version</emphasis>
              </entry>
              <entry>
                <para>
                  This describes which phorum version is required to use
                  this module. Modules with a requirement above the current
                  phorum version are automatically disabled when going to
                  the modules page. This feature was added in Phorum 5.2.
                </para>
                <para>
                  Example:<sbr/>
                  <literal>require_version: 5.2.2</literal>
                </para>
              </entry>
            </row>

            <row>
              <entry>
                <emphasis role="bold">
                  author<sbr/>
                  url<sbr/>
                  version<sbr/>
                  release_date
                </emphasis>
              </entry>
              <entry>
                <para>
                  These fields are all informational. The information
                  from these fields will be shown on the Modules admin
                  page. You are allowed to omit these fields from the
                  module information, but we advice you to fill them to
                  provide as much useful info to the users of your module.
                </para>
                <para>
                  The fields are free form. The "url" field should contain
                  a URL to a page where more information about the module
                  can be found. This can for example be a dedicated page
                  about your module or a discussion page in the phorum.org
                  support forums.
                </para>
                <para>
                  Example:<sbr/>
                  <literal>
                    author: John Doe, Phorum hacker<sbr/>
                    url: http://example.com/phorum/mod_foo/<sbr/>
                    version: 0.9.1-alpha<sbr/>
                    release_date: May 17th, 2007
                  </literal>
                </para>
              </entry>
            </row>

            <row>
              <entry>
                <emphasis role="bold">category</emphasis>
              </entry>
              <entry>
                <para>
                  The category field is used for categorizing the module.
                  You can place your module inside one or more categories by
                  adding one or more category lines to the module information.
                  The category is used for automatically generating a
                  categorized list of available modules on the phorum.org
                  web site.
                </para>
                <para>
                  For consistency and for preventing wild growth of
                  categories, we use a fixed set of categories from which
                  you can choose. Please select your category / categories
                  carefully and do not put your module in too many
                  categories. Available categories to choose from are:
                  <itemizedlist>
                    <listitem>
                      <emphasis role="bold">admin</emphasis><sbr/>
                      Modules that are useful for performing administrative
                      tasks and for handling advanced Phorum configuration.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">bbcode</emphasis><sbr/>
                      Modules that implement extra BBcode tags.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">embed_content</emphasis><sbr/>
                      Modules for embedding content (e.g. images, audio,
                      video, flash, etc.) in message bodies. These
                      modules implement viewers that are shown inside the
                      message bodies when reading the message and which take
                      away the need to launch some external viewer to open
                      attachments and/or linked files.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">phorum3conversion</emphasis><sbr/>
                      Modules that can help sites to convert from the
                      old Phorum 3 system to Phorum 5.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">email</emphasis><sbr/>
                      Modules that extend or enhance the email system.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">integration</emphasis><sbr/>
                      Modules that can be used for integrating Phorum with
                      other systems.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">user_management</emphasis><sbr/>
                      These modules deal with user registration, logging in
                      and out, login status and user management tasks.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">moderator</emphasis><sbr/>
                      Modules that extend or enhance the moderation system.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">posting</emphasis><sbr/>
                      Modules that extend or enhance posting and/or
                      editing messages.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">search</emphasis><sbr/>
                      Modules that provide search features
                      or that replace the full message search backend.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">seo</emphasis><sbr/>
                      Modules that apply search engine optimization
                      measures to Phorum.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">spam</emphasis><sbr/>
                      Modules that help protecting Phorum against spam.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">user_features</emphasis><sbr/>
                      Modules that give the users new options and enhance
                      their experience.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">viewlayout</emphasis><sbr/>
                      Modules that add information to or alter the view /
                      layout of Phorum pages.
                    </listitem>
                    <listitem>
                      <emphasis role="bold">uncategorized</emphasis><sbr/>
                      Modules that do not have a category assigned. This one
                      is mainly mentioned for completeness. In the online
                      module list, this category will be assigned to modules
                      that don't have a category set in their info.txt.
                    </listitem>
                  </itemizedlist>
                </para>
                <para>
                  Example:<sbr/>
                  <literal>category: user_features</literal><sbr/>
                  <literal>category: posting</literal>
                </para>
              </entry>
            </row>

          </tbody>
          </tgroup>
        </table>
      </para>

      <para>
        It is allowed to use multiple hook lines in your module information,
        so your module can act upon multiple hooks. When doing this, it
        is also allowed to use the same hook function for handling different
        hooks in your module (asuming the hooks are compatible).
      </para>
      <para>
        Here is an example of what the module information for our example
        module "foo" might look like:
        <example id="example.moduleinfo">
          <title>Module information</title><programlisting><![CDATA[
title: Foo
desc: This is the Foo module for Phorum. Nothing exciting...
version: 1.0.2
release_date: Jan 1st, 2008
url: http://www.phorum.org
author: John Doe <johndoe@example.com>
require_version: 5.2.2
category: user_features

hook: some_hook|phorum_mod_foo_some_hook
hook: some_other_hook|phorum_mod_foo_some_other_hook
hook: yet_another_hook|phorum_mod_foo_some_other_hook

priority: run some_hook before some_other_module]]></programlisting>
        </example>

        What this module info does, is telling Phorum that when it gets to
        "some_other_hook", it will have to call the function
        <literal>phorum_mod_foo_some_other_hook()</literal> in your module.
        It also tells that for "yet_another_hook" the same function has to
        be called. It will also take care that the hook "some_hook" is run
        before the same hook in the module "some_other_module".
      </para>

    </section> <!-- end of module info -->

    <section id="modules.structure">
      <title>Module file structure</title>

        <section id="modules.structureintro">
          <title>Introduction</title>
          <para>
            This section describes the file structure of Phorum modules.
            This structure contains things like the
            <xref linkend="modules.moduleinfo"
            xrefstyle="template:module information"/>,
            <xref linkend="modules.hookfunctions"
            xrefstyle="template:hook functions"/> and possibly additional
            stuff like templates, translations, modules settings, images,
            scripts, classes, etc.
          </para>
          <para>
            If your module only needs module information and hook functions
            to function, it is possible to use the
            <xref linkend="modules.singlefile"
            xrefstyle="template:single file structure"/>. If you need more
            than that, then use the <xref linkend="modules.multifile"
            xrefstyle="template:multiple file structure"/>.
          </para>
        </section>

        <section id="modules.singlefile">
          <title>Single file modules</title>
          <para>
            Single file modules are useful in case case no additional files
            have to be distributed with your module. Because the module
            consists of only one single file, it is very easy to distribute.
            Beware though that the moment that you want to support for
            example a settings screen, multiple languages or custom images,
            you will have to switch to the multiple file module structure.
            Switching does mean some extra work for your users. So only use
            this format for modules for which you are sure that you do not
            need additional files in the future.
          </para>
          <para>
            Single file modules consist of one single PHP file. The name
            of this file is not restricted. We advice you to use
            <filename>mod_&lt;module name&gt;.php</filename> though
            for clarity and consitency with other module
            (e.g. <filename>mod_foo.php</filename>).
            This file contains both the module information and the hook
            function definitions. For storing the module informaton, a
            special PHP comment is used. This comment must look like the
            following:
            <programlisting><![CDATA[
/* phorum module info
<module information lines go here>
*/]]></programlisting>
            Using the example module info from
            <xref linkend="example.moduleinfo"/>, the complete single
            file module would look like this (see XXX why we use the
            check on PHORUM at the start of this file):
            <example id="example.singlefilemodule">
              <title>Single file module</title>
<programlisting>
<filename>{phorum dir}/mods/mod_foo.php</filename><![CDATA[
<?php

if(!defined("PHORUM")) return;

/* phorum module info
title: Foo
desc: This is the Foo module for Phorum. Nothing exciting...
version: 1.0.2
release_date: Jan 1st, 2008
url: http://www.phorum.org
author: John Doe <johndoe@example.com>
require_version: 5.2.2
category: user_features

hook: some_hook|phorum_mod_foo_some_hook
hook: some_other_hook|phorum_mod_foo_some_other_hook
hook: yet_another_hook|phorum_mod_foo_some_other_hook

priority: run some_hook before some_other_module
*/

function phorum_mod_foo_some_hook ($data) {
    // Do stuff for "some_hook".
    return $data;
}

function phorum_mod_foo_some_other_hook ($data) {
    // Do stuff for "some_other_hook" and "yet_another_hook".
    return $data;
}

?>]]></programlisting>
            </example>

            Installation of a single file module is done by putting the PHP
            file (e.g. <filename>mod_foo.php</filename>) directly in the
            directory <filename>{phorum dir}/mods/</filename> and activating
            the module from the "Modules" screen in your admin interface.
          </para>

        </section> <!-- end of single file modules -->

        <section id="modules.multifile">
          <title>Multiple file modules</title>

          <para>
            These modules are useful in case you need additional files
            to be stored with your module, for example a settings screen,
            language files or custom images.
          </para>
          <para>
            They are stored in their own subdirectory below
            the directory <filename>{phorum dir}/mods/</filename>.
            If you have a module named "foo", you will have to create a
            directory <filename>{phorum dir}/mods/foo/</filename> for storing
            all module files.
          </para>
          <para>
            Inside this subdirectory, you will have to create a least
            two files:
            <itemizedlist>
              <listitem>
                A file called <filename>info.txt</filename>.
                This file contains the module information for your module
                (see <xref linkend="modules.moduleinfo"/>).
              </listitem>
              <listitem>
                The PHP file which contains the hook function definitions
                for your module. The basename of this file should be the
                same as the name of the module subdirectory. So for our
                example module "foo", you will have to create a file named
                <filename>foo.php</filename>.
              </listitem>
            </itemizedlist>
          </para>
          <para>
            Using the example module info from
            <xref linkend="example.moduleinfo"/>, the complete multiple
            file module would look like this (see XXX why we use the
            check on PHORUM at the start of the PHP file):
            <example id="example.multifilemodule">
              <title>Multi file module</title>
<programlisting>
<filename>{phorum dir}/mods/foo/info.txt</filename><![CDATA[
title: Foo
desc: This is the Foo module for Phorum. Nothing exciting...
version: 1.0.2
release_date: Jan 1st, 2008
url: http://www.phorum.org
author: John Doe <johndoe@example.com>
require_version: 5.2.2
category: user_features

hook: some_hook|phorum_mod_foo_some_hook
hook: some_other_hook|phorum_mod_foo_some_other_hook
hook: yet_another_hook|phorum_mod_foo_some_other_hook

priority: run some_hook before some_other_module]]></programlisting>

<programlisting>
<filename>{phorum dir}/mods/foo/foo.php</filename><![CDATA[
<?php

if(!defined("PHORUM")) return;

function phorum_mod_foo_some_hook ($data) {
    // Do stuff for "some_hook".
    return $data;
}

function phorum_mod_foo_some_other_hook ($data) {
    // Do stuff for "some_other_hook" and "yet_another_hook".
    return $data;
}

?>]]></programlisting>

            </example>

            So far, the module has exactly same functionality as the single
            file module from <xref linkend="modules.singlefile"/>.
            From here on, the functionality can be extended. Some of the
            possibilities are:
            <itemizedlist>
              <listitem>
                Using custom files for your module
                (images, classes, libs, etc.);
              </listitem>
              <listitem>
                Letting your module support multiple languages.
                (See XXX about creation of language files)
              </listitem>
              <listitem>
                Creating a settings screen for your module;
                (See XXX about creation of settings screens)
              </listitem>
              <listitem>
                Adding template files for your module;
                (See XXX about module template files)
              </listitem>
            </itemizedlist>
          </para>

        </section> <!-- end of multi file modules -->

    </section> <!-- end of module structure -->

    <section id="modules.languages">
      <title>Supporting multiple languages</title>

      <para>
        This feature is supported by the <xref linkend="modules.multifile"
        xrefstyle="template:multiple file structure"/>.
      </para>
      <para>
        If your module includes text that will be displayed to end users,
        you should strongly consider making it support multiple languages.
        This will allow Phorum installations that use a different language(s)
        to display output of your module in the same language(s),
        instead of the language you have written the module in.
      </para>
      <para>
        For supporting multiple languages, the first thing to do is add the
        following line to your module information file
        <filename>info.txt</filename>:

        <programlisting>hook: lang|</programlisting>

        There is no actual hook function configured here, because the
        "lang" hook is only used as a marker for Phorum. It tells Phorum
        that your module supports multiple languages.
      </para>
      <para>
        Next, you must provide at least one language file with your module.
        Language files are stored in a subdirectory name "lang" inside your
        module directory. In our sample module, the full directory would be
        <filename>{phorum dir}/mods/foo/lang/</filename>. The language files
        must be named identical to the main language files that Phorum uses.
        To include both English and French, your module would require the
        following file structure:
        <programlisting>
{phorum dir}/
     |
     +-- mods/
          |
          +-- foo/
               |
               +-- info.txt
               |
               +-- foo.php
               |
               +-- lang/
                    |
                    +-- english.php
                    |
                    +-- french.php </programlisting>

        The structure of your language files will be almost identical to
        that of the main Phorum language files. However, for your own
        language files it is advisable to add an extra level in the
        language variables, to avoid conflicts with language string from
        other modules or Phorum itself. Here is an example of how you
        could do that:

        <programlisting><![CDATA[
<?php
$PHORUM["DATA"]["LANG"]["mod_foo"] = array(
    "Hello"   => "Hello!",
    "Bye"     => "Good bye!"
);
?> ]]></programlisting>

        Here, the extra inserted level is <literal>["mod_foo"]</literal>.
        To access the "Hello" string from your module code you would
        use the PHP variable:
        <programlisting>
$PHORUM["DATA"]["LANG"]["mod_foo"]["Hello"]</programlisting>

        When you want to use the language string from a template file,
        the you would use the following <xref linkend="templates.templatevars"
        xrefstyle="template:template variable"/>:
        <programlisting>
{LANG->mod_foo->Hello}</programlisting>

      </para>
      <para>
        In case a Phorum installation is using a language that your module
        does not support, Phorum will automatically attempt to fallback to
        English. So it is highly recommend that you include an
        <filename>english.php</filename> language file in all your modules.
        If both the current language and English are not found, Phorum will
        be unable to load a language for your module and will display empty
        space instead of your language strings.
      </para>
      <para>
        Always try to reuse strings that are already in the main Phorum
        language files itself. Only create custom strings when there is
        no alternative available. Having more text to translate is more
        work for translators and using core language strings helps in
        keeping the used terminology consistent.
      </para>

    </section> <!-- end of module languages -->

    <section id="modules.datastorage">
      <title>Module data storage</title>

      <section id="modules.datastorageintro">
        <title>Introduction</title>
        <para>
          Sometimes, modules will have to store some data in the Phorum
          system. For example an avatar module would have to store what
          avatar a user want to show and a poll module would have to add
          the question, answers and voting results for a poll to messages
          in which a poll is added.
        </para>
        <para>
          This section description what standard methods are available for
          letting modules store their data in the Phorum system. Of course,
          as a module writer, you can divert from this and use any kind
          of storage that you like. You are in no way limited to only use
          Phorum specific methods here.
        </para>
      </section>

      <section id="modules.storemessagedata">
        <title>Storing data for messages</title>

        <para>
          If your module needs to store data along with a Phorum message,
          the easiest way is to make use of the meta information array that
          is attached to each message array
          (<literal>$message["meta"]</literal>).
          This array is a regular PHP array, which is stored in the
          database as serialized data (see <ulink url="http://www.php.net/serialize">PHP's serialize manual</ulink>).
          Because Phorum and other modules make use of this meta data as
          well, you should never squash it, neither access the meta data
          in the database directly. Instead use the methods described in
          this section.
        </para>
        <para>
          To prevent name space collissions with other modules or Phorum,
          it is good practice to create only one key in the meta data
          array named <literal>mod_&lt;yourmodule&gt;</literal> (in our
          example: <literal>mod_foo</literal>). If your module needs to
          store only one single value, then put it directly under this key:
          <programlisting>
$message["meta"]["mod_foo"] = "the single value";</programlisting>
          If multiple values need to be stored, then put an array under
          the key. This array can be as complicated as you like:
          <programlisting><![CDATA[
$message["meta"]["mod_foo"] = array(
    "key1"    => "value1",
    "key2"    => "value2",
    "complex" => array(
        0 => "what",
        1 => "a",
        2 => "cool",
        3 => "module"
    )
); ]]></programlisting>
        </para>
        <para>
          <important>because the meta data is stored as serialized data in the
          database, it is not possible to handle the data you store in there
          through SQL queries.</important>
        </para>
        <para>
          When storing information in the meta data from a hook function, you
          can encounter two different situations, which both need a different
          way of handling: hooks that get an editable message array as their
          argument and hooks that don't.
        </para>

        <section id="modules.storemessagedata.type1">
          <title>
            From hooks that get an editable message array as their argument
          </title>
          <para>
            <remark>
              If you see ??? below at the places where you are supposed
              to see hook docs, then it is because the hook docs for
              "before_post" and "before_edit" have not yet been written.
            </remark>
            There are some hooks that send a full message structure to the
            hook functions. These can change the message structure before
            returning it to Phorum. Examples are the hooks
            "<xref linkend="hook.before_post"/>" and
            "<xref linkend="hook.before_edit"/>". For these kind of
            hooks, you can update the meta information in the message
            structure and be done with it. Here's an example of what this
            could look like in your hook function:
            <programlisting><![CDATA[
function phorum_mod_foo_before_post ($message)
{
    // Make sure that we have an array for mod_foo in the meta data.
    if (!isset($message["meta"]["mod_foo"]) ||
        !is_array($message["meta"]["mod_foo"])) {
        $message["meta"]["mod_foo"]["foodata"] = array();
    }

    // Add some fields to the mod_foo data.
    $message["meta"]["mod_foo"]["foodata"] = "Some data";
    $message["meta"]["mod_foo"]["bardata"] = "Some more data";

    // Return the updated message. Phorum will take care of
    // storing the "mod_foo" array in the database.
    return $message;
} ]]></programlisting>
          </para>
        </section> <!-- end of storing message data from message hooks -->

        <section id="modules.storemessagedata.type2">
          <title>From other hooks</title>
          <para>
            For other hooks, the proper way to store information in the meta
            data is to first retrieve the current message data (including the
            current meta data) using the phorum_db_get_message() function.
            After this, merge the information for your module with the
            existing meta data and store the updated data in the database
            using the phorum_db_update_message() function.
            Here is an example of what this could look like in your hook
            function:
            <programlisting><![CDATA[
function phorum_mod_foo_some_hook ($data)
{
    // Somehow you get the id for the message. Here we asume
    // that it is stored in the $data hook parameter.
    $message_id = $data["message_id"];

    // Retrieve the message from the database.
    $message = phorum_db_get_message ($message_id);

    // Extract the current meta data.
    $meta = $message['meta'];

    // Make sure that we have an array for mod_foo in the meta data.
    if (!isset($meta["mod_foo"]) || !is_array($meta["mod_foo"])) {
        $meta["mod_foo"]["foodata"] = array();
    }

    // Add some fields to the mod_foo data.
    $meta["mod_foo"]["foodata"] = "Some data";
    $meta["mod_foo"]["bardata"] = "Some more data";

    // Store the updated meta data in the database.
    phorum_db_update_message($message_id, array("meta" => $meta));

    // Return the data that we got as input for this hook function.
    return $data;
} ]]></programlisting>

           Changing meta data for a message this way will ensure that the
           existing meta data is kept intact.
          </para>
        </section> <!-- end of storing message data from other hooks -->

      </section> <!-- end of storing message data -->

    </section> <!-- end of storing data for a module -->

  </section> <!-- end of writing your own modules -->

</chapter>
