Modules
https://secure.gravatar.com/avatar/b28e536690cbbcc42568497fe280b4f4.png?d=wavatar&s=28
Wed Feb 20 20:56 Authored by zegenie

Introduction  

Modules are the main way of extending and/or modifying functionality in The Bug Genie. Modules can be used for anything from providing alternative authentication backend, to altering the way pages looks and works - and much of the functionality that is part of the main package is actually provided by modules.

With modules, you can add new sections to the site, add account settings and much more. Here's a quick howto on how to set up your first module.

A quick overview  

Any installed module is automatically loaded and set up when the core engine initializes on each request. The module functionality is always enabled and available before any main functions are invoked. This lets you hook into pretty much any part of the core system without manipulating the base files. Modules can add routes (URLs) dynamically and on demand, and can also hook into and provide additional functionality from the command line interface (cli). You can set up modules that communicate with eachother directly or via the event system, or your module can operate (almost) on its own.

Module loading and initialization  

Modules are loaded after the core classes are added to the autoloader, and the context initialized (including the request), but before user authentication happens. All modules are loaded and added to the context before they are initialized, and no module functionality is provided before a module has been initialized. Because of the order of initialization, there is no i18n object available to modules until after they have been loaded and initialized.

Structure  

To create a new module, create a new directory under the "modules" directory in the top level. The module name (also called the module key) must be unique (clearly), and should only contain lowercase letters (convenience only - remember, some filesystem are case insensitive, which can easily lead to bugs). Inside the new module directory, create two files - one called class and another one called module, a folder called classes, and a module classfile inside the classes directory.

The end result should look like this:
 modules
   - mymodule
       - classes
           MyModule.class.php
       class
       module


The module file is used when installing this module, to provide a descriptive name for the module. Inside the module file, put the description of the module, which will then be used when the module is shown for installation:
 My Module - a fantastic module


The class file provides the classname of the main module class, and the module version. Inside the class file, put the name of the class that is the main module class, as well as the version number, separated by a pipe. (More information about how the main module class needs to be structured follows). In this case, the content of the file "class" would be
 MyModule|1.0


The class specified in the class file will be autoloaded when the module is instantiated. The module key will be the folder name (keep in mind the difference between the module key and the module class), and used to reference the module later. For instance, retrieving this module from elsewhere in the code is done by passing the module key to the static getModule() function in TBGContext.

Example:
// Retrieve the "mymodule" module
$module = TBGContext::getModule('mymodule');

echo get_class($module);
// outputs "MyModule"


Module contents  

A basic module needs to extend the core TBGModule class. This class takes care of a module's lifecycle, and implements a few final methods such as _construct(), install() and uninstall(). These methods cannot be overridden, but the module loading flow in The Bug Genie gives some alternative methods of initializing your module. When a module is loaded, it is instantiated, all its settings are cached, and the _initialize() method is called. In addition to this, you can implement the following three methods, which allows you to fine-tune your module during the setup phase:
  • _addRoutes() - if your module has any routes, set them up here. Remember to read the section about module routes.
  • _addListeners() - for event hooks


Note: the only function that is required for your module to operate, is the _initialize() function. This can be an empty method if you don't require any setup for your module during its instantiation, but it needs to exist.

Because of the way the TBGModule class extends the orm framework base classes, you also need to add an orm @Table annotation to your module, pointing to the TBGModulesTable class. See the example below.

Here's an example of a basic module:

modules/mymodule/module:
 My Module - a fantastic module


modules/mymodule/class:
 MyModule|1.0


modules/mymodule/classes/MyModule.class.php:
/**
 * My fancy MyModule module
 *
 * @package mymodule
 * @subpackage core
 * 
 * @Table(name="TBGModulesTable")
 */
class MyModule extends TBGModule
{

    protected $_longname = 'MyModule';

    protected $_description = 'My fancy module MyModule';

    protected $_module_config_title = 'MyModule';

    protected $_module_config_description = 'Set up the MyModule module from this section';

    protected $_has_config_settings = true;

    protected $_module_version = '0.1';

    /**
     * Return an instance of this module
     * Convenience method to provide better code completion
     *
     * @return MyModule
     */
    public static function getModule()
    {
        return TBGContext::getModule('mymodule');
    }

    protected function _initialize()
    {
    }

    protected function _addListeners()
    {
    }

    protected function _addRoutes()
    {
        $this->addRoute('mymodule_index', '/mymodule', 'index');
    }

}


Installing a module  

To be able to use a module, it needs to be installed - without installing it, it will not be loaded. This can be done either via the cli
 ./tbg_cli manage_modules install <module_name>
or via the module configuration interface. After you have installed it the module, it will be added to the autoloader and loaded on each request, as well as via the cli.

Adding installation data or fixtures  

During module installation, some functions in your module are executed (if they exist) - in the following order:
  • _install() - used to set default settings and other generic functionality
  • _loadFixtures() - useful if you need to load fixtures into database tables created during installation


Note: If your module has database table classes in the classes/B2DB folder, they will be created after the _install() function has been called but before the _loadFixtures() function is called. This means you cannot add data to any custom tables in the _install() function, but you can do it in the _loadFixtures() function. Read more about database tables and classes in the ORM documentation.

Using the cli to setup an empty module  

The Bug Genie CLI has a convenience command to create an empty module skeleton, called via
 ./tbg_cli create_module MyModule


This command will create all the necessary folders and files to get your module up and running. You can continue from there, adding pages and more.

Routing - your first module page  

So, unless you just want to linger in the background and do tasks invisible to the user, you probably want to have a page or something where user can interact with. External modules are treated in a similar way to internal modules - that means they follow the same rules and conventions as the internal modules does when it comes to Actions and Templates. However - it differs for external modules in that to be able to access the page, it needs to be added to the routing stack - it needs to have a URL which the user can access.

You set this up in the _addRoutes() function, where routes are added after the module has been initialized. Keep in mind that routes are being processed first-come, first-served, so you should make a conscious effort to avoid having routes where the URL overwrites previous URLs. (See the Routing documentation for more information about routes in general.) To add a route to the internal list of available routes, use the built-in addRoute() function from the module object:

TBGModule::addRoute():
$this->addRoute($route_key, $url, $action);


modules/mymodule/classes/MyModule.class.php:
// Add a route available via : http://<thebuggenie.location>/mymodule
// which will trigger the runFrontpage() method in the mymodules
// actions class
$this->addRoute('mymodule_frontpage', '/mymodule', 'frontpage');


The parameters in this call are similar to the normal routing parameters - except that the $module parameter from the original function defaults to the current module, so that parameter is excluded (you cannot setup alternate routes for existing core routes, or routes from other modules). Actions and templates are set up according to the documentation as specified in the Actions and Templates sections.

Route caching  

The routes provided by your module are cached after the first time your module is initialized. This means that the _addRoutes() method will not be triggered more than once if caching is enabled. This is expected during production, but can be difficult when developing. To avoid this, turn off caching, or turn on TBG debug mode in core/bootstrap.php.

Attachments 0

Comments 0

/unthemed/mono/no-comments.png
Expand, collaborate and share
Post a comment and get things done