Application plugins

From CollectiveAccess Documentation
Jump to: navigation, search

Capabilities

Application plugins are PHP classes you can write to extend CollectiveAccess with specialized functionality. If you need to add custom user interfaces – including menu items and screens – to CollectiveAccess application plugins are usually the best option.

Each application plugin has its own directory in app/plugins which contains all of the code, views, graphics and configuration required for operation. At a minimum every plugin has a plugin class. This class, a sub-class of BaseApplicationPlugin, defines methods that "hook" various events that may occur during a user request. Your plugin class need only implement methods for the hooks it is interested in. Every time a user request is processed by CollectiveAccess and hookable events triggered, each plugin implementing a method for a given hook will called.

Information will be passed to your methods by the application plugin interface. The scope and format of this information varies by hook and is described in detail in the Hooks section. In addition, all plugins have access to the current request object, and by extension request parameters and the application configuration file, via an inherited getRequest() method.

If you need to do any of the following then application plugins are probably a good solution:

  1. Add custom menus
  2. Add completely custom screens with their own controllers, views and even database tables
  3. Modify, verify or otherwise intercept data being edited, saved or deleted (for example, if you wanted to be able to reformat titles on the fly, or convert input of certain fields to all upper case)
  4. Modify the behavior of the CollectiveAccess user interface in specific ways

If you need to add support for new media formats, add custom search functionality, implement new attribute types (including attributes that leverage web services), generate custom item identifiers (aka accession numbers) or support alternative file and media storage (eg. cloud storage, external repositories) then you should look at some of the other available plugin interfaces.

Layout

Every plugin has a directory located in app/plugins The name of this directory should be the name of the plugin (for example mediaImporter). Within this directory you must create a file with the name of your plugin and the suffix 'Plugin.php' This file should contain a PHP class with your plugin's name suffixed with 'Plugin'.

