	<sect1 id="dev.plugins.building">
		<title>Building a Plugin</title>

		<para>
			This section will act as a walkthrough of how to build a plugin, from the
			bare basics all the way up to advanced topics.  A general understanding of
			the concepts covered in the last section is assumed, as well as knowledge
			of how the event system works.  Later topics in this section will require
			knowledge of database schemas and how they are used with MantisBT.
		</para>

		<para>
			This walkthrough will be working towards building a single end result: the
			"Example" plugin as listed in the <link linkend="dev.plugins.building.source">
			next section</link>.  You may refer to the final source code along the way,
			although every part of it will be built up in steps throughout this section.
		</para>

		<sect2 id="dev.plugins.building.basics">
			<title>The Basics</title>

			<para>
				This section will introduce the general concepts of plugin structure,
				and how to get a barebones plugin working with MantisBT.  Not much will be
				mentioned yet on the topic of adding functionality to plugins, just how to
				get the development process rolling.
			</para>

			<sect3 id="dev.plugins.building.basics.structure">
				<title>Plugin Structure</title>

				<para>
					The backbone of every plugin is what MantisBT calls the "basename", a
					succinct, and most importantly, unique name that identifies the plugin.
					It may not contain any spacing or special characters beyond the ASCII
					upper- and lowercase alphabet, numerals, and underscore.  This is used
					to identify the plugin everywhere except for what the end-user sees.
					For our "Example" plugin, the basename we will use should be obvious
					enough: "Example".
				</para>

				<para>
					Every plugin must be contained in a single directory named to match the
					plugin's basename, as well as contain at least a single PHP file, also
					named to match the basename, as such:
				</para>

				<programlisting>
Example/
	Example.php
				</programlisting>

				<para>
					This top-level PHP file must then contain a concrete class deriving from
					the <classname>MantisPlugin</classname> class, which must be named in the
					form of <classname>%Basename%Plugin</classname>, which for our purpose
					becomes <classname>ExamplePlugin</classname>.
				</para>

				<para>
					Because of how <classname>MantisPlugin</classname> declares the
					<function>register()</function>	method as <literal>abstract</literal>, our
					plugin must implement that method before PHP will find it semantically
					valid.  This method is meant for one simple purpose, and should never be
					used for any other task: setting the plugin's information properties,
					including the plugin's name, description, version, and more.
				</para>

				<para>
					Once your plugin defines its class, implements the <function>register()</function>
					method, and sets at least the name and version properties, it is then
					considered a "complete" plugin, and can be loaded and installed within
					MantisBT's plugin manager.  At this stage, our Example plugin, with all the
					possible plugin properties set at registration, looks like this:
				</para>

				<programlisting><filename>Example/Example.php</filename>

&lt;?php
class ExamplePlugin extends MantisPlugin {
    function register() {
        $this->name = 'Example';    # Proper name of plugin
        $this->description = '';    # Short description of the plugin
        $this->page = '';           # Default plugin page

        $this->version = '1.0';     # Plugin version string
        $this->requires = array(    # Plugin dependencies, array of basename => version pairs
            'MantisCore' => '1.2.0, &lt;= 1.2.0',  #   Should always depend on an appropriate version of MantisBT
            );

        $this->author = '';         # Author/team name
        $this->contact = '';        # Author/team e-mail address
        $this->url = '';            # Support webpage
    }
}
				</programlisting>

				<para>
					This alone will allow the Example plugin to be installed with MantisBT, and
					is the foundation of any plugin.  More of the plugin development process
					will be continued in the next sections.
				</para>
			</sect3>
		</sect2>

		<sect2 id="dev.plugins.building.pages">
			<title>Pages and Files</title>

			<para>
				The plugin API provides a standard hierarchy and process for adding new pages and
				files to your plugin.  For strict definitions, pages are PHP files that will be
				executed within the MantisBT core system, while files are defined as a separate
				set of raw data that will be passed to the client's browser exactly as it appears
				in the filesystem.
			</para>

			<para>
				New pages for your plugin should be placed in your plugin's
				<filename>pages/</filename> directory, and should be named using only letters and
				numbers, and must have a ".php" file extension.  To generate a URI to the new page
				in MantisBT, the API function <function>plugin_page()</function> should be used.
				Our Example plugin will create a page named <filename>foo.php</filename>, which
				can then be accessed via <literal>plugin_page.php?page=Example/foo</literal>, the
				same URI that <function>plugin_page()</function> would have generated:
			</para>

			<programlisting><filename>Example/pages/foo.php</filename>

