How to package SearchKit Displays in an extension
Ship an extension with SearchKit-based tabs for the Contact Summary screen.
Using a Search Display as a contact summary tab requires 3 interconnected entities:
- A SavedSearch containing the api params for the search.
- A SearchDisplay linked to the
SavedSearchby id (
saved_search_id = $savedSearch.id).
- An Afform linked to both the
SearchDisplayby name (via embedded tag).
1. The Status Quo
Afforms can already be packaged as
.aff.html/.aff.json files, and the Afform API & GUI have excellent handling for packaged Afforms to be overridden and reverted by site admins. If an extension upgrade provides updates to a packaged Afform, overrides will not be affected but the default version will be upgraded automatically.
DAO-based entities like
SearchDisplay can be packaged as
.mgd.php files which will be added to the database via
hook_civicrm_managed. However, the
CRM_Core_ManagedEntities system doesn't provide any way for admins to override and then revert back to the packaged version, nor to reconcile potentially overridden entities with new packaged versions during extension upgrades. There are also an issue where the system doesn't guerantee write order, and in this case we need it to write the
SavedSearch prior to the
SearchDisplay, which contains a foreign key to the former.
Currently there is a workaround using chaining and
'update' = 'never', for example as used by the Deduper Extension.
CRM_Core_ManagedEntities offers us 2 modes for packaging
SearchDisplay entities, neither is ideal:
'update' = 'always'will essentially lock the entities. Any changes to the search made by the site admin will be overwritten on a regular basis. This solves the extension upgrade problem at the cost of configurability.
'update' = 'never'will drop the entities into the database and then never touch them again. This is the lesser of two evils because at least this way they are configurable.
The bottom line: The status quo allows us to package searches and displays. They will be user-configurable but not revertable (if the admin makes a mess of them, he'd have to delete them all and then uninstall/reinstall the extension). During extension upgrades, the packaged Afforms will update, but changes to
.mgd.php files will do nothing unless the extension is uninstalled, searches are deleted, and then it's reinstalled.
2. Create APIv4
This would do something like the
Afform APIv4 entity: read from the database and also from json files. This would need to be opt-in on a per-entity basis (starting with
SearchDisplay) and would be mostly for configuration entities, as a file/DB hybrid would not be able to perform joins in the GET action.
- Add an APIv4 trait
SearchDisplayto use that trait
- Add a specialized
getaction which would read from json files and the database.
- Add calculated fields comparable to Afform's
- Would give excellent feature parity with Afform's packaged systems.
- Reverting and upgrades would be simple.
- Involves extra file i/o and directory scanning with each
get- feasible with hundreds of records but not many thousands.
- Restricted to APIv4 as the packaged entities wouldn't exist as far as the DAO is concerned.
- Entities have to opt-in (whereas
mgdworks on any entity).
- Retrofitting an existing API over would involve a slight BC breakage as the new
getmethod would be missing
Make the manager aware of whether a record has been manually updated. Add a new
'update' = 'auto' mode which would intelligently push updates from
.mgd.php only to untouched records. Add a way to revert a record.
- Add an
is_overriddencolumn to the
- Add some type of trigger to set that column when manual changes are made to a managed entity.
- Add some type of
Revertapi action (currently the
Managedclass doesn't even have an API so this will take some thought).
- Add a way to know if a database record has a corresponding managed entry (maybe a calculated field or maybe a DFK join - both would be slightly tricky).
- Fully backward compatible with existing entities.
- Improves the existing "Managed" system instead of inventing a new one.
- Wouldn't be a drag on performance.
- Might be a lot of work.