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 easiest way to package and distribute managed records is using the APIv4 Export action:

  1. Create the record(s) you want in CiviCRM (on a live site, or preferably on a demo or test installation).
  2. Visit the APIv4 Explorer, select the entity type and the Export action.
  3. Enter the id of your record.
  4. Set update and cleanup modes as desired (see below).
  5. Click the Execute button.
  6. In the Result panel, select View as PHP, select and click the "Copy" button.
  7. In your extension, create a managed directory if one doesn't already exist.
  8. Create a new file in the managed directory with the suffix .mgd.php (the name of the file should help you remember what's in it, a good practice is to use the name output by the API Export).
  9. Begin the file with the line <?php and paste the contents from the Export action.

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.