Modules

Modules are components of the Hierarchical Model View Controller application design pattern further explained in chapter
HMVC - Extending the Model-View-Controller Pattern.

Table of Contents

Overview

Following below the features and key points of revIgniter's approach to the HMVC pattern:

Structure of a HMVC Module

All modules are arranged in their own folder in the application/modules directory and may contain configuration files and sub-directories like the main MVC component in the application directory.

application/modules/
    |--myModule/
       |--config/
       |--controllers/
       |--extensions/
       |--helpers/
       |--language/
       |--libraries/
       |--models/
       |--stacks/
       |--views/

Please see as an example the very basic module "moduleSample" in application/modules. You can find a real-world example (a JSON feed module) here: https://gitlab.com/rabitt/revigniter-jsonfeed-module

Module Controller Specifications

Provided that the controller is used as an application controller, put all handler names which are likely to serve as uri segments into the global gModuleHandlers.

Provided that the controller is used as a library or widget, put the name of the main handler (the handler named after the module) as well as the index handler name and all names of handlers which are likely to be called by using the rigRunModule() function into the global gModuleHandlers.

To avoid name collisions with standard application controller index handlers the name of your module controller's index handler must be composed of the controller name followed by the word "Index" like: myModuleIndex.

Sample code of a module controller named after the module:

<?lc

# PUT YOUR HANDLER NAMES INTO THE GLOBAL gModuleHandlers AS A COMMA SEPARATED LIST
put "myModule,myModuleIndex,otherHandler" into gModuleHandlers


command myModule
  # MAIN HANDLER, THIS HANDLER IS CALLED WHEN THE CONTROLLER IS LOADED
  # LOAD REQUIRED LIBRARIES, MODELS, HELPERS ETC. HERE
  -- Code...
end myModule


command myModuleIndex
  # DEFAULT HANDLER, THIS HANDLER IS CALLED WHEN THE CONTROLLER IS RUN AND NO HANDLER IS SPECIFIED
  # REMEMBER TO PUT ALL THE VARIABLES TO BE MERGED WITH VIEWS INTO THE ARRAY VARIABLE gData
  -- Code...
end myModuleIndex


command otherHandler
  -- Code..., calling _privatehandler for example
end otherHandler


command _privatehandler
  # HANDLER NAME NOT USED AS URI SEGMENT / NOT CALLED BY rigRunModule(), SO, THERE IS NO NEED
  # TO STORE IT'S NAME IN gModuleHandlers
  -- Code...
end _privatehandler



--| END OF myModule.lc
--| Location: ./application/modules/myModule/controllers/myModule.lc
----------------------------------------------------------------------

There is a very basic sample controller in modules/moduleSample/controllers which can serve as application controller as well as widget / view partial.

Note: In case you use module controllers as application controller you must include a routes.lc file in the yourModule/config directory. Routing has no effect on view partials or if modules are used as libraries. Please see the sample routes file in modules/moduleSample/config.

Using Modules as Application Controllers

To use modules as application controllers specify the controller script to be invoked using URI segments. There is no difference to standard controllers. For example to run the sample module as application controller the appropriate URL would read:

example.com/moduleSample

Note: On the basis of the URL there is no way to distinguish between standard application controllers and module controllers used as app controllers. So, to avoid name collisions with app controller names be careful naming your module controllers. Of course this applies to naming modules used as widgets only.

Using Modules as Libraries or Widgets / View Partials

Widgets are, in contrast to modules used as app controllers, intrinsically tied to the modules library. So, please see chapter Modules Library for further information.

Module Paths

Module paths and module controller paths are relative to application/modules/. Keep in mind that module controllers can be located in sub-folders of myModule/controllers and that you must omit the name of the "controllers" directory in module paths. So, paths to controller files can be:

myModule/myController

or (calling in each case the index handler "myControllerIndex"):

myModule/mySubDirectory/myController

To address a particular controller handler instead of the index handler add it's name as segment Like:

myModule/myController/myControllerHandler

Use additional segments to pass parameters:

myModule/myController/myControllerHandler/name/joe

If you name a controller after your module and this controller is not in a sub-directory of myModule/controllers you can omit the controller name and the path would simply be:

myModule

If you don't include a handler name the controller's index handler, myModuleIndex in this case, is called. Calling a particular handler of controller myModule of module myModule would read:

myModule/myOtherHandler

Note: Currently "query string" URLs are not compatible with modules. So, always use segment-based URLs.

Loading Module Files and Resources

You can load models, libraries, helpers etc. like in standard application controllers. To load equivalent module files add the module's name to parameter lists like:

