Skip to main content
fusionCore routes all Apex trigger logic through a single, metadata-driven framework that lives in the Platform package under the FCORE_BASE namespace. Instead of writing logic in trigger files, you write small handler classes — trigger units — and register each one against an object through Custom Metadata. The framework decides which units run, in what order, and whether to run at all. This design gives you a few things for free:
  • A single, predictable execution path for every object’s automation.
  • Per-object, per-handler, per-user, and org-wide on/off switches without code changes.
  • A clean separation between automation logic and validation logic.
The framework dispatches events as part of trigger execution. For the publish/subscribe layer that runs alongside it, see Event Framework. For shared helpers referenced below, see Utility Functions.

Writing a Trigger

A trigger file contains exactly one line. It constructs a FCORE_BASE.TriggerExecutor for the object’s SObjectType and calls execute(). Never put logic in the trigger file itself — the executor delegates to your registered trigger units.
FCORE_BASE.TriggerExecutor exposes:
  • TriggerExecutor(SObjectType) — constructor; pass the object’s SObjectType.
  • execute() — runs every enabled trigger unit registered for that object, in order, for the current trigger context.
Wire up all the trigger contexts your registered units might use. The executor only invokes the contexts each unit overrides, so listing every context in the trigger signature is safe and keeps future units from being silently skipped.

Writing a Trigger Unit

A trigger unit is an Apex class that extends the abstract class FCORE_BASE.TriggerUnit. By convention its name ends in TU. Override only the contexts your unit needs — every context method is a global virtual void with an empty default implementation.

Available Contexts

Use bulkBefore() and bulkAfter() to do shared, query-once setup (for example, loading related records) that the per-context methods then consume — this keeps your unit bulk-safe.
Keep each trigger unit focused on one concern. Several small units on one object are easier to order, test, and disable independently than one large unit that handles every context.

Registering a Trigger Unit

Registration uses two Custom Metadata types. When you reference them from Apex or in metadata files, the API names carry the FCORE_BASE__ namespace prefix.

FCORE_BASE__Trigger__mdt — one record per object

This record enables the framework for an object and is the anchor that trigger units link to.

FCORE_BASE__Trigger_Unit__mdt — one record per handler

This record registers a single trigger unit class against an object’s Trigger__mdt record. A Trigger_Unit__mdt record looks like this:

Ordering

Trigger units for one object run in ascending FCORE_BASE__Order__c — a unit with Order 10 runs before a unit with Order 20. Leave gaps between values (10, 20, 30, …) so you can slot a new unit between two existing ones later without renumbering everything.

Turning Triggers Off

Bypass is layered. Each layer is independent, and the framework checks them in this sequence — any one of them stops a unit from running:

Disabling for the Current Transaction

FCORE_BASE.TriggerExecutor.TRIGGER_CONTEXT is a TriggerContext you can use to suppress automation programmatically — for example, around a data fix in an anonymous block or a one-off script. These changes apply only to the current transaction; re-enable as soon as the protected DML is done.
TRIGGER_CONTEXT exposes these methods, each taking a String:
  • disableSObject(String) / enableSObject(String) — toggle every unit for one object.
  • disableClass(String) / enableClass(String) — toggle one unit by class name.
  • disableValidations() / enableValidations() — toggle validation units as a group (see below).

Validation Triggers

Validation-only logic belongs in its own kind of unit. A validation unit extends FCORE_BASE.ValidationTriggerUnit — an abstract subclass of TriggerUnit — and registers through the same Trigger_Unit__mdt records as any other unit. By convention its name ends in VTU. Keeping validations in their own units means you can switch them off as a group without touching the automation units that should keep running.
  • Metadata gate: FCORE_BASE__Org_Setting__mdt.Global_Validations_Enabled__c — when false, every ValidationTriggerUnit is skipped.
  • Runtime gate: FCORE_BASE.TriggerExecutor.TRIGGER_CONTEXT.disableValidations() / enableValidations() — suppress validation units for the current transaction (for example, during a data migration).
A validation unit raises its errors with the shared validation helpers rather than calling addError() directly:
Because this logic lives in a ValidationTriggerUnit, both Global_Validations_Enabled__c and disableValidations() skip it automatically — you do not need to add your own enabled check. See Utility Functions for the full set of ValidationUtils helpers.

Prefer a Validation Trigger Unit Over a Declarative Validation Rule

When you need new validation logic, build it as a ValidationTriggerUnit rather than a declarative Salesforce Validation Rule. A validation trigger unit gives you two things a Validation Rule cannot:
  • OrderingFCORE_BASE__Trigger_Unit__mdt.FCORE_BASE__Order__c positions your validation relative to every other trigger unit on the object, including other validations.
  • Programmatic disableFCORE_BASE.TriggerExecutor.TRIGGER_CONTEXT.disableValidations() and the per-handler FCORE_BASE__Trigger_Unit__mdt.FCORE_BASE__Is_Enabled__c field can turn the check off for a single transaction or a single handler, without a metadata deployment.
A declarative Validation Rule only has its own Active checkbox — it cannot be reordered against other automation, and disabling it for one transaction (for example, during a data migration) means deactivating it org-wide first.

Gating a Declarative Validation Rule

If a declarative Validation Rule is still the right tool — for example, a simple field check on a standard object with no accompanying Apex — gate it on Global_Validations_Enabled__c too, so it can be disabled the same way as validation trigger units. Every validation rule shipped with fusionCore follows this pattern (for example PricebookEntry.Block_Standard_Price_Change). Add the gate as another AND condition if your formula already uses the AND() function:
Or with the && operator if your formula is written with infix logic:
Unlike a ValidationTriggerUnit, a declarative Validation Rule does not gate on Global_Validations_Enabled__c automatically — you must add the condition yourself. The flag also only gates the rule at runtime; it has no effect on ordering. If ordering matters, build the check as a ValidationTriggerUnit instead.