diff --git a/docs/api/v4/actions.md b/docs/api/v4/actions.md index 9a593b5ae03473609d77cfc6d8c19f5766ff5850..84f3532832ce01e5afc7af71872852e7bb08094b 100644 --- a/docs/api/v4/actions.md +++ b/docs/api/v4/actions.md @@ -31,6 +31,10 @@ along with some _metadata_ actions to retrieve information about the structure o Search for records based on query parameters. For most entities, `get` includes advanced features such as [joins](explicit-joins.md). +* **`export`** + + Available only for [Managed Entity](managed.md) types, outputs code which can be used to package and distribute a record in an extension. + ## Write Actions * **`create`** @@ -39,11 +43,13 @@ along with some _metadata_ actions to retrieve information about the structure o * **`update`** - Update one or more existing records with new values. + Update one or more existing records with new values. If an `id` is not supplied, then query params are required to search for records to update. * **`save`** - Save an array of records. For each one, the presence of an `id` determines whether an existing record will be updated. + Given an array of records, either `create` or `update` each one. By default the presence of an `id` determines whether an existing record will be updated. + The `match` param gives finer control over this, and lets you specify one or more fields; if a single existing record matches *all* of them, it will be updated instead of a new record created. For example you can `save` an array of contacts and specify + `['external_id']` as the `match` param, which will update contacts with matching `external_id`s. * **`delete`** @@ -51,11 +57,15 @@ along with some _metadata_ actions to retrieve information about the structure o * **`replace`** - Replace an existing set of records with a new or modified set of records. For example, replace a group of "Phone" numbers for a given contact. + Replace an existing set of records with a new or modified set of records. For example, replace a group of `Phone` numbers for a given `Contact`. !!! warning Replace includes an implicit delete action - use with care & test well before using in production. +* **`revert`** + + Available only for [Managed Entity](managed.md) types, resets a record to its original packaged state. + diff --git a/docs/api/v4/managed.md b/docs/api/v4/managed.md new file mode 100644 index 0000000000000000000000000000000000000000..e1498688d16374768c365c1c80b68b12bbd66ba3 --- /dev/null +++ b/docs/api/v4/managed.md @@ -0,0 +1,63 @@ +# APIv4 Managed Entities + +## Introduction + +When [writing an extension](../../extensions/index.md), 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. + +## 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`](actions.md#write-actions) 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`](../../hooks/hook_civicrm_install.md) +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`](actions.md#write-actions) to the `params` array, declaring which fields should be compared to +see if a record exists before creating a new one. diff --git a/mkdocs.yml b/mkdocs.yml index 3d5f3f637e39438ecba8bd19f74e88ec9b42167d..dba8e7c6579512a93826fa75ffaab5cc593c8c5e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -104,6 +104,7 @@ nav: - Option Lists: api/v4/pseudoconstants.md - Chaining: api/v4/chaining.md - Custom Data: api/v4/custom-data.md + - Managed APIv4 Entities: api/v4/managed.md - Differences Between Api v3 and v4: api/v4/differences-with-v3.md - APIv4 Architecture: api/v4/architecture.md - APIv4 Changelog: api/v4/changes.md