You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 29 Next »

Registry functionality can be extended with the use of Plugins. Building a Registry Plugin requires knowledge of PHP, CakePHP, and COmanage.

Building a Registry Plugin

Background

  1. Understand the Cake Framework. You should minimally have worked through the tutorials and examples.
  2. Understand Cake Plugins. Registry Plugins are just Cake Plugins, with some extra conventions.
  3. Understand the Registry Data Model.

Plugin Directory

Set up a new Plugin in the directory app/Plugin/MyPlugin. You might find it handy to use Cake's bake command.

$ cd app
$ ./Console/cake bake plugin MyPlugin

Plugin Model

  1. Create a Model whose name matches the name of the Plugin. In this example, the Model is created at app/Plugin/MyPlugin/Model/MyPlugin.php.
  2. Define $cmPluginType to indicate the type of the Plugin, from the following options:

    $cmPluginType

    Description

    enroller
    Enrollment Flow Plugin

    normalizer

    Normalization Plugin

    provisioner

    Provisioning Plugin

    other

    Any other type of Plugin

Here's an example Model:

class LdapProvisioner extends AppModel {
  // Required by COmanage Plugins
  public $cmPluginType = "provisioner";
}

Database Schema

Plugins have full access to the Registry database. You can create your own additional tables by creating a schema file and placing it in Plugin/MyPlugin/Config/Schema/schema.xml. The file is specified in ADOdb AXMLS format.

Tables should follow the Cake standard conventions, including id, created, and modified.

Once the file is created, the database schema will automatically be updated by the normal mechanism:

$ cd app
$ ./Console/cake database

Database Prefixing

For the most part, the database prefix as specified in the database configuration file will just work. The exception is that foreign keys must have the prefix explicitly hardcoded (CO-174). For now, using the prefix cm_ is recommended.

Foreign Key Dependencies

If you define tables for your plugin, you will almost certainly want foreign keys into the core database schema. For example, your tables may have co_person_id or co_id to refer to CO People or COs, respectively.

In order for deletes to cascade successfully when the parent object is deleted, you must specify any dependencies your plugin has. (Failure to do so will result in foreign key violation errors when the parent object is deleted.) To do so, define an array $cmPluginHasMany in Model/MyPlugin.php, which consists of an array where the keys are the model the foreign key points to and the values are the name of the model they point from.

For example:

// Document foreign keys
public $cmPluginHasMany = array(
  "CoPerson" => array("CoChangelogProvisionerExport")
);

CoPerson hasMany CoChangelogProvisionerExports. Put another way, co_changelog_provisioner_exports has a column co_person_id that is a foreign key to co_people.

Language Texts

Do not hardcode display texts, but instead create lookup files that translate keys into language specific texts. For now, Registry uses a custom mechanism for I18N/L10N (CO-351). Use _txt(key) or _txt(key, array(param1, param2)) in your code to generate language-specific text, and then define those keys in the file Plugin/MyPlugin/Lib/lang.php:

// When localizing, the number in format specifications (eg: %1$s) indicates the argument
// position as passed to _txt.  This can be used to process the arguments in
// a different order than they were passed.

$cm_my_plugin_texts['en_US'] = array(
  // Titles, per-controller
  'ct.co_my_plugin_model.1'  => 'My Plugin Model',
  'ct.co_my_plugin_model.pl' => 'My Plugin Models',

  // Plugin texts
  'pl.myplugin.someparam'    => 'Some Parameter',
  'pl.myplugin.another'      => 'Another Parameter'
);

Use of Standard Views

You may use Registry's "standard" views to easily render your pages in the Registry look. Simply create links from Plugin/MyPlugin/View/Model to ../../../../View/Standard. See core Registry views for examples. Note that you will need to define the language texts ct.co_X_model.1 and ct.co_X_model.pl to use the standard views, replacing X with the name of your model.

Plugins can add items to Registry's menus. To do so, define in Model/MyPlugin.php a function cmPluginMenus() that returns an array. The key in this array is the menu location to append to (see table below), and the value is another array, which defines one or more labels and the corresponding controllers and actions to generate links to. The Plugin infrastructure will automatically append CO IDs and CO Person IDs as appropriate.

Whether or not a Plugin menu is rendered is determined by the default permission as listed below.

Menu Location Key

Menu Location

Default Permission

CO ID Inserted?

CO Person ID Inserted?

cmp

Platform Menu

CMP Administrator

 

 

coconfig

Organization Menu / CO Configuration Submenu

CO Administrator

(tick)

 

cos

Organization Menu / CO Submenu

Member of CO

(tick)

 

copeople

Organization Menu / People Submenu

Member of CO

(tick)

 

coperson

My Account Menu

Member of CO

(tick)

(tick)

An example:

