This is an old revision of the document!


  • Preface: The described plugin-system below is currently implemented in dotproject.net, but it seems that it is dead. The described information could be usefull for Feng Office, but was not originally developed by me. I simply installed and used dotProject and I have written some plugins using theire system (as described below)
  • TODO: What exactly are hooks and what are the differences between hooks and plugins
  • Plugins in my way of thinking:
    1. are pieces of code, images, etc which extend the Feng Office functionality and introduce *new* things like a diary. A normal diary can be made as a document, but if I possibly want do some more things like searching inside or do some statistics etc, it is a good idea to capsule this information-centric-functionality into a plugin.
    2. In my way of thinking plugins normally should extend the horizontal menu in Feng Office (depends of the kind of plugin)
  • Limitations of current plugin-system:
    1. One developer can overwrite code by accident of another developer, because every plugin is zipped and has inside the Feng Office-folder-structure. When two different plugins are deflated, which had changes in the same file, the last plugin wins (lost-update-problem)
    2. Every (major?) update of the Feng Office-distribution has a high potential of loosing plugin-functionality
  • Must-Have-Features of a new plugin-system:
    1. installable, uninstallable, activatable, deactivateble, movable (in menu, but depends on type)
    2. different kinds of plugin-types like extends horizontal menu, extends context-menu, etc
    3. can be configurable (ideally also via web in admin-page)
    4. are able by themselves to create tables (when they are installed)
    5. are able by themselves to update tables (when a developer creates a new version)
    6. are able by themselves to delete tables (when they are uninstalled)
    7. provide information about themselves like, name, current_version, description, dependencies to user plugins, etc
  • Architectural thoughts:
    • Folder-structure
      1. All plugins should reside in a single subfolder of Feng Office, ideally called plugins
      2. Each plugin creates its own top-folder (inside plugins), where all the stuff is, which is needed by the plugin
      3. There should be a naming-convention for creating the subfolder-name
    • Database-Design
      1. Each plugin is allowed to create tables, which are needed due to the plugin-operation
      2. There should be a naming convention for tables, created by a plugin, prefix, etc
      3. Feng Office should be improoved to use constraints (if it does not do already) to limit plugin-accidents
      4. Feng Office has to store some plugin-relevant information in an own table:
        • Name of plugin
        • Status of plugin (installed, installable)
        • State of plugin (activaed, deactivated)
        • Version of plugin
        • Storage-location of plugin (subfolder-name)
        • TODO
      5. This information must be checked againt the folder, when the plugin-administration-module is called to administer plugins
    • Class-Design
      1. There should be a setup.php in top of the plugins-folder to supply the methods and information needed during installation, administration, etc
      2. There should then be another entry-point into the plugin like an index.php or a class-file, which is instantiated(info provided by setup)
      3. TODO
    • Procedural things and flow
      • Installation of a new plugin
        1. [ADMIN] deploys a new plugin into the feng-plugins-folder, called diary (folder is then feng-base/plugins/com-example-diary-or-whatever)
        2. [ADMIN] browses then to feng-plugin-administration-page (module)
        3. [Feng Office] reads information from table to know about all plugins from last folder-scan and their status
        4. [Feng Office] reads then all subfolders in plugins-folder and determines a new one, which does not match against anything in the read table
        5. [Feng Office] because its new, it can only be installed. setup.php-information is read (array, or whatever) and some information presented (description)
        6. [Feng Office] checks dependecies to other plugins (and versions) and is everything is ok, shows install-button
        7. [ADMIN] clicks on install, after having read the description and developer-remarks
        8. [Feng Office] executes install-methods in setup-php, which should execute database-statements, etc
      • Upgrade a plugin to a newer version
        1. TODO
      • Remove a plugin
        1. TODO
      • Configure a plugin
        1. TODO
    • Code-snippets
      1. setup.php: (an example I wrote for my old dotProject-installation 5 years ago)
<?php
// MODULE CONFIGURATION DEFINITION
$config = array();
$config['mod_name'] = 'Diary'; 
$config['mod_setup_class'] = 'CSetupDiary';
$config['mod_version'] = '0.8';
$config['mod_config'] = false;                        // show 'configure'
//some more config-details

class CSetupDiary {

function remove() {                                   // run this method on uninstall process
    db_exec( "DROP TABLE diary;" );                   // remove the diary table from database

    return null;
  }


  function upgrade( $old_version ) { 

    switch ( $old_version ){
    case "0.9":
      //do some alter table commands
      return true;

    case "1.0":
      //do some alter table commands
      return true;

    default:
      return false;
    }
  }

  function install() {
    // prepare the creation of a dbTable -> create diary
    $sql = "CREATE TABLE diary ( " .          
      "  diary_id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT" .
      ", diary_owner_id INT(11) UNSIGNED NOT NULL" .
      ", diary_header VARCHAR(100)" .
      ", diary_main TEXT" .
      ", diary_date DATE" .
      ", diary_last_modified TIMESTAMP" .
      ", PRIMARY KEY  (diary_id)" .
      ", UNIQUE KEY diary_id (diary_id)" .
      ") TYPE=MyISAM;";

    db_exec( $sql ); db_error();                 // execute the queryString through feng-api

    return null;
  }
}
?>