I have a requirement to create triggers dynamically after a managed package is installed. I have read that the tooling API can be used to create triggers dynamically however it cannot be used in production. Is it possible to create triggers from a managed package in an org? I want to be able to create the trigger based on some user inputs.
-
4Why do you think you can't use the Tooling API in production?– Adrian Larson ♦Commented Jan 13, 2017 at 14:17
-
can't you add your triggers to managed package? Or write triggers in a sandbox with this package installed and then deploy them to prod?– NovargCommented Jan 13, 2017 at 14:19
-
Why do you need to create a new trigger? Can't you have a trigger as part of the package and let the user inputs be saved as custom settings?– martinCommented Jan 13, 2017 at 14:19
-
@martin it is not always true that trigger should be on the object, which is part of managed package. gerad26 -- you can use tooling api, as Adrian Larson said– kurunveCommented Jan 13, 2017 at 14:22
-
7DLRS does this on a configuration page (visualforce). It's open source, so you can take a peek under the hood.– sfdcfox ♦Commented Jan 13, 2017 at 14:22
1 Answer
Yes, it's possible via the SOAP API (in Enterprise production systems the Tooling API will indeed not work. It does in Dev Hub orgs and dev orgs, which makes things pretty confusing). You'll need a zip library to zip up the triggers, then create a package.xml file with ApexTrigger and (assuming you have test classes for your triggers) ApexClass Sections.
Due to the requirement to zip the files, we do that part in Javascript, using jszip, adding "files" (the strings making up the triggers and classes) with code like this:
zipFile.file('triggers/'+triggerName+'.trigger',buildTrigger(triggerName,objectName));
zipFile.file('classes/'+className+'.cls',buildClass(className,objectName));
To actually deploy the file, we are not using Javascript but rather the MetadataAPI surfaced by the Metadataservice class, generated from the SOAP API with wsdl2apex using this code:
/* create triggers and classes with zipped metadata */
public static String createNewMetadata(String zipData,List<String> allTestClasses) {
// Deploy zip file
MetadataService.MetadataPort service = MetadataService.createService();
MetadataService.DeployOptions deployOptions = new MetadataService.DeployOptions();
deployOptions.allowMissingFiles = false;
deployOptions.autoUpdatePackage = false;
deployOptions.checkOnly = false;
deployOptions.ignoreWarnings = false;
deployOptions.performRetrieve = false;
deployOptions.purgeOnDelete = false;
deployOptions.rollbackOnError = true;
deployOptions.testLevel = 'RunSpecifiedTests';
deployOptions.runTests = allTestClasses;
deployOptions.singlePackage = true;
// if its not test code deploy, otherwise return a fake ID
if (!Test.isRunningTest()) {
MetadataService.AsyncResult asyncResult = service.deploy(zipData,deployOptions);
return asyncResult.id;
}
else {
return '123';
}
}