/**
  * Expose menu items.
  *
  * @ since COmanage Registry v0.9.2
  * @ return Array with menu location type as key and array of labels, controllers, actions as values.
  */
public function cmPluginMenus() {
  return array(
    "coperson" => array(_txt('pl.dirviewer.viewmenu') =>
                      array('controller' => "dir_viewers",
                            'action'     => "view"))
  );
}

Adding links to Related Actions is not currently supported. (CO-520)

REST API

Exposing Plugin functionality via the REST API is not currently supported. (CO-521)

Additional Requirements By Plugin Type

Plugin Types not listed here have no additional requirements.

Enrollment Flow Plugins

The name of the Plugin should match the format FooEnroller.

The entry point for Enrollment Flow Plugins is foo_enroller/foo_enroller_co_petitions/start/coef:# for the start step, and foo_enroller/foo_enroller_co_petitions/step/# for all other steps (where # is the relevant CO Petition ID).

The easiest way to implement the Plugin itself is to extend CoPetitionsController. This way, most of the overhead of processing the request will be handled for you, and your plugin need only implement execute_plugin_step for each step you wish to process. (Note the name of each step is camelCased.) Once your plugin is finished, it should return control to the flow by redirecting back to the main flow, using the URL passed in $onFinish. The redirect URL is also available in the view variable $vv_on_finish_url.

Sample Enroller Plugin
// Plugin/FooEnroller/Controller/FooEnrollerCoPetitionsController.php
 
App::uses('CoPetitionsController', 'Controller');

class FooEnrollerCoPetitionsController extends CoPetitionsController {
  // Class name, used by Cake
  public $name = "FooEnrollerCoPetitions";
  public $uses = array("CoPetition");
  
  /**
   * Plugin functionality following petitionerAttributes step
   *
   * @param Integer $id CO Petition ID
   * @param Array $onFinish URL, in Cake format
   */
  
  protected function execute_plugin_petitionerAttributes($id, $onFinish) {
    // Do some work here, then redirect when finished.

    $this->redirect($onFinish);
  }
}

Standard MVC rules apply. Note the corresponding Views will match the action name (eg: petitioner_attributes.ctp) and not the function name.

Normalization Plugins

Some additional conventions are required when writing a Normalization Plugin.

  1. The name of the Plugin should match the format FooNormalizer.
  2. The Plugin must implement one function, which is defined in Model/FooNormalizer.php.
    1. normalize(), which accepts an array of data in typical Cake format and returns an array of normalized data in the same format. This function should be sure to copy any data to the return array that it does not modify, not just normalized data.

Provisioning Plugins

Some additional conventions are required when writing a Provisioning Plugin.

(warning) Provisioning Plugins are Provision*ers*, but the parent model is CoProvision*ing*. Be careful to reference the correct suffix.

  1. The name of the Plugin should match the format FooProvisioner.
  2. The Plugin should implement a model CoFooProvisionerTarget, and a corresponding Controller. (These are in addition to the other models and controllers required for Plugins.)
    1. This Model should extend CoProvisionerPluginTarget.
    2. The Controller should to extend SPTController ("Standard Provisioning Target" Controller), which provides some functionality common to most/all Provisioners (including parsing of co_provisioning_target_id.
    3. When a new Provisioning Target is created, a skeletal row in the corresponding co_foo_provisioner_targets table will be created. There is no add operation or view required. The skeletal row will point to the parent Provisioning Target.
    4. When a Provisioning Target is edited, the entry point to the Plugin will be foo_provisioner/co_foo_provisioner_targets/edit/#/co:x. This will be called immediately after the parent Provisioning Target is created.
  3. Note CoProvisioningTarget has a hasOne (ie: 1 to 1) relationship with CoFooProvisionerTarget.
  4. The table co_foo_provisioner_target should include a foreign key to co_provisioning_target:id.
    1. Other tables used by the plugin should reference co_foo_provisioner_target:id.
  5. The Plugin must implement two functions, which are defined in Model/CoProvisionerPluginTarget.php. See that file for the function signatures, including what data is passed to the Plugin and what results are expected to be returned.
    1. status() to obtain the current provisioning status for a CO Person or CO Group. Note: there is a default implementation that may be sufficient for many provisioner plugins. Registry will automatically manage entries in cm_co_provisioning_exports and relay that information through the default status() call.
    2. provision() to execute provisioning for a CO Person or CO Group.

Provisioning and Delete Operations

When a delete operation passes through to a Provisioning Plugin, it will generally only be because a CoPerson (or CO Group) is deleted. (Deleting, say, a TelephoneNumber will show up as an update.) The plugin will be called before the delete has committed to the database. This is so that the underlying data is still available for the plugin to perform its work.

Note that cascading delete, described above, will clean up any relevant tables.

  • No labels