Apex Academy
Módulo 7·02·34 min

El patrón Handler

El trigger se queda con una sola tarea (decir QUÉ evento es) y todo lo demás se muda a una clase. Es el patrón que encontrarás en casi cualquier org profesional.

En Admin esEl elemento Start de un Record-Triggered Flow frente a su lienzo

✓ En esta sub-lección

  1. 01Separar el CUÁNDO (el trigger) del QUÉ (la clase handler).
  2. 02Escribir un handler con un método por evento y pasarle Trigger.new desde el trigger.
  3. 03Saber por qué la clase no debe leer Trigger.new por su cuenta.
  4. 04Reconocer este patrón en los frameworks que usan las orgs reales.

La nutria: ¿Te acuerdas? · Repaso de la lección 1

¿Cómo decide CaseTrigger en qué evento está?

Tras la tarea 1 tienes un trigger que funciona y en el orden correcto, pero con dos reglas mezcladas en el mismo archivo. La idea del es sencilla: el trigger solo dice CUÁNDO (qué evento está pasando) y una clase dice QUÉ se hace. Así el trigger cabe en una pantalla aunque el objeto tenga veinte reglas.

  1. Salesforce guarda
  2. CaseTrigger
  3. CaseTriggerHandler
// Data Loader inserta 200 casos

Paso 1 de 7

Una carga de 200 casos llega a la base de datos. Antes de guardarlos, Salesforce dispara los triggers before insert del objeto Case.

Una carga de 200 casos, de la base de datos al trigger y del trigger al handler, en before y en after.

La nutria: El Start y el lienzo

Así me lo explico yo: un Record-Triggered Flow tiene dos partes, el elemento Start, donde eliges objeto, si se dispara al crear o al editar y si es antes o después de guardar; y el lienzo, donde van las decisiones y las acciones. El trigger delgado es el Start: objeto y eventos. El handler es el lienzo: la lógica. Nadie mete las decisiones dentro del Start.

Anatomía: un trigger delgado y su handler

Apex
trigger AccountTrigger on Account (before insert, before update, after update) {
    AccountTriggerHandler handler = new AccountTriggerHandler();
    switch on Trigger.operationType {
        when BEFORE_INSERT { handler.beforeInsert(Trigger.new); }
        when BEFORE_UPDATE { handler.beforeUpdate(Trigger.new, Trigger.oldMap); }
        when AFTER_UPDATE  { handler.afterUpdate(Trigger.new, Trigger.oldMap); }
    }
}

public with sharing class AccountTriggerHandler {
    public void beforeInsert(List<Account> newAccounts) { /* … */ }
    public void beforeUpdate(List<Account> newAccounts, Map<Id, Account> oldMap) { /* … */ }
    public void afterUpdate(List<Account> newAccounts, Map<Id, Account> oldMap) { /* … */ }
}
Un método por evento, con un nombre que dice cuál. Los de update reciben también oldMap, para poder comparar (Módulo 6).
EventoMétodo del handlerQué le pasa el trigger
BEFORE_INSERTbeforeInsertTrigger.new
BEFORE_UPDATEbeforeUpdateTrigger.new, Trigger.oldMap
AFTER_INSERTafterInsertTrigger.new (ya con Id)
AFTER_UPDATEafterUpdateTrigger.new, Trigger.oldMap
BEFORE_DELETE / AFTER_DELETEbeforeDelete / afterDeleteTrigger.old, Trigger.oldMap

Por qué se le pasa Trigger.new, en vez de que lo lea la clase

Dentro del trigger CaseTrigger, Trigger.new ya es una List<Case>: la plataforma sabe de qué objeto es. Dentro de una clase cualquiera, en cambio, Trigger.new es una lista genérica de sObject, y habría que convertirla con (List<Case>) Trigger.new como viste en el Módulo 1. Pero el motivo de fondo no es el casting: una clase que lee Trigger.new solo funciona dentro de un trigger. Una clase que recibe una List<Case> funciona con cualquier lista de casos: la de un trigger, la de una consulta o la que fabriques en una clase de test (Módulo 10).

Nombres que se reconocen de un vistazo

La convención más extendida: el trigger se llama como el objeto más Trigger (CaseTrigger, AccountTrigger) y su clase, igual más Handler (CaseTriggerHandler). Parece un detalle, pero es lo que permite que otra persona abra una org que no conoce y encuentre en segundos dónde vive la lógica de Case.

La nutria: Simplificación: with sharing

Verás public with sharing class en todos los ejemplos, y yo tampoco lo entendí del todo al principio. De momento tómalo como «la forma correcta de declarar una clase que toca datos»: significa que la clase respeta las reglas de uso compartido del usuario, igual que un informe solo le enseña lo que puede ver. El Módulo 12 lo explica a fondo y cuándo se usa otra cosa.