@@ -138,6 +138,11 @@ public virtual with sharing class fflib_SObjectDomain
138138 **/
139139 public virtual void onAfterDelete () { }
140140
141+ /**
142+ * Override this to perform processing during the after undelete phase, this is called by the handleAfterDelete method
143+ **/
144+ public virtual void onAfterUndelete () { }
145+
141146 /**
142147 * Base handler for the Apex Trigger event Before Insert, calls the onApplyDefaults method, followed by onBeforeInsert
143148 **/
@@ -206,6 +211,19 @@ public virtual with sharing class fflib_SObjectDomain
206211 onAfterDelete ();
207212 }
208213
214+ /**
215+ * Base handler for the Apex Trigger event After Undelete, checks object security and calls the onAfterUndelete method
216+ *
217+ * @throws DomainException if the current user context is not able to delete records
218+ **/
219+ public void handleAfterUndelete ()
220+ {
221+ if (Configuration .EnforcingTriggerCRUDSecurity && ! SObjectDescribe .isCreateable ())
222+ throw new DomainException (' Permission to create an ' + SObjectDescribe .getName () + ' denied.' );
223+
224+ onAfterUndelete ();
225+ }
226+
209227 /**
210228 * Returns the SObjectType this Domain class represents
211229 **/
@@ -274,6 +292,7 @@ public virtual with sharing class fflib_SObjectDomain
274292 Trigger .isInsert ,
275293 Trigger .isUpdate ,
276294 Trigger .isDelete ,
295+ Trigger .isUnDelete ,
277296 Trigger .new ,
278297 Trigger .oldMap );
279298 }
@@ -282,7 +301,7 @@ public virtual with sharing class fflib_SObjectDomain
282301 /**
283302 * Calls the applicable override methods such as beforeInsert, beforeUpdate etc. based on a Trigger context
284303 **/
285- private static void triggerHandler (Type domainClass , Boolean isBefore , Boolean isAfter , Boolean isInsert , Boolean isUpdate , Boolean isDelete , List <SObject > newRecords , Map <Id , SObject > oldRecordsMap )
304+ private static void triggerHandler (Type domainClass , Boolean isBefore , Boolean isAfter , Boolean isInsert , Boolean isUpdate , Boolean isDelete , Boolean isUndelete , List <SObject > newRecords , Map <Id , SObject > oldRecordsMap )
286305 {
287306 // After phase of trigger will reuse prior instance of domain class if ITriggerStateful implemented
288307 fflib_SObjectDomain domainObject = isBefore ? null : popTriggerInstance (domainClass , isDelete ? oldRecordsMap .values () : newRecords );
@@ -297,6 +316,7 @@ public virtual with sharing class fflib_SObjectDomain
297316 if (isInsert ) domainObject = domainConstructor .construct (newRecords );
298317 else if (isUpdate ) domainObject = domainConstructor .construct (newRecords );
299318 else if (isDelete ) domainObject = domainConstructor .construct (oldRecordsMap .values ());
319+ else if (isUndelete ) domainObject = domainConstructor .construct (newRecords );
300320
301321 // Should this instance be reused on the next trigger invocation?
302322 if (domainObject .Configuration .TriggerStateEnabled )
@@ -316,6 +336,7 @@ public virtual with sharing class fflib_SObjectDomain
316336 if (isInsert ) domainObject .handleAfterInsert ();
317337 else if (isUpdate ) domainObject .handleAfterUpdate (oldRecordsMap );
318338 else if (isDelete ) domainObject .handleAfterDelete ();
339+ else if (isUndelete ) domainObject .handleAfterUndelete ();
319340 }
320341 }
321342
@@ -560,6 +581,7 @@ public virtual with sharing class fflib_SObjectDomain
560581 private Boolean isInsert = false ;
561582 private Boolean isUpdate = false ;
562583 private Boolean isDelete = false ;
584+ private Boolean isUndelete = false ;
563585 private List <SObject > records = new List <SObject >();
564586 private Map <Id , SObject > oldRecords = new Map <Id , SObject >();
565587
@@ -571,17 +593,18 @@ public virtual with sharing class fflib_SObjectDomain
571593 private void testTriggerHandler (Type domainClass )
572594 {
573595 // Mock Before
574- triggerHandler (domainClass , true , false , isInsert , isUpdate , isDelete , records , oldRecords );
596+ triggerHandler (domainClass , true , false , isInsert , isUpdate , isDelete , isUndelete , records , oldRecords );
575597
576598 // Mock After
577- triggerHandler (domainClass , false , true , isInsert , isUpdate , isDelete , records , oldRecords );
599+ triggerHandler (domainClass , false , true , isInsert , isUpdate , isDelete , isUndelete , records , oldRecords );
578600 }
579601
580602 public void onInsert (List <SObject > records )
581603 {
582604 this .isInsert = true ;
583605 this .isUpdate = false ;
584606 this .isDelete = false ;
607+ this .isUndelete = false ;
585608 this .records = records ;
586609 }
587610
@@ -591,6 +614,7 @@ public virtual with sharing class fflib_SObjectDomain
591614 this .isUpdate = true ;
592615 this .isDelete = false ;
593616 this .records = records ;
617+ this .isUndelete = false ;
594618 this .oldRecords = oldRecords ;
595619 }
596620
@@ -599,9 +623,19 @@ public virtual with sharing class fflib_SObjectDomain
599623 this .isInsert = false ;
600624 this .isUpdate = false ;
601625 this .isDelete = true ;
626+ this .isUndelete = false ;
602627 this .oldRecords = records ;
603628 }
604629
630+ public void onUndelete (List <SObject > records )
631+ {
632+ this .isInsert = false ;
633+ this .isUpdate = false ;
634+ this .isDelete = false ;
635+ this .isUndelete = true ;
636+ this .records = records ;
637+ }
638+
605639 public Boolean hasRecords ()
606640 {
607641 return records != null && records .size ()> 0 || oldRecords != null && oldRecords .size ()> 0 ;
@@ -676,6 +710,12 @@ public virtual with sharing class fflib_SObjectDomain
676710 }
677711 }
678712
713+ public override void onAfterUndelete ()
714+ {
715+ // Not required in production code
716+ super .onAfterUndelete ();
717+ }
718+
679719 public override void onBeforeInsert ()
680720 {
681721 // Assert this variable is null in the after insert (since this domain class is stateless)
0 commit comments