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 esta sub-lección
- 01Separar el CUÁNDO (el trigger) del QUÉ (la clase handler).
- 02Escribir un handler con un método por evento y pasarle Trigger.new desde el trigger.
- 03Saber por qué la clase no debe leer Trigger.new por su cuenta.
- 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.
- Salesforce guarda
- CaseTrigger
- CaseTriggerHandler
// Data Loader inserta 200 casosPaso 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.
La nutria: El Start y el lienzo
Anatomía: un trigger delgado y su handler
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) { /* … */ }
}| Evento | Método del handler | Qué le pasa el trigger |
|---|---|---|
| BEFORE_INSERT | beforeInsert | Trigger.new |
| BEFORE_UPDATE | beforeUpdate | Trigger.new, Trigger.oldMap |
| AFTER_INSERT | afterInsert | Trigger.new (ya con Id) |
| AFTER_UPDATE | afterUpdate | Trigger.new, Trigger.oldMap |
| BEFORE_DELETE / AFTER_DELETE | beforeDelete / afterDelete | Trigger.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