Approval workflow how-tos
There is a lot that a developer can do with the approval workflows framework, because it was designed to give form plugin developers a lot of room for customisation.
For these how-tos, we’ll walk through an example of creating an approvalform plugin and associated workflow that allows applicants to request access to a course, with automatic enrolment if their application is approved.
We’ll call this example plugin approvalform_enrol
, the ‘Course enrolment request form’.
- 1 How to start an approvalform plugin
- 2 Create a default enrolment workflow
- 3 How to change a form label, or make it a lang string
- 4 How to add help text to form fields
- 5 How to modify form schema dynamically
- 6 How to set the application title from a form field
- 7 How to use a field value to trigger an action on event
- 8 How to capture key application data in a local table
- 9 How to trigger a transition via scheduled task
How to start an approvalform plugin
Fundamentally, approvalform plugins define the form fields and labels which are available to workflows based on them. But because they are plugins, they can also have their own front-end components, database tables, report sources, hook watchers, event observers, notifications and more.
Plugins should be placed in the server/mod/approval/form/ directory.
A minimalist approvalform plugin with the name ‘xyz' consists of the following:
form.json
- this is the JSON form schema which defines all of the available fields and sectionsversion.php
- a standardversion.php
file, with the component nameapprovalform_xyz
classes/xyz.php
- class which extends\mod_approval\model\form\approvalform_base
, can just be a stub (empty class definition)lang/en/approvalform_xyz.php
- language string for the plugin name
Install, enable, and prepare for use by workflows
Once Totara detects the new plugin and installs it via upgrade, it will need to be enabled. Go to Quick-access menu > Plugins > Approval form plugins > Manage approval form plugins and click the eye icon to enable it.
The plugin is now available when creating a new approval workflow form, which can then be used in one or more workflows. Go to Quick-access menu > Approval workflows > Manage approval forms to add a new form based on the new plugin.
Example code
To start, the approvalform_enrol
plugin consists of:
form.json
(see the JSON schema documentation for details):
{
"title": "Course enrolment request form",
"shortname": "enrol",
"revision": "Revised November 2023",
"version": "2023112400",
"language": "en",
"component": "approvalform_enrol",
"fields": [
{
"key": "course_id",
"line": "1",
"label": "Course ID",
"type": "number",
"required": true
},
{
"key": "notes",
"line": "2",
"label": "Why do you want to take this course?",
"type": "editor",
"char_length": "50",
"required": true
}
]
}
version.php
:
<?php
$plugin->version = 2023110200; // The current module version (Date: YYYYMMDDXX).
$plugin->requires = 2023110200; // Requires this Totara version.
$plugin->component = 'approvalform_enrol'; // To check on upgrade, that module sits in correct place
classes/enrol.php
:
<?php
namespace approvalform_enrol;
use mod_approval\model\form\approvalform_base;
/**
* Class enrol provides an interface to the approvalform_enrol sub-plugin.
*
* @package approvalform_simple
*/
class enrol extends approvalform_base {
// Stub
}
lang/en/approvalform_enrol.php
:
Create a default enrolment workflow
To create a default enrolment workflow, run this PHP script in your directory roots:
How to change a form label, or make it a lang string
If the label for a form field is not quite right, you have two options for changing it:
Hard-coded change to the
form.json
schemaUse a language string key as the label, by changing it to
<key>_label
, where<key>
is the language string key.
The hard-coded approach is simple, but requires a developer if it needs to be changed in future. It also only supports forms in a single language.
Using a language string key as the label allows the label to be translated into multiple languages, and allows admins to change the label themselves by editing the language string.
Help text can also be a language string - see the How to add help text to form fields.
In either case, once the form schema has been changed, its internal version number needs to be increased. Any approval forms based on the plugin will then need to be refreshed to pick up the new schema.
Example code
Updated form.json
and language string definitions to use language strings for form labels.
form.json
updated:
lang/en/approvalform_enrol.php
updated:
How to add help text to form fields
There are multiple options for adding help text to a form field (help text appears when the i icon is clicked).
Hard-coded change to the
form.json
schema, add a 'help' property to any field.Use a language string key as the help text, by changing it to
<key>_help
, where<key>
is the language string key.Use the
help_html
property instead, when you need to include HTML markup. Normally help text is plain text, and special characters are escaped.
As always, once the form schema has been changed, its internal version number needs to be increased. Any approval forms based on the plugin will then need to be refreshed to pick up the new schema.
Example code
form.json
updated:
lang/en/approvalform_enrol.php
updated:
How to modify form schema dynamically
If you need to modify the form schema before it is sent to the front end to be rendered, for example to control the range of years in a date picker, or the set of available choices in a select field, you can do that by implementing adjust_form_schema_for_application()
in your approvalform class.
This is used internally to adjust editor fields for the current user, so ensure that you call parent::adjust_form_schema_for_application()
at some point in your implementation.
Pseudo-code:
The form_schema in $form_schema
will be a subset of the form.json
schema, made up of the collection of form_views configured for the workflow at the current stage – hence the need for the conditional that checks whether the schema has the desired field.
Example code
We need to get the course ID from a $_GET
var, so that the applicant doesn’t have to fill it in themselves.
classes/enrol.php
updated:
How to set the application title from a form field
Similar to how an approvalform plugin can modify form schema dynamically, it can also modify the application data (the form response), by implementing observe_form_data_for_application()
in your approvalform class.
Note that observe_form_data_for_application()
gets called whenever application data is processed - both on the way into the database (when posted by the applicant) and on the way out to the page (when the submitted application is viewed). Care should be taken to only execute actions once, and only when they need to be actioned.
Example code
We want to give each application the same name as the requested course.
classes/enrol.php
updated:
How to use a field value to trigger an action on event
Very often as an application moves through a workflow, we want to make something happen in the system. Currently this is only possible by observing an application event, or writing a scheduled task that looks for applications in a particular state.
Available application events include:
Application completed -
mod_approval\event\application_completed
Existing approvals invalidated due to rejection or withdrawal -
mod_approval\event\approvals_invalidated
Application approved -
mod_approval\event\level_approved
Application rejected -
mod_approval\event\level_rejected
Application entered new level -
mod_approval\event\level_started
Application fully-approved at stage -
mod_approval\event\stage_all_approved
Application ended current stage -
mod_approval\event\stage_ended
Application entered new stage -
mod_approval\event\stage_started
Application submitted -
mod_approval\event\stage_submitted
Application withdrawn -
mod_approval\event\stage_withdrawn
The Application completed event does not imply anything about whether the application was approved or not. It is triggered any time an application enters an ‘end' stage and cannot progress any further. Use Application fully-approved at stage to respond to approval.
As with all Totara events, care must be taken to ensure that you are only observing the particular events you want to observe. The event object ID is the application ID, and from there you can use the application model to discover the overall context of the application.
Event observer pseudo-code:
Note that detecting true application state can be tricky with advanced workflow configurations. This is because of the configurability of workflows:
An application can reach an end state (i.e. be 'completed') on any transition, including form submission
You may need to do something at a particular stage, but stage names are admin-editable
You may need to check a particular form field value, but the admin can configure the workflow so that the field is not required, or not even available
Please contact Totara Support if you have particular issues with detecting application state, or suggestions for improvement.
Example code
Our example approvalform plugin needs to enrol the applicant on their selected course once the application is approved at all levels.
Note that we’re just using manual enrolments here for simplicity. Ideally we would create an enrolment plugin specifically for use with approvalform_enrol
-based workflows.
db/event.php
:
classes/observer/application_event.php
:
How to capture key application data in a local table
Approval workflows response data is stored as a JSON blob, so it can be difficult to access, filter, or sort applications based on the answers to specific form fields.
To solve this problem, approvalform plugins can create their own responses table, with fields for application_id and any form keys they wish to access or report on. Then use \approvalform_base::observe_form_data_for_application()
to save the tracked form response fields to the table.
Once application response fields are stored in a table, it can be used in report sources and business logic to supplement the information in the ttr_approval_application
table.
Example code
Our enrolment workflow needs to track the course_id provided by each application.
db/install.xml
:
classes\entity\response.php
:
classes\enrol.php
updated:
How to trigger a transition via scheduled task
Some workflows require time to pass before the application transitions to a new stage. This can be accomplished with a 'waiting' stage, and a scheduled task that makes the transition occur when a condition is met.
Or perhaps you want to automatically transition applications to an 'abandoned' end state after a certain amount of time, or if an approval deadline passes. Again, this is accomplished with a scheduled task.
Task pseudo-code:
Loading the correct applications is made much easier if response fields or other metadata is tracked in a local database table, as described in the How to capture key application data in a local table section.
Example code
For our course enrolment use case, we want to automatically withdraw applications that have not been completed before the course start date is reached.
lang/en/approvalform_enrol.php
updated:
db/tasks.php
:
classes\task\withdraw_late_applications.php
:
Â