The concept of a Plugin or additional module is any form or quantity of programming code that does not form part of the main Production Cliqon administration system. As a Developer, you should undertake all your additional application development work as Plugins as we do for any additional project work that we perform directly for customers. The contents of the Plugin subdirectory structure will never be overwritten by a system update. However, you can take advantage of the way Cliqon carries out updates by adding certain files to the System Update List and arranging a location with us from where these updates can be downloaded.


For clarity, please let us reiterate that you would not use the Plugins facilities and methodology for front end web development. That is already catered for with PageController and the CMS or Website Classes and Methods.

Plugin basics

A plugin is treated like a microcosm of the Cliqon administration system. By default, it is presumed that virtually all files related to the plugin will be found in the /plugins sub directory. However it must be stressed that in common with many other aspects of the Cliqon infrastructure, this is a convenience not a requirement. Thus, if as a developer, you are working on a major module, you can configure the Routes and Controllers to point to an alternative subdirectory. You may want to do this so as to avoid conflict with other Plugins. We do not yet impose strict rules and conventions on the naming of files. Perhaps we will have to do that in the future.

Routing

The first element to be considered is the generation of a Route that will respond to a URL related to your Plugin. This might be a Page URL, an AJAX URL or an API URL. The Routes configuration file contains a series of lines, which by default, follow the routing strategy of a production Cliqon system:


; For External and Internal

'/plugin/:idiom/:string' = 'PluginController'

'/plugin/:idiom/:string/:alpha' = 'PluginController'

'/plugin/:idiom/:string/:alpha/:alpha' = 'PluginController'


For a full URL, this reads https://yourdomain.com/plugin/idiom/action/table/tabletype/?key1=val1&key2=val2 and so on. The critical point being that we want the URL to be matched to the Controller, in this case, the PluginController.

Controller

All Controllers in Cliqon do fundamentally the same job, they route a Request to a Class and Method and / or they return a stream of HTML that has been generated by the Template Engine and / or they generate a JSON or JSONP (remote) string.


In the case of most of the Cliqon production controllers, these tasks are allotted to different Controllers - thus Default, Page and Admin controllers only return a stream of HTML. While the Ajax and API controllers only return an array as a JSON string (which may contain a string of HTML as an element of the array).


The Plugin Controller is different in the respect that it has the necessary facilities to do all the tasks that a Controller can be asked to do. To achieve this feat of returning either HTML or JSON, depending on the demand, we must make an assumption, a Request header that contains an element of Ajax - that is, it is an XHR headed request, will be handled by "api_exec" method, whilst ordinary headed requests (whether GET or POST) will be handled by the "page_exec" method.


The Page_Exec method is a hybrid. We assume that you wish that your additional development pages be encapsulated in the standard administrative framework. To achieve this, the method invokes the Admindesktop infrastructure in order to set top navigation, left and right side menus plus the footer. We assume that all content within the page container will be presented by a named plugin Class and Method. This means that the content will be a component template and this template will be found in /plugins/components/.


However when we come look at Api_Exec, we find that all references refer to assets that will be located in the /plugins/ subdirectory.

Menu

You will need to create menu entries in the administration "admleftsidemenu" or possibly the "admtopmenu" in order to gain access to your new facilities. Please refer to the section on Menus to understand how to do this.

Example Plugin

Anyone who has been in programming for a long time will understand that when one is working with a complex system that Cliqon has now become, one can be surprised how things work in just the same way as someone coming to the system for the first time. So please accept that just because we wrote the system and ought to know how it works, there are times when the system surprises us. It is thus with Plugin development. I believe that this is caused by the fact that Plugins are only needed for Application development and must be developed as a parallel track to the Administrative system.


As our example Plugin we have written a simple Cashbook to handle household expenses in a house in shared occupancy - that is where things such as electricity bills and food purchases have to be shared.


The Cashbook Plugin provides two extra major module facilities - the first is a table of transactions which is managed with a complete record management system (or CRUD facility), the second is a facility to calculate what amounts of money the residents have put into the shared cash box so that all expenses are paid.


To make matters more interesting we chose to use a different Table generation facility than that which is built into the standard Cliqon system and go back to using DataTables from Spry Media. The main reason for considering that using DataTables is a retrograde step is that it means we are not using Vue for table presentation and it is difficult to persuade the table to be fluid and responsive.


By now you should know that the menu entry is what drives the system or to be more precise, what content is displayed within the administrative container framework. Here is a summarised version of the menu entry for the Accounts Cashbook Datatable:


....

c_reference = 'ASM1049'

c_type = 'admleftsidemenu'

c_category = 'accounting'

c_common = 'Cash Book'

c_level = '60:70:90'

c_order = 'ah'

c_parent = 'ASM1048'

d_page = 'plugin'

d_type = 'admdatatablesnet'

d_table = 'dbtransaction'

d_tabletype = 'cashbook'

d_icon = 'shopping-basket'

d_title.en = 'Cash Book'

d_description.en = 'Income and expenses'

....


This creates a URL of https://ourdomain.com/plugin/en/admdatatablesnet/dbtransaction/cashbook. We know that the Routing will render the Plugin controller. What will the Plugin Controller do?


Firstly you need to be aware that virtually all Administration Menu calls are GET requests and treated as XHR headed. In this case, the controller will invoke the "Api_Exec", in which case the key word is the value of the $action variable which is "admdatatablesnet". As this module is a Plugin, it will be handled by the Plugin Class. This Class is equivalent to Ajax.php and Api.php,  that is, it operates like a parser or interface that provides some extra information to a method call before calling the appropriate Class and Method and passing the arguments.


We look in Plugin.php and we find that it contains a Class called "Plugin" (that extends Admin) and within the class is a method called "admdatatablesnet". Thus when the Plugin controller attempted to invoke Class->Plugin and Method->admdatatablesnet, no error was generated and an array (as expected as the return to the invocation or instantiation of the class and method) was returned.


               function admdatatablesnet($vars)

               {

                       global $clq;

                       $acc = $clq->resolve('Accounting');

                       return [

                               'content' => $acc->displayTransactions($vars),

                               'callBack' => ""

                       ];        

               }


The next step in the process, as defined in Plugin, is that the actual processing is undertaken by the Class name "Accounting" and within that class, a Method named "displayTransactions".


The "displayTransactions" method follows a relatively standard path for Cliqon processes.


    • it processes the arguments passed to the method
    • reads the configuration for this service, collection and model, in this case - the admdatatablesnet service, the dbtransaction collection and cashbook model
    • it extends or translates references for language strings found in the model. These language strings should be User strings and not Admin Strings (that dbitem->string and not dbcollection->string)
    • it generates the column names that will be used on the datatable
    • it sets up some configuration arrays, such as the page length property array, which is peculiar to the DataTablesNet datatable service
    • it sets up the top buttons
    • it names the component template
    • it generates the JSON Web Token
    • it generates the javascript configuration variables for the page
    • the Javascript is set as the script for the page (that is, the code that will be rendered by the script component that is common to all pages in the admin system)
    • the component template, named above, is rendered by the template engine and the result of that render process (eg a steam of HTML) is returned to the caller script (Ajax.Php) and thence to the Plugin Controller.


The controller treats this stream as a portion of the JSON Array that it returns to the browser.


For more information about the lifecycle, see the section on Page Lifecycle at Build a System -> build a website -> page lifecycle.

Created with the Personal Edition of HelpNDoc: Full-featured EPub generator