This documentation currently applies to MR7 and later, and is expected to evolve with future releases. |
Management of CakePHP plugins has changed significantly since Cake 2, largely due to the use of PHP Autoloading in Cake 4. The least bad way to handle this in a production environment is to install plugins via composer, though such procedures are not yet formalized for Registry PE. This document currently describes how to write plugins that will ship with Registry (either core or available).
In addition, Registry Plugins have been redesigned to address various long standing problems. All plugins are expected to be instantiated, with improved common libraries to simplify the design of new plugin types. Instantiations now refer to plugins via Plugin.Model
notation, creating a generalized solution for polymorphic plugins (plugins that can implement more than one plugin type) as well as multiple entry points (so a single plugin can easily provide multiple functions).
external_identity_source
. (underscore is used rather than dasherize so that the type can be easily converted back via classify or camelize.)The easiest way to create the structure for the new Plugin is with Cake's bake command.
While there are no longer technical requirements around the construction of a Plugin's name, it is still advisable for the Plugin to be named in a way that describes its primary purpose, such as SqlSource or NightlyReport.
Pick an appropriate location for the plugin: Core Plugins should go in app/plugins
, Available Plugins should go in app/availableplugins
, and Local Plugins should go in local/plugins
.
$ cd $SRC/app $ ./bin/cake bake plugin MyPlugin 1. /src/comanage/git/registry-pe/app/plugins/ 2. /src/comanage/git/registry-pe/app/availableplugins/ 3. /src/comanage/git/registry-pe/app/../local//plugins/ Choose a plugin path from the paths above. > 2 |
Allow composer.json
to be overwritten, this is how the autoloader paths will be updated.
Modifying composer autoloader File `/src/comanage/git/registry-pe/app/composer.json` exists Do you want to overwrite? (y/n/a/q) y |
It's not obvious from the command output, but app/src/Application.php
will also be updated to load the plugin. This change is not needed (Registry will automatically load activated plugins) and should be reverted.
The default namespace for the Plugin will be the name of the plugin ( |
The |
Within the plugin directory, create the file src/config/plugin.json
. This file contains a single JSON document, with the following top level members:
schema.json
file, and will inherit definitions from that file's columnLibrary
.reports_id
) is defined for each plugin type to simplify schema definition.The following Plugin Types are supported:
Plugin | Description | Available Since | Additional Requirements |
---|---|---|---|
assigner | Identifier Assignment Plugins | v5.0.0 MR10 | Identifier Assignment Plugins (PE) |
enroller | Enrollment Flow Plugins | Enrollment Flow Plugins (PE) | |
job | Job Plugins | v5.0.0 MR8 | Job Plugins (PE) |
provisioner | Provisioner Plugins | v5.0.0 MR9 | Provisioner Plugins (PE) |
report | Report Plugins | v5.0.0 MR7 | Report Plugins (PE) |
server | Server Plugins | v5.0.0 MR9 | Server Plugins (PE) |
source | External Identity Source Plugins | v5.0.0 MR11 | External Identity Source Plugins (PE) |
{ "types": { "report": [ "PersonStatusReports" ] }, "schema": { "tables": { "person_status_reports": { "columns": { "id": {}, "report_id": { "type": "integer", "foreignkey": { "table": "reports", "column": "id" }, "notnull": true }, "status": {} }, "indexes": { "person_status_reports_i1": { "columns": [ "report_id" ] } } } } } } |
Registry Plugins that implement both the source
and provisioner
Plugin Types are referred to as Connectors.
Plugins must implement at least one Entry Point Model for each Plugin Type declared in the types
section. Entry Point Models belongTo the Pluggable Model. For example, PersonStatusReports belongsTo Reports. Plugins may implement additional models beyond the Entry Point Model, these do not need to be registered in plugin.json
. There are no naming requirements for Entry Point Models, but it is recommended that the name references the Plugin Type (and in many cases may be the same as or similar to the plugin name).
Requirements for Entry Point Models vary by Plugin Type (see Additional Requirements By Plugin Type, below).
See also: Declaring Primary Links to Plugins
A Plugin is instantiated when an administrator creates a new instance of a Pluggable Model. As part of this process, a skeletal instance of the Entry Point Model is created, populated only with a foreign key to the Pluggable Model (AR-Plugin-9). Validation and Application Rules are not executed when this record is created. The administrator is then redirected to the edit view for the Entry Point Model (/plugin/controller/edit/#
).
If the Pluggable Model is deleted, the Entry Point Model associated with it is also deleted (AR-Plugin-10).
Plugins do not need to (and generally should not) implement add or delete actions for their Entry Point Models.
Registry PE uses the standard Cake localization mechanisms. Following convention, plugins should use the underscored version of their name as the domain for translation.
# In $PLUGIN/resources/locales/en_US/my_plugin.po msgid "welcome" msgstr "Welcome to My Plugin" # In some code print __d('my_plugin', 'welcome'); |
Plugins can also take advantage of automatic field localization in views. Whereas normally the field name filename
referenced in fields.inc
would be localized via __d('field', 'filename')
, if the plugin defines a msgid
of field.filename
in my_plugin.po
, the plugin's localization of filename
will be used when rendering the plugin's view templates. The same applies for controller
localizations.
StandardController will automatically look for view templates columns.inc
and fields.inc
for index and add/edit/view operations, respectively.
Plugins can extend StandardEnum
to define their own enumerations.
To localize the enumeration values, add entries to the localization file (defined above) following the naming convention enumeration.EnumName.key
.
To reference enumerations as automatic view variables, prefix the enumeration with the plugin name.
// $plugin/src/Lib/Enum/WidgetColorEnum.php namespace MyWidget\Lib\Enum; use App\Lib\Enum\StandardEnum; class WidgetColorEnum extends StandardEnum { const Purple = 'P'; const Fuschia = 'F'; } // $plugin/resources/locales/en_US/my_widget.po msgid "enumeration.WidgetColorEnum.F" msgstr "Fuschia" msgid "enumeration.WidgetColorEnum.P" msgstr "Purple" // $plugin/src/Model/Table/WidgetsTable.php use MyWidget\Lib\Enum\WidgetColorEnum; public function initialize(array $config): void { ... $this->setAutoViewVars([ // This will automatically populate the field "colors" in the view form with the // enumeration values 'colors' => [ 'type' => 'enum', 'class' => 'MyWidget.WidgetColorEnum' ] ]); } public function validationDefault(Validator $validator): Validator { ... $validator->add('type', [ 'color' => ['rule' => ['inList', WidgetColorEnuum::getConstValues()]] ]); } |
When Plugins allow data to be typed in inbound messages (eg: in a JSON file or SQL view), the machine readable value
of the Type should be used, not the Display Name (which is more likely to be changed) and not the type record id
(which exposes internal mechanics to upstream systems). Pipelines will automatically map value
to the foreign key necessary for maintaining internal database records.
Model-specific APIs are enabled by default via REST API v2.
Plugins may additionally implement function-oriented APIs by defining additional routes in the Plugin's config/routes.php
. By convention, Plugins should publish their APIs at /api/pluginmodel
(resulting in URLs like https://server.org/registry-pe/api/pluginmodel
). Versioning underneath this URL should be the next component, eg /api/pluginmodel/v1
unless implementing an API that imposes other requirements.
For Core and Available Plugins, be sure to commit the changes to composer.json
, vendor/composer/autoload_psr4.php
, and vendor/composer/autoload_static.php
, but not Application.php
.
Procedures for local plugins have not yet been defined (CFM-243).
If a Plugin is moved between directories (eg: from availableplugins
to plugins
) several steps are required:
composer.json
(update both autoload
and autoload-dev
).composer dumpautoload
./bin/cake cache clear_all
Plugins are activated by a Platform Administrator. Within the COmanage CO, go to Configuration > Plugins. Loading this page will refresh the Plugin Registry (AR-Plugin-11), the new Plugin should be available in the list of Plugins. Activate the Plugin via the Activate menu item. This will also apply the database schema defined in schema.json
. The database schema can manually be applied via the Apply Database Schema menu item.
A Plugin cannot be suspended if it has at least one Entry Point Model that is in use by a Configuration model (ie: referenced by a Pluggable Model that is categorized as Configuration). (AR-Plugin-8) |