&lt;?php
echo '&lt;p&gt;Here is a link to &lt;a href="', plugin_page( 'foo' ), '">page foo&lt;/a&gt;.&lt;/p&gt;';
			</programlisting>

			<para>
				Adding non-PHP files, such as images or CSS stylesheets, follows a very similar
				pattern as pages.  Files should be placed in the plugin's
				<filename>files/</filename> directory, and can only contain a single period in
				the name.  The file's URI is generated with the <function>plugin_file()</function>
				function.  For our Example plugin, we'll create a basic CSS stylesheet, and modify
				the previously shown page to include the stylesheet:
			</para>

			<programlisting><filename>Example/files/foo.css</filename>

p.foo {
    color: red;
}
			</programlisting>

			<programlisting><filename>Example/pages/foo.php</filename>

&lt;?php
echo '&lt;p&gt;Here is a link to &lt;a href="', plugin_page( 'foo' ), '">page foo&lt;/a&gt;.&lt;/p&gt;';
echo '&lt;link rel="stylesheet" type="text/css" href="', plugin_file( 'foo.css' ), '"/&gt;',
     '&lt;p class="foo"&gt;This is red text.&lt;/p&gt;';
			</programlisting>

			<para>
				Note that while <function>plugin_page()</function> expects on the page's name,
				without the extension, <function>plugin_file()</function> requires the entire
				filename so that it can distinguish between <filename>foo.css</filename> and
				a potential file <filename>foo.png</filename>.
			</para>

			<para>
				The plugin's filesystem structure at this point looks like this:
			</para>

			<programlisting>
Example/
	Example.php
	pages/
		foo.php
	files/
		foo.css
			</programlisting>

		</sect2>

		<sect2 id="dev.plugins.building.events">
			<title>Events</title>

			<para>
				Plugins have an integrated method for both declaring and hooking events, without
				needing to directly call the event API functions.  These take the form of class
				methods on your plugin.
			</para>

			<para>
				To declare a new event, or a set of events, that your plugin will trigger, override
				the <function>events()</function> method of your plugin class, and return an
				associative array with event names as the key, and the event type as the value.
				Let's add an event "foo" to our Example plugin that does not expect a return value
				(an "execute" event type), and another event 'bar' that expects a single value that
				gets modified by each hooked function (a "chain" event type):
			</para>

			<programlisting><filename>Example/Example.php</filename>

&lt;?php
class ExamplePlugin extends MantisPlugin {
    ...

    function events() {
        return array(
            'EVENT_EXAMPLE_FOO' => EVENT_TYPE_EXECUTE,
            'EVENT_EXAMPLE_BAR' => EVENT_TYPE_CHAIN,
        );
    }
}
			</programlisting>

			<para>
				When the Example plugin is loaded, the event system in MantisBT will add these two
				events to its list of events, and will then allow other plugins or functions to hook
				them.  Naming the events "EVENT_PLUGINNAME_EVENTNAME" is not necessary, but is considered
				best practice to avoid conflicts between plugins.
			</para>

			<para>
				Hooking other events (or events from your own plugin) is almost identical to declaring
				them.  Instead of passing an event type as the value, your plugin must pass the name
				of a class method on your plugin that will be called when the event is triggered. For
				our Example plugin, we'll create a <function>foo()</function> and
				<function>bar()</function> method on our plugin class, and hook them to the events we
				declared earlier.
			</para>

			<programlisting><filename>Example/Example.php</filename>

&lt;?php
class ExamplePlugin extends MantisPlugin {
    ...

    function hooks() {
        return array(
            'EVENT_EXAMPLE_FOO' => 'foo',
            'EVENT_EXAMPLE_BAR' => 'bar',
        );
    }

    function foo( $p_event ) {
        ...
    }