Your plugin can have, if it needs to, its own controllers, views, graphics and configuration. By conventions these are located in directories within the plugin directory with the following layout (following our 'mediaImporter' example):

  • app/plugins/mediaImporter
  • app/plugins/mediaImporter/mediaImporterPlugin.php [plugin class]
  • app/plugins/mediaImporter/conf [directory containing plugin's configuration file(s); most plugins define at least one configuration file]
  • app/plugins/mediaImporter/controllers [directory containing plugin's controllers; only needed if the plugin generates a full user interface]
  • app/plugins/mediaImporter/views [directory containing views for the plugin's controllers; only needed if the plugin generates a full user interface]
  • app/plugins/mediaImporter/graphics [directory containing graphic elements; only needed if the plugin generates a full user interface]

The Plugin Class

Besides implementing a method for each hook your plugins needs to use, you must also define a checkStatus() method that returns information about the plugin and whether it is available for use or not. The return value for checkStatus() is an array with four keys:

  • description : a description of the plugin
  • errors : an array of text error messages relating to the initialization of the plugin. This should be an empty array if there are no errors. If the plugin is not available the reason why should be expressed in the errors array.
  • warnings : an array of text warning messages relating to the initialization of the plugin. Should be a list of warnings about anything that will limit the functionality of the plugin. Should be an empty array if there are no warnings.
  • available : set to true if plugin is loaded and available for use, false if it cannot load for some reason.

If initialization of your plugin fails, or for some reason the plugin should not be available in the current context (eg. the user does not have privileges to use the plugin, or some requirement for running is not met) then you must return false for the available value.

Your plugin must also set the $description property, inherited from the base plugin class. This should be set to a short description of the plugin, for display to the system administrator.

If your plugin needs to load its own configuration files or do other initialization, then you will need to include a constructor in your class. The constructor is passed an absolute file path to the plugin's directory, which is needed to load plugin-specific configuration files (or anything else in the plugin directory for that matter).

Hooks

The following hooks can be used by your plugin by defining a method in your plugin class using the hook name prefixed with "hook" For example, if your plugin needs to run every time a user edits an item define a method in your class like this:

public function hookEditItem($pa_params) {
	$item_id = $pa_params['id'];  // The parameter passed to EditItem is a key'ed array of values (see below for details)
	$table_num = $pa_params['table_num'];

	// ... more code here ...
}

Note that some hooks require you to return a value, while others do not. Use care when writing plugins that modify standard user interface elements such as menu bars. Errors in the values your plugin returns for hooks such as RenderMenuBar can make the system unusable.

If your plugin returns an array, the contents of that array will be merged with the array that was passed to you effectively incorporating your changes. There is one significant exception: if you return an empty the plugin manager will immediately return the null value to the caller and abort processing. Other plugins that may respond to the hook will not be called. This allows your plugin to "short circuit" a call to a hook, behavior that is useful in situations where the first plugin that can do the job must exclusively get the job. Note that returning any non-array value from your plugin is ignored by the plugin manager. In those cases the plugin manager will return the parameters passed into the hook unchanged.


Navigation

Hook name Description Parameters
RenderMenuBar Triggered when Providence is generating the top-level menu bar just prior to its being drawn on-screen. This hook gives your plug-in the opportunity to add its own menus or modify existing menus. Param 1: the full top-level navigation array (structure as defined in the navigation.conf file) Your plug-in hook should modify this array as needed and return it

Editing (Providence editors)

These hooks are triggered by specific actions in the Providence object, entity, place, etc. editors.

Hook name Description Parameters
EditItem Triggered when any bundle-able item (ca_objects, ca_entities, et. al.) are opened for editing in Providence. Param 1: an array with the following keys:
  • id = the row_id of the item being edited
  • table_num : the table number for the type of item being edited
  • table_name : the name of the table for the type of item being edited
  • instance : an instance of the model corresponding to the item being edited, loaded with the current row
BeforeSaveItem Triggered just before any bundle-able item (ca_objects, ca_entities, et. al.) is saved in Providence. The new values from the form are not applied at this time. To modify data before saving it to the database use BeforeBundleInsert and BeforeBundleUpdate. Param 1: an array with the following keys:
  • id = the row_id of the item being edited
  • table_num : the table number for the type of item being edited
  • table_name : the name of the table for the type of item being edited
  • instance : an instance of the model corresponding to the item being saved, loaded with the current row
SaveItem Triggered after any bundle-able item (ca_objects, ca_entities, et. al.) is saved in Providence. Param 1: an array with the following keys:
  • id = the row_id of the item being edited
  • table_num : the table number for the type of item being edited
  • table_name : the name of the table for the type of item being edited
  • instance : an instance of the model corresponding to the item being saved, loaded with the current row
BeforeDuplicateItem Triggered just before any bundle-able item (ca_objects, ca_entities, et. al.) is duplicated in Providence. This hook gives your plug-in the opportunity to make modifications to the item being duplicated prior to it being committed to the database. Param 1: an array with the following keys:
  • id = the row_id of the item being duplicated
  • table_num : the table number for the type of item being duplicated
  • table_name : the name of the table for the type of item being duplicated
  • instance : an instance of the model corresponding to the item being duplicated, loaded with the current row
DuplicateItem Triggered after any bundle-able item (ca_objects, ca_entities, et. al.) is duplicated in Providence. Param 1: an array with the following keys:
  • id = the row_id of the item being duplicated
  • table_num : the table number for the type of item being duplicated
  • table_name : the name of the table for the type of item being duplicated
  • instance : an instance of the model corresponding to the item being duplicated, loaded with the current row
  • duplicate : an instance of the model corresponding to the newly created duplicate
DeleteItem Triggered when any bundle-able item (ca_objects, ca_entities, et. al.) are deleted by the Providence editor. Param 1: an array with the following keys:
  • id = the row_id of the item being edited
  • table_num : the table number for the type of item being edited
  • table_name : the name of the table for the type of item being edited
  • instance : an instance of the model corresponding to the item being deleted, loaded with the current row

Labelable models (API-level calls)

These hooks are called when your code invokes addLabel(), editLabel() or deleteLabel() on a model inheriting from LabelableBaseModelWithAttributes.

Hook name Description Parameters
BeforeLabelInsert Triggered before label is inserted when addLabel() is called. This hook gives you the opportunity to modify a label before it is recorded in the database. Param 1: an array with the following keys:
  • id = the row_id of the item being edited. This is not the label_id! This is the primary key of the row to which the label is associated.
  • table_num : the table number for the type of item being edited. This is not the number of the label table. It is the name of the table to which the label is associated.
  • table_name : the name of the table for the type of item being edited. This is the name of the table associated with the label, not the label table itself.
  • instance : an instance of the model corresponding to the item being saved, loaded with the current row
  • label_instance : an instance of the model corresponding to the label being added, loaded with the label being created. Any changes you need to make to the label before it is written to the database should made to this model.
AfterLabelInsert Triggered after label is inserted when addLabel() is called. This hook lets your code run after a new label has been written to the database. Param 1: an array with the following keys:
  • id = the row_id of the item being edited. This is not the label_id! This is the primary key of the row to which the label is associated.
  • table_num : the table number for the type of item being edited. This is not the number of the label table. It is the name of the table to which the label is associated.
  • table_name : the name of the table for the type of item being edited. This is the name of the table associated with the label, not the label table itself.
  • instance : an instance of the model corresponding to the item being saved, loaded with the current row
  • label_instance : an instance of the model corresponding to the label being inserted, loaded with the new label information. This model will reflect the label as written.
BeforeLabelUpdate Triggered before label is updated when editLabel() is called. This hook gives you the opportunity to modify a label before it is recorded in the database. Param 1: an array with the following keys:
  • id = the row_id of the item being edited. This is not the label_id! This is the primary key of the row to which the label is associated.
  • table_num : the table number for the type of item being edited. This is not the number of the label table. It is the name of the table to which the label is associated.
  • table_name : the name of the table for the type of item being edited. This is the name of the table associated with the label, not the label table itself.
  • instance : an instance of the model corresponding to the item being saved, loaded with the current row
  • label_instance : an instance of the model corresponding to the label being saved, loaded with the label being edited. Any changes you need to make to the label before it is written to the database should made to this model.
AfterLabelUpdate Triggered after label is updated when editLabel() is called. This hook lets your code run after a label modification has been written to the database. Param 1: an array with the following keys:
  • id = the row_id of the item being edited. This is not the label_id! This is the primary key of the row to which the label is associated.
  • table_num : the table number for the type of item being edited. This is not the number of the label table. It is the name of the table to which the label is associated.
  • table_name : the name of the table for the type of item being edited. This is the name of the table associated with the label, not the label table itself.
  • instance : an instance of the model corresponding to the item being saved, loaded with the current row
  • label_instance : an instance of the model corresponding to the label being saved, loaded with the label being edited. This model will reflect any changes made to the label.
BeforeLabelDelete Triggered before label is deleted when removeLabel() is called. This hook gives you the opportunity to note that a label is being deleted before the fact. It does not (currently) allow you to cancel the delete. You can only watch in horror as it happens. Param 1: an array with the following keys:
  • id = the row_id of the item being edited. This is not the label_id! This is the primary key of the row to which the label is associated.
  • table_num : the table number for the type of item being edited. This is not the number of the label table. It is the name of the table to which the label is associated.
  • table_name : the name of the table for the type of item being edited. This is the name of the table associated with the label, not the label table itself.
  • instance : an instance of the model corresponding to the item being saved, loaded with the current row
  • label_instance : an instance of the model corresponding to the label being saved, loaded with the label being edited. Any changes you need to make to the label before it is written to the database should made to this model.
AfterLabelDelete Triggered after label is deleted when removeLabel() is called. Param 1: an array with the following keys:
  • id = the row_id of the item being edited. This is not the label_id! This is the primary key of the row to which the label is associated.
  • table_num : the table number for the type of item being edited. This is not the number of the label table. It is the name of the table to which the label is associated.
  • table_name : the name of the table for the type of item being edited. This is the name of the table associated with the label, not the label table itself.
  • instance : an instance of the model corresponding to the item being saved, loaded with the current row
  • label_instance : an instance of the model corresponding to the label being saved, loaded with the label being edited. This model will reflect any changes made to the label.

Bundleable models (API-level calls)

These hooks are called when your code invokes insert() or update() on a model inheriting from BundleableLabelableBaseModelWithAttributes.

Hook name Description Parameters
BeforeBundleInsert Triggered before instance is inserted into the database when insert() is called. This hook gives you the opportunity to modify instance data before it is recorded in the database. Param 1: an array with the following keys:
  • id = null since no id is set before the insert.
  • table_num : the table number for the type of item being edited.
  • table_name : the name of the table for the type of item being edited.
  • instance : an instance of the model corresponding to the item being inserted, loaded with the current row. You can alter the contents of this instance as needed.
AfterBundleInsert Triggered after instance is inserted when insert() is called. This hook lets your code run after a new instance has been written to the database. The primary key id will be set to the value generated by the database. Param 1: an array with the following keys:
  • id = the newly issues row_id of the item that has just been inserted.
  • table_num : the table number for the type of item being edited.
  • table_name : the name of the table for the type of item being edited.
  • instance : an instance of the model corresponding to the item being saved, loaded with the current row
BeforeBundleUpdate Triggered before bundle is updated when update() is called. This hook gives you the opportunity to modify the instance before it is recorded in the database. Param 1: an array with the following keys:
  • id = the row_id of the item being edited.
  • table_num : the table number for the type of item being edited.
  • table_name : the name of the table for the type of item being edited. .
  • instance : an instance of the model corresponding to the item being saved, loaded with the current row. You can alter the contents of this instance as needed.
AfterBundleUpdate Triggered after instance is updated when editLabel() is called. This hook lets your code run after an instance modification has been written to the database. Param 1: an array with the following keys:
  • id = the row_id of the item being edited.
  • table_num : the table number for the type of item being edited.
  • table_name : the name of the table for the type of item being edited.
  • instance : an instance of the model corresponding to the item being saved, loaded with the current row

Authorization

Hook name Description Parameters
GetRoleActionList Triggered when Providence is generating a list of user actions. This hooks gives your plug-in the ability to add its own user actions to the list. These actions will appear in the user roles configuration screens alongside Providence's standard actions and function identically. You can test whether a user has privileges for your custom actions at run-time and vary the behavior of your plug-in accordingly. Param 1: user actions array (structure is as defined in the user_actions.conf configuration file; you should modify this array and then return it in your hook. The format of your modifications should conform to the layout of a standard user action entry in user_actions.conf.

Task Queue

Hook name Description Parameters
RegisterTaskQueuePluginDirectories Triggered when task queue is initialized. This hook given your plug-in the opportunity to insert its own task queue plugin directories into the list of paths the TaskQueue class looks in to load task handler plugins. This is useful when you need to post tasks onto the task queue that use a handler specific to your application plugin. Rather than putting part of your plugin - the task handler - in the main plugins directory at app/lib/core/Plugins/TaskQueueHandlers, you can keep them in a directory of your choosing within the your plug-in directory. Param 1: an array with the following keys:
  • handler_plugin_directories : the array of plugin directories. Your plugin should add its own directory paths to this array.
  • instance : the current TaskQueue instance

User login editor

Hook name Description Parameters
BeforeUserSaveData Triggered just before primary user information (user name, password, email, name) are saved. Param 1: an array with the following keys:
  • user_id : the user_id of the user being edited.
  • instance : An instance of the ca_users model for the user being edited.
AfterUserSaveData Triggered just after primary user information (user name, password, email, name) are saved. Param 1: an array with the following keys:
  • user_id : the user_id of the user being edited.
  • instance : An instance of the ca_users model for the user being edited.
BeforeUserSavePrefs Triggered just before user preferences are saved. Param 1: an array with the following keys:
  • user_id : the user_id of the user being edited.
  • instance : An instance of the ca_users model for the user being edited.
AfterUserSavePrefs Triggered just after user preferences are saved. Param 1: an array with the following keys:
  • user_id : the user_id of the user being edited.
  • instance : An instance of the ca_users model for the user being edited.
  • modified_prefs: An array with keys set to the codes of preferences that have been modified by the save. Array values are true for each key.

Link generation

Available from v1.4

Hook name Description Parameters
CanHandleGetAsLinkTarget Sets 'acceptsTarget' key in returned param array if the link target can be handled by the plugin. Param 1: an array with the following keys:
  • target : A link target as set in the returnAsLinkTarget option in get(). Your plugin should only set the 'acceptsTarget' key in the param array with true for targets it recognizes.
GetAsLink Returns an HTML link to a specific record in a specific table as defined in the passed parameters. This allows the plugin to automatically generate links to itself or elsewhere when using the "returnAsLink" option in get() Param 1: an array with the following keys:
  • target : A link target as set in the returnAsLinkTarget option in get().
  • request : The current request (an RequestHTTP object).
  • content : Link text to display.
  • table : The table that the link should point to.
  • id : The primary key in the table that the link should point to.
  • classname : A CSS class to apply to the link.
  • additionalParameters : Any array of additional parameters to append to the link. Array keys are parameter names and array values are parameter values. May be null if there are no parameters set.
  • options : An array of options. These are the same options that can be passed to the caEditorUrl() and caDetailUrl() helpers. May be null if there are no options set.

Periodic tasks

Hook name Description Parameters
hookPeriodicTask Triggered every time periodic tasks need to be run. This typically happens in conjunction with processing of the task queue by a Unix-style CRON job running the support/utils/processTaskQueue.php utility script, but can be triggered elsewhere. Your method implementing this hook should do whatever it needs, pulling data from configuration files, the network, filesystem, Etc. No parameters are passed by the application to your plugin via this hook.

Note that there is no guarantee that invocations of your method will be evenly spaced or have a set minimum or maximum interval between invocations. If you need to restrict how often your method runs you will have to adjust the frequency with which periodic tasks are run (typically by modifying the CRON job that started the run) or implement logic in your plugin to keep track of invocations.
None

Common Problems

If CA is silently refusing to load your plugin then consider the following frequent mistakes:

  1. Is your plugin class named properly? It needs to be the name of your plugin directory + "Plugin". (eg. for a "mediaImport" plugin, the plugin class filename should be "mediaImportPlugin.php" and the class defined within that file named "mediaImportPlugin"
  2. Is your plugin class directly within the plugin directory? It should not be in a sub-directory
  3. Is your plugin class returning true for the available setting in getStatus()?
sphinx
Namespaces

Variants
Actions
Navigation
Tools
User
Personal tools