Skip to content

APIv4 Managed Entities


When writing an extension, it's often necessary to insert data when the extension is enabled, for example menu items, or custom fields or option values all might need to be added for the extension to function. Extensions may also want to ship with preconfigured SearchKit Displays.

You'd want these items to be added when the extension is installed, disabled when the extension is disabled, and deleted when the extension is uninstalled. In some cases you'd also want to allow the end-user to make changes, e.g. adjusting settings for a search display, but allow them to revert it back to the original state defined by your extension. In other cases, e.g. a reserved option value, you want the user to be locked out of editing or deleting it, but you do want changes made in your extension code to update the record in the database, e.g. if you later add a description to the option value record.

All this is easy to do with APIv4 Managed Entities.

Managed Entities are tracked in a table in CiviCRM called civicrm_managed. You can use APIv4 to get records from this table if you want to see what is in there (or make sure your entity has been added) and use the APIv4 reconcile action to have the list of declared entities compared against what is present in the civicrm_managed table - any that are missing will be created and depending on your update mode and cleanup mode they may be updated or deleted if the declaration has changed. Note that you can declare Managed Entities using APIv4 or APIv3 but APIv4 is more robust as it can handle the situation where a similar record already exists.

Creating a Managed Record

The recommended way to package and distribute managed records is using the civix export command:

  1. Create the record(s) you want in CiviCRM (on a live site, or preferably on a demo or test installation).
  2. On the command line, cd path/to/your/extension, then civix export EntityName id. (To get the ID of the entity, either look at the URL, look it up in the database, or list it in the API4 explorer.)
  3. This will generate a .mgd.php file in your extension's managed directory (or when exporting Afforms, .aff.* files in the ang directory).
  4. Afterwards you can optionally adjust the update and cleanup settings in the generated file (see below).

Example: To export a saved search with all its related search displays and Afforms:

civix export SavedSearch 12
Example: To export an Afform, including its definition and layout files:
civix export Afform nameOfMyForm

Type civix export -h for more info about the command.

Note that the API4 explorer can also be used to export managed records, but should only be used if you are already quite familiar with the managed files structure.

Update Modes

This setting determines whether a managed record will be auto-updated after it is intalled. This is important to consider if the values in your mgd.php record might ever change in future updates to your extension.

  • always: Forcibly overwrite record with values from the .mgd.php definition with every cache-flush.
  • never: Once installed, the record will never be updated.
  • unmodified: Updates to the .mgd.php will be propigated only if the record has not been updated by the user.

In general, always is a good choice for records which are not meant to be updated by the user, such as reserved OptionValues. In most other cases, unmodified is the best trade-off between allowing edits to be made by the user, and propidating updates when changes are made to the .mgd.php in new versions of the extension. Changes made by the user can be undone by the revert API action.

Cleanup Modes

This setting determines whether a managed record will be deleted when the extension is uninstalled.

  • always: Unconditionally delete the record when the extension is uninstalled.
  • never: Once installed, the record will never be auto-deleted.
  • unused: Determines whether any references to the record exist (e.g. if the record is an Acitity Type, do any activities exist of that type?), and only delete it if not.

Handling possibly existing records

Normally, if the Managed system tries to add a record which already exists, it causes an error. However, sometimes an extension author isn't sure if the item they want to distribute already exists. For example, the 1.0 release of an extension may have used hook_civicrm_install to add an OptionValue. In the 2.0 release, it's decided to move it into a mgd.php file - what to do about existing sites which have already installed the OptionValue?

The solution is to add match to the params array, declaring which fields should be compared to see if a record exists before creating a new one. The civix export command automatically adds the relevant matches for an entity. For example, an OptionValue will need to match on name, value and option_group_id. A CustomField will need to match on name and custom_group_id. Without adequate parameters, the Managed system can get confused between similar entities across different parent entities. Such as OptionValue entities with the same value in different OptionGroup entities.