    function bar( $p_event, $p_chained_param ) {
        ...
        return $p_chained_param;
    }
}
			</programlisting>

			<para>
				Note that both hooked methods need to accept the <parameter>$p_event</parameter>
				parameter, as that contains the event name triggering the method (for cases where
				you may want a method hooked to multiple events).  The <function>bar()</function>
				method also accepts and returns the chained parameter in order to match the
				expectations of the "bar" event.
			</para>

			<para>
				Now that we have our plugin's events declared and hooked, let's modify our earlier
				page so that triggers the events, and add some real processing to the hooked
				methods:
			</para>

			<programlisting><filename>Example/Example.php</filename>

&lt;?php
class ExamplePlugin extends MantisPlugin {
    ...

    function foo( $p_event ) {
        echo 'In method foo(). ';
    }

    function bar( $p_event, $p_chained_param ) {
        return str_replace( 'foo', 'bar', $p_chained_param );
    }
}
			</programlisting>

			<programlisting><filename>Example/pages/foo.php</filename>

&lt;?php
echo '&lt;p&gt;Here is a link to &lt;a href="', plugin_page( 'foo' ), '">page foo&lt;/a&gt;.&lt;/p&gt;';
     '&lt;link rel="stylesheet" type="text/css" href="', plugin_file( 'foo.css' ), '"/&gt;',
     '&lt;p class="foo"&gt;';

event_signal( 'EVENT_EXAMPLE_FOO' );

$t_string = 'A sentence with the word "foo" in it.';
$t_new_string = event_signal( 'EVENT_EXAMPLE_BAR', array( $t_string ) );

echo $t_new_string, '&lt;/p&gt;';
			</programlisting>

			<para>
				When the first event "foo" is signaled, the Example plugin's
				<function>foo()</function> method will execute and echo a string.  After that,
				the second event "bar" is signaled, and the page passes a string parameter; the
				plugin's <function>bar()</function> gets the string and replaces any instance of
				"foo" with "bar", and returns the resulting string.  If any other plugin had
				hooked the event, that plugin could have further modified the new string from the
				Example plugin, or vice versa, depending on the loading order of plugins.  The
				page then echos the modified string that was returned from the event.
			</para>
		</sect2>

		<sect2 id="dev.plugins.building.config">
			<title>Configuration</title>

			<para>
				Similar to events, plugins have a simplified method for declaring configuration
				options, as well as API functions for retrieving or setting those values at runtime.
			</para>

			<para>
				Declaring a new configuration option is achieved just like declaring events.  By
				overriding the <function>config()</function> method on your plugin class, your
				plugin can return an associative array of configuration options, with the option
				name as the key, and the default option as the array value.  Our Example plugin
				will declare an option "foo_or_bar", with a default value of "foo":
			</para>

			<programlisting><filename>Example/Example.php</filename>

&lt;?php
class ExamplePlugin extends MantisPlugin {
    ...

    function config() {
        return array(
            'foo_or_bar' => 'foo',
        );
    }
}
			</programlisting>

			<para>
				Retrieving the current value of a plugin's configuration option is achieved by
				using the plugin API's <function>plugin_config_get()</function> function, and can
				be set to a modified value in the database using
				<function>plugin_config_set()</function>.  With these functions, the config option
				is prefixed with the plugin's name, in attempt to automatically avoid conflicts in
				naming.  Our Example plugin will demonstrate this by adding a secure form to the
				"config_page", and handling the form on a separate page "config_update" that will
				modify the value in the database, and redirect back to page "config_page", just
				like any other form and action page in MantisBT:
			</para>

			<programlisting><filename>Example/pages/config_page.php</filename>

&lt;form action="&lt;?php echo plugin_page( 'config_update' ) ?&gt;" method="post"&gt;
&lt;?php echo form_security_field( 'plugin_Example_config_update' ) ?&gt;

&lt;label&gt;Foo or Bar?&lt;br/&gt;&lt;input name="foo_or_bar" value="&lt;?php echo string_attribute( $t_foo_or_bar ) ?&gt;"/&gt;&lt;/label&gt;
&lt;br/&gt;
&lt;label&gt;&lt;input type="checkbox" name="reset"/&gt; Reset&lt;/label&gt;
&lt;br/&gt;
&lt;input type="submit"/&gt;

&lt;/form&gt;
			</programlisting>

			<programlisting><filename>Example/pages/config_update.php</filename>

&lt;?php
form_security_validate( 'plugin_Example_config_update' );