rigLoadModel "moduleModel", , "myModule"
  
rigLoaderLoadLibrary "Modulelibrary", , "myModule"

get rigLangLoadLang("moduleLang", "french", "myModule")

rigLoadHelper "moduleHelper", "myModule"

get rigLoadConfig("mymoduleconfig", TRUE, TRUE, "myModule")

rigLoadStack "moduleStack", , , "myModule"

rigLoadExtension "com.myDomain.library.myExtension", "myModule"
-- "com.myDomain.library.myExtension" is a folder (containing your "module.lcm" file) located in modules/myModule/extensions/

Auto-loading Module Resources

To autoload module resources, open your application/modules/myModule/config/autoload.lc file and add the item you want loaded to the gModuleAutoload array like:

put "database" into sAutoLibraries[1]
put "myLib" into sAutoLibraries[2]
put sAutoLibraries into gModuleAutoload["libraries"]

You'll find instructions in the autoload file of the sample module corresponding to each type of resource item which can be auto-loaded.

Loading Views

In general module view files are loaded like any other view file using rigLoadView(). Provided that the particular module is used as widget you must keep in mind that you should not set the second parameter of this function to true. To set this parameter is unnecessary anyway because loading the view of a widget always returns data as a string rather than sending it to the browser.

Module Configuration

To configure your module simply add a configuration file "config.lc" to application/modules/myModule/config/ like the one you find in the config directory of the sample module.

Setting a Module's Configuration Value in a Configuration File

To add configuration data related to your module use the module name as array key in a multidimensional array named "gConfig" like:

put "foo" into gConfig["myModule"]["bar"]

Overriding a Global Configuration Value in a Configuration File

To override global configuration data just omit the module's name as array key.

put "french" into gConfig["language"]

Fetching Module Config Items

To retrieve an item from your module's config file, use the standard function and add the name of your module as second parameter like:

rigFetchConfigItem("itemName", "myModule")

Setting a Module Config Item

If you would like to dynamically set a module's config item or change an existing one, you can so using:

rigSetConfigItem("itemName", "itemValue", "myModule")

Where itemName is the gConfig array index you want to change, and itemValue is its value, and the third parameter is the name of your module.

URI Routing

Note, the following applies to modules only if used as application controllers. Routing has no effect on view partials or if modules are used as libraries. In case you use module controllers as application controller you must include a routes.lc file in the yourModule/config directory. This file lets you re-map URI requests to specific controller functions. Typically there is a one-to-one relationship between a module URL string and its corresponding controller page library/handler. The segments in a module URL normally follow this pattern:

example.com/myModule/handler/ID/

or in case the name of the page library is not equal to the module name

example.com/myModule/pagelibrary/handler/ID/

or using a sub-directory in myModule/controllers

example.com/myModule/sub-directory/pagelibrary/handler/ID/

In some instances, however, you may want to remap this relationship so that a different page library/handler is called than the one corresponding to the URL. Store these custom routes which are relative to application/modules/ in the gRoute["yourModule"] array using a key number starting with number 2 like:

put "myModule/mysub-directory/myPagelibrary/myHandler" into gRoute["myModule"][2]["myModule/foo/bar"]

Please see chapter Uri Routing for complete details.

Reserved Routes

There are two reserved routes for modules:

put "myModule/pagelibrary" into gRoute["myModule"][1]["defaultController"]

This route indicates which controller page library should be loaded if the URI contains no data besides the module name. In the above example, the "pagelibrary" page library would be loaded. If the "defaultController" route is empty and there is only one URI segment specifying the name of the module, revIgniter expects that there is a controller named after the module and tries to load myModule/myModule. If no handler is specified the module's index handler is called which must be composed of the controller name followed by the word "Index" so that the route would look like: myModule/myModule/myModuleIndex.

put "" into gRoute["myModule"][1]["404Override"]

This route will tell the Router what URI segments to use if those provided in the URL cannot be matched to a valid route, in other words if the controller specified is missing. If this route is empty the default 404 error page is provided.

Note: Module routes are relative to application/modules/. The gRoute["myModule"] array must be numbered and the key number for reserved routes must be 1. So custom route key numbers start with number 2.

Module Assets

A nice side effect of using the asset helper to deal with module CSS files, JavaScript files and images is that it simplifies distribution of modules including assets. Just organize all related assets (as described in chapter Asset Helper) in a folder preferably named after your module and store it in assets/modules. This way installation of a module with appendant assets is as simple as copying two folders to the right place.