This is an old revision of the document!
Table of Contents
Dynamic Plugin Requirements
Author: John Reese
Status: Feedback / Bugfixing
Introduction
This is a proposal for a very lightweight method of including a plugin/hook system for Mantis. It should be able to handle not only minor enhancements for areas such as outputting text, but adding new pages, menu items, and entire features to the application. It should be very simple, but very powerful.
This feature is meant as a counter point to the Add-Ons Support Requirements by offering a much simpler and easier to use plugin system without sacrificing flexibility or power.
Proposed Approach
Plugins will be very simple packages, extracted into the Mantis/plugins directory and enabled through the Management interface. There will be a simple event system that will handle hooking functionality in various forms, including data processing, list retrieval, and output. Events will be called at various points in the normal flow of Mantis, and the plugin API will handle calling any necessary plugin functions.
When a plugin is loaded at runtime, it will register basic information about itself to Mantis, including its name, author, description, version, and dependencies (Mantis version, other plugins). It will then register a callback function for each event that it would like to handle. When an event occurs, any plugin callbacks will be called in the order they are registered. The event type will determine how callback parameters and return values are processed.
New content pages will be added by creating scripts in a special directory of the plugin, and links to that page will be created with an API call to simplify the task. Plugin pages will not need to load the Mantis core, but will need to call the html_page_top() or html_page_bottom() functions as necessary.
Language Files
To simplify the usage of language files, plugins will simply need to supply a lang/
directory with appropriate strings files. The language API will search for strings in the main language files first, and only load the current plugin's language files if a needed string is not found elsewhere.
Database Schema
There will need to be a simple and unified method for plugins to maintain their database schema, otherwise plugins will get released without proper upgrade paths for users. The plugin manager should provide an automated schema upgrade mechanism that works the same as the Mantis upgrade mechanism. For performance reasons, the schema for plugins should only be checked when the plugin management screens are accessed, where it should notify the user of the need to upgrade the schema.
Event Types
These should be the basic event types, from which all (or most) events can be formed.
Execute event
- Simplest type of event.
- No parameters
- No return value
- Includes EVENT_PLUGIN_INIT
Output event
- Event giving plugins a chance to output content. Strings returned from callback are cleaned for display and appended back to back with a separator string.
- Parameters:
- separator string to output between plugins
- No return value
- Includes EVENT_PAGE_TOP and EVENT_PAGE_BOTTOM
Process event
- Event allowing a plugin to process an input string and return a modified version to the originator.
- Parameters:
- Input string
- Return value:
- Modified input string
- Includes EVENT_TEXT_GENERAL for bug links, bugnote links, wiki links, and other markup options.
Default event
- Can be used for everything else.
- Parameters
- Array of key/value pairs as direct parameters to the callback
- Return value
- Array of key/value pairs directly from the callback
Database Changes
- Create table
mantis_plugin_table
- basename varchar(40) primary key, the directory name for the plugin
- enabled boolean index
Configuration Changes
plugins_enabled
(default ON)manage_plugin_threshold
(default ADMINISTRATOR)
Sample Event Flows
Plugin Execution
This flow of action should occur during normal Mantis execution. It should be possible to bypass this by either disabling plugins from config_inc.php
or by a page declaring a special flag before including core.php
.
- List of enabled plugins is retrieved from database.
- For each enabled plugin:
- Include
plugins/<basename>/register.php
- Call
plugin_callback_<basename>_info()
function - Call
plugin_callback_<basename>_register()
function
- Send EVENT_PLUGIN_INIT signal
- Execute normal page contents with events as necessary
Event Execution
This flow of action should occur whenever an event is signaled, assuming plugins are enabled.
- Prepare parameters from event origin
- For each registered callback:
- Include
plugins/<basename>/events.php
- Call
plugin_event_callback_<basename>_<function_name>()
- Alter parameters for next callback if necessary
- Output content if necessary
- Return callback values to event originator if necessary
Plugin Hierarchy
<basename> represents the plugin's directory name, and should be a short, unique name that does not include version names or other changing identifiers. 'mantis' is a reserved basename, and represents a virtual plugin used for allowing dependencies based on Mantis versions.
mantis/ plugins/ <basename>/ register.php events.php lang/ ... pages/ ...
register.php
is the only file required for a plugin to be valid. It must contain two callbacks for plugin information and event registrations. This file should only have the following callbacks, but may include additional functions or callbacks for more complex plugins.plugin_callback_<basename>_info()
- This function must return an array of plugin information, including name, version, ad dependencies.plugin_callback_<basename>_register()
- This function must return an array of event names and corresponding function callbacks.plugin_callback_<basename>_schema()
- This function is only required if the plugin needs to maintain changes or additions to the Mantis schema. It must return an array of schema upgrades in the same format as theadmin/schema.php
upgrade script.
events.php
is required for using event hooks. It should contain all the event callback functions, or include additional scripts with the necessary callbacks. All event callback functions must be named asplugin_event_callback_<basename>_<name>()
. This script will only be loaded if the plugin has registered for an event.lang/
is only required if the plugin needs to use language strings that don't appear in the standard language files. These files will only be loaded if the requested strings cannot be found otherwise.pages/
is only required if a plugin needs to have its own pages. They can be accessed by linking a url returned by theplugin_page()
function. These pages need not load the core libraries, as it will already be loaded for them.
Sample Plugin (Super Cow Powers)
This is a very minimal plugin.
Directory Structure
mantis/ plugins/ supercow/ register.php events.php
sample/register.php
<?php /** * Return plugin details to the API. * @return array Plugin details */ function plugin_callback_supercow_info() { return array( 'name' => 'Super Cow Powers', 'description' => 'Gives your Mantis installation super cow powers.', 'version' => '1.0', 'author' => 'John Reese', 'contact' => 'jreese@leetcode.net', 'url' => 'http://leetcode.net', ); } /** * Register callback methods for any events necessary. */ function plugin_callback_supercow_register() { plugin_register( 'EVENT_PLUGIN_INIT', 'header' ); }
sample/events.php
<?php /** * Handle the EVENT_PLUGIN_INIT callback. */ function plugin_event_callback_supercow_header() { header( 'X-Mantis: This Mantis has super cow powers.' ); }
Feedback
- (vboctor): EVENT_TEXT_GENERAL - You might need to differentiate where this text is going, e.g. normal text (like string_display()), text within an edit box (like string_attribute()).
- (vboctor): EVENT_TEXT_GENERAL - I am assuming that you will be pipelining the results of one plug-in into another, right?
- (vboctor): EVENT_TEXT_GENERAL - If you look at the current implementation you will notice that the order of applying the display filters affects the final results. How are we going to handle such cases? The order sensitivity is mainly relating to html tags.
- (vboctor): Default event - With the default events, how are you going to handle the return values returned by all these plug-ins? Are you going to run one plugin, then dependent on the return value, decide whether to continue with the chain or not?
- (vboctor): How is the admin going to enable/disable plug-ins after unpacking them in the right place in the directory structure?
- (vboctor): Some plug-ins may like to change the terminology of Mantis, for example, use 'ticket' rather than 'issue'. You current approach only allows adding new strings.
- (vboctor): We need to rationalize how custom functions / plug-ins will overlap. For example, if a developer have overridden a custom function to do some generically useful behavior, then he/she may want to share this in the form of a plug-in.
- (vboctor): I would love to allow the development of Mantis Packs which provide a way to develop a plugin that makes Mantis work better with a certain development process (e.g. scrum) or work better for users migrating their installations from a specific bug tracker (for example, the statuses, reports, custom fields, etc).
- (vboctor): We need to support attachment preview plug-ins.
- (vboctor): We need to allow plug-ins to add new blocks to pages like issue view, update, etc.
- (vboctor): It should be easy to develop features like Twitter notifications as plug-ins. Once we do that, then the community can have plugins for all similar services like SMS, Jaiku, Pownce, etc.