$f_foo_or_bar = gpc_get_string( 'foo_or_bar' );
$f_reset = gpc_get_bool( 'reset', false );

if ( $f_reset ) {
    plugin_config_delete( 'foo_or_bar' );
} else {
    if ( $f_foo_or_bar == 'foo' || $f_foo_or_bar == 'bar' ) {
        plugin_config_set( 'foo_or_bar', $f_foo_or_bar );
    }
}

form_security_purge( 'plugin_Example_config_update' );
print_successful_redirect( plugin_page( 'foo', true ) );
			</programlisting>

			<para>
				Note that the <function>form_security_*()</function> functions are part of the
				form API, and prevent CSRF attacks against forms that make changes to the system.
			</para>
		</sect2>

		<sect2 id="dev.plugins.building.language">
			<title>Language and Localization</title>

			<para>
				MantisBT has a very advanced set of localization tools, which allow all parts of of
				the application to be localized to the user's preferred language.  This feature has
				been extended for use by plugins as well, so that a plugin can be localized in much
				the same method as used for the core system.  Localizing a plugin involves creating
				a language file for each localization available, and using a special API call to
				retrieve the appropriate string for the user's language.
			</para>

			<para>
				All language files for plugins follow the same format used in the core of MantisBT,
				should be placed in the plugin's <filename>lang/</filename> directory, and named
				the same as the core language files. Strings specific to the plugin should be
				"namespaced" in a way that will minimize any risk of collision.  Translating the
				plugin to other languages already supported by MantisBT is then as simple as
				creating a new strings file with the localized content; the MantisBT core will find
				and use the new language strings automatically.
			</para>

			<para>
				We'll use the "configuration" pages from the previous examples, and dress them up
				with localized language strings, and add a few more flourishes to make the page act
				like a standard MantisBT page.  First we need to create a language file for English,
				the default language of MantisBT and the default fallback language in the case that
				some strings have not yet been localized to the user's language:
			</para>

			<programlisting><filename>Example/lang/strings_english.txt</filename>

&lt;?php

$s_plugin_Example_configuration = "Configuration";
$s_plugin_Example_foo_or_bar = "Foo or Bar?";
$s_plugin_Example_reset = "Reset Value";
			</programlisting>

			<programlisting><filename>Example/pages/config_page.php</filename>
&lt;?php

html_page_top( plugin_lang_get( 'configuration' ) );
$t_foo_or_bar = plugin_config_get( 'foo_or_bar' );

?&gt;

&lt;br/&gt;

&lt;form action="&lt;?php echo plugin_page( 'config_update' ) ?&gt;" method="post"&gt;
&lt;?php echo form_security_field( 'plugin_Example_config_update' ) ?&gt;
&lt;table class="width60" align="center"&gt;

&lt;tr&gt;
    &lt;td class="form-title" rowspan="2"&gt;&lt;?php echo plugin_lang_get( 'configuration' ) ?&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr &lt;?php echo helper_alternate_class() ?&gt;&gt;
    &lt;td class="category"&gt;&lt;php echo plugin_lang_get( 'foo_or_bar' ) ?&gt;&lt;/td&gt;
    &lt;td&gt;&lt;input name="foo_or_bar" value="&lt;?php echo string_attribute( $t_foo_or_bar ) ?&gt;"/&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr &lt;?php echo helper_alternate_class() ?&gt;&gt;
    &lt;td class="category"&gt;&lt;php echo plugin_lang_get( 'reset' ) ?&gt;&lt;/td&gt;
    &lt;td&gt;&lt;input type="checkbox" name="reset"/&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
    &lt;td class="center" rowspan="2"&gt;&lt;input type="submit"/&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
&lt;/form&gt;

&lt;?php

html_page_bottom();
			</programlisting>

			<para>
				The two calls to <function>html_page_top()</function> and
				<function>html_page_bottom()</function> trigger the standard MantisBT header and
				footer portions, respectively, which also displays things such as the menus and
				triggers other layout-related events.  <function>helper_alternate_class()</function>
				generates the CSS classes for alternating row colors in the table.  The rest of the
				HTML and CSS follows the "standard" MantisBT markup styles for content and layout.
			</para>
		</sect2>

	</sect1>
