### Basic Usage of PortalUsers Domain Class in Salesforce Source: https://fflib.dev/docs/domain-layer/example Demonstrates how to instantiate and use the IPortalUsers interface to call the validateUserSso method. It shows examples of validating an existing list of portal users and a new list. ```apex List portalUsers = new List(); IPortalUsers iPortalUsers = (IPortalUsers) Application.Domain.newInstance( portalUsers ); // use the existing list of portalUsers that was passed to the domain class on initialisation Map validatedUsersBySsoId = iPortalUsers.validateUserSso(); // use a new list of portalUsers List portalUsersNew = new List(); Map validatedUsersBySsoId = iPortalUsers.validateUserSso(portalUsersNew); ``` -------------------------------- ### Basic Usage of PortalUser Selector Source: https://fflib.dev/docs/selector-layer/example Demonstrates how to instantiate the IPortalUserSelector and use its selectById method to retrieve PortalUser__c records by their IDs. This example assumes the selector has been properly configured via custom metadata. ```apex /* PortalUserService.cls */ IPortalUserSelector portalUserSelector = (IPortalUserSelector)Application.Selector.newInstance( PortalUser__c.SObjectType ); List portalUsers = portalUserSelector.selectById( new Set{'SF_RECORD_ID'} ); ``` -------------------------------- ### Basic Trigger Handler Setup in Apex Source: https://fflib.dev/docs/triggers This Apex code demonstrates the basic setup for an fflib trigger handler. It defines a trigger for the PortalUser__c sObject and delegates the trigger logic to the PortalUsers.class domain handler. This ensures that trigger execution is managed by the corresponding domain class. ```apex trigger PortalUserTrigger on PortalUser__c (before insert, before update) { fflib_SObjectDomain.triggerHandler(PortalUsers.class); } ``` -------------------------------- ### Basic Usage of Apex Service Source: https://fflib.dev/docs/service-layer/example Shows how to instantiate and use the CommunityPortalService. It demonstrates calling methods to retrieve all portal users and check if a user is logged in. ```Apex ICommunityPortalService communityPortalService = (ICommunityPortalService) Application.Service.newInstance( ICommunityPortalService.class ); // example usage via a Selector class List allPortalUsers = communityPortalService.getAllPortalUsers(); // example usage via a Domain Class Boolean isUserLoggedIn = communityPortalService.isUserLoggedIn(UserInfo.getUserId()); ``` -------------------------------- ### Create PortalUsers Domain Class in Salesforce Apex Source: https://fflib.dev/docs/domain-layer/example Implements the IPortalUsers interface and extends ApplicationSObjectDomain to create the PortalUsers domain class. It includes boilerplate code for instantiation, trigger handler methods for validation, and domain methods for SSO validation. ```apex public inherited sharing class PortalUsers extends ApplicationSObjectDomain implements IPortalUsers { // 1. Boilerplate code public static IPortalUsers newInstance(List records) { return (IPortalUsers) Application.Domain.newInstance(records); } public static IPortalUsers newInstance(Set recordIds) { return (IPortalUsers) Application.Domain.newInstance(recordIds); } public PortalUsers(List records) { super(records); } public class Constructor implements fflib_SObjectDomain.IConstructable { public fflib_SObjectDomain construct(List sObjectList) { return new PortalUsers(sObjectList); } } // 2. Trigger methods public override void onBeforeInsert() { this.validateUserSso(getRecords()); } public override void onBeforeUpdate(Map existingRecords) { this.validateUserSso(getChangedRecords(new Set{ 'SSOId__c' })); } // 3. Domain methods public Map validateUserSso() { validateUserSso((List)getRecords()); } public Map validateUserSso(List portalUsers) { // run sso validation here } } ``` -------------------------------- ### Implement PortalUserSelector Class Source: https://fflib.dev/docs/selector-layer/example Implements the IPortalUserSelector interface for the PortalUser__c object. This class includes sObject field definitions, boilerplate code for selector instantiation and configuration, and methods for querying records. ```apex /* PortalUserSelector.cls */ public inherited sharing class PortalUserSelector extends ApplicationSObjectSelector implements IPortalUserSelector { /* 1. sObjectField list */ private List additionalSObjectFieldList = new List{ 'Id', 'SSOId__c', 'FirstName__c', 'LastName__c', 'DisplayName__c' }; /* 2. Boilerplate code */ public static PortalUserSelector newInstance() { return (PortalUserSelector) Application.Selector.newInstance( PortalUser__c.SObjectType ); } public Schema.SObjectType getSObjectType() { return PortalUser__c.SObjectType; } public fflib_QueryFactory getQueryFactory() { return new fflib_QueryFactory(getSObjectType()); } public override List getSObjectFieldList() { return new List(); } public List getSObjectFieldListWithRelatedFields() { return this.additionalSObjectFieldList; } public void setSObjectFieldListWithRelatedFields(String[] values) { this.additionalSObjectFieldList = values; } @TestVisible private List getAdditionalSObjectFieldList() { return new List{}; } /* 3. Selector Methods */ public List selectById(Set idSet) { if (idSet.isEmpty()) { return new List(); } fflib_QueryFactory qf = getQueryFactory(); qf.selectFields(getSObjectFieldListWithRelatedFields()); qf.setCondition('Id IN :idSet'); return Database.query(qf.toSOQL()); } public PortalUser__c selectById(Id recordId) { List recordList = selectById(new Set{ recordId }); return recordList.isEmpty() ? null : recordList[0]; } public List selectAll() { fflib_QueryFactory qf = getQueryFactory(); qf.selectFields(getSObjectFieldListWithRelatedFields()); return Database.query(qf.toSOQL()); } } ``` -------------------------------- ### Define IPortalUserSelector Interface Source: https://fflib.dev/docs/selector-layer/example Defines the interface for the PortalUser selector, specifying methods for selecting records by ID and selecting all records. It extends the IApplicationSObjectSelector interface. ```apex /* IPortalUserSelector.cls */ public interface IPortalUserSelector extends IApplicationSObjectSelector { List selectById(Set idSet); PortalUser__c selectById(Id idSet); List selectAll(); } ``` -------------------------------- ### Define IPortalUsers Interface for Salesforce Domain Source: https://fflib.dev/docs/domain-layer/example Defines the IPortalUsers interface, extending IApplicationSObjectDomain, to specify methods for the PortalUsers domain class. This interface includes a method for validating user SSO IDs. ```apex /* IPortalUsers.cls */ public interface IPortalUsers extends IApplicationSObjectDomain { Map validateUserSso(List ssoId); } ``` -------------------------------- ### Implement Apex Service Class Source: https://fflib.dev/docs/service-layer/example Implements the ICommunityPortalService interface, providing the actual logic for the service methods. It demonstrates using Selector and Domain classes for data retrieval and business logic. ```Apex public inherited sharing class CommunityPortalService implements ICommunityPortalService { // example usage via a Selector Class public List getAllPortalUsers() { IPortalUserSelector selector = (IPortalUserSelector)Application.Selector.newInstance( PortalUser__c.SObjectType ); return selector.selectAll(); } // example usage via a Domain Class public Boolean isUserLoggedIn(String userId) { IPortalUsers iPortalUsers = (IPortalUsers) Application.Domain.newInstance( new Set{userId} ); Map validatedUsersBySsoId = iPortalUsers.validateUserSso(); return validatedUsersBySsoId.get(userId); } } ``` -------------------------------- ### Define Apex Service Interface Source: https://fflib.dev/docs/service-layer/example Defines the interface for the Community Portal Service, outlining the methods that the service class must implement. This promotes contract-based programming and allows for different implementations. ```Apex /* ICommunityPortalService.cls */ public interface ICommunityPortalService { List getAllPortalUsers(); Boolean isUserLoggedIn(String portalUserSsoId); } ``` -------------------------------- ### SOQL Parent-to-Child Relationship Query Source: https://fflib.dev/docs/selector-layer/advanced-usage/child-selectors Demonstrates a standard Salesforce SOQL query to select parent records along with their child records. This is a foundational example before introducing fflib. ```apex List accounts = [ SELECT Id, (SELECT Id FROM ChildAccounts) FROM Account WHERE Id =: accountId ]; ``` -------------------------------- ### Test Domain Class: PortalUsersTest (Apex) Source: https://fflib.dev/docs/domain-layer/test-classes Demonstrates testing the PortalUsers domain class. Includes tests for new instance creation, handling DML operations (insert, update, delete), and validating user SSO. Assumes the existence of `fflib_IDGenerator` and `GenericTestFactory` for test data setup. ```Apex @IsTest private class PortalUsersTest { // test that generating a new instance works // this will fail if the Custom Metadata records have not been setup @IsTest static void newInstanceTest() { IPortalUsers instanceByIds = PortalUsers.newInstance( new Set{ fflib_IDGenerator.generate(PortalUser__c.SObjectType) } ); IPortalUsers instanceByRecords = PortalUsers.newInstance(new List()); } @IsTest static void insertAndUpdateOnRecords() { // Test insert, update and delete fires off triggers properly List portalUsers = new List{ GenericTestFactory.createPortalUser(), GenericTestFactory.createPortalUser(), GenericTestFactory.createPortalUser() }; insert portalUsers; update portalUsers; delete portalUsers; } @IsTest static void validateUserSsoTest() { // TODO: mock selector and/or service methods before running the domain class method List portalUsers = new List{ GenericTestFactory.createPortalUser(), GenericTestFactory.createPortalUser(), GenericTestFactory.createPortalUser() }; IPortalUsers portalUsersDomain = (IPortalUsers) Application.Domain.newInstance(portalUsers); portalUsersDomain.validateUserSso(); } } ``` -------------------------------- ### fflib Basic Usage: Enabling Child Contact Fetching Source: https://fflib.dev/docs/selector-layer/advanced-usage/child-selectors Illustrates the basic usage of the fflib Selector Layer to fetch child records. This example shows how to instantiate a selector, enable the fetching of related 'Contacts' using a setter method, and then execute the query. ```apex /* PortalUserService.cls */ IPortalUserSelector portalUserSelector = (IPortalUserSelector)Application.Selector.newInstance( PortalUser__c.SObjectType ); // flag we would like to fetch child Contacts portalUserSelector.setWithContacts(true); List portalUsers = portalUserSelector.selectById( new Set{'SF_RECORD_ID'} ); // this is just an example of using the fetched Contacts (for the first account we've found) for (Contact contact : portalUsers[0].Contacts) { // do something with the contact } ``` -------------------------------- ### Create Apex Controller with @AuraEnabled Method (Apex) Source: https://fflib.dev/docs/implementation-layer/example This Apex code defines a controller class `PortalUserController` with a method `getAllPortalUsers` annotated with `@AuraEnabled(Cacheable=true)`. This method is intended to be called by LWC components and retrieves portal user data through a service layer, adhering to the implementation layer pattern. ```Apex public with sharing class PortalUserController { @TestVisible private static ICommunityPortalService communityPortalService = (ICommunityPortalService) Application.Service.newInstance( ICommunityPortalService.class ); @AuraEnabled(Cacheable=true) public static List getAllPortalUsers() { return communityPortalService.getAllPortalUsers(); } } ``` -------------------------------- ### Apex Test Class for Controller with Mocked Service Source: https://fflib.dev/docs/implementation-layer/test-classes This Apex code demonstrates how to write a test class for a controller, utilizing fflib_ApexMocks to mock service layer dependencies. It covers setting up mocks, defining mock data, stubbing service method calls, and asserting the controller's response. ```Apex @IsTest(IsParallel=true) private class PortalUserControllerTest { // Mocks static fflib_ApexMocks mocks = new fflib_ApexMocks(); // Services (mock) // it is good practice to append "Mock" to these definitions. // you may need to initialise actual service methods (not mocked) in your test class. static ICommunityPortalService communityPortalServiceMock = (ICommunityPortalService) mocks.mock( ICommunityPortalService.class ); @IsTest static void getAllPortalUsersTest() { // 1. Setup your mock data List portalUsers = new List{ GenericTestFactory.createPortalUser(), GenericTestFactory.createPortalUser(), GenericTestFactory.createPortalUser() }; // 2. Mock your service methods (and return your mocked data). // Put service method inputs here too for mocking (e.g. myServiceMethod(accountId, contactId)). mocks.startStubbing(); mocks.when(communityPortalServiceMock.getAllPortalUsers()) .thenReturn(portalUsers); mocks.stopStubbing(); // 3. set the mock service(s) Application.Service.setMock(ICommunityPortalService.class, communityPortalServiceMock); // 4. Call the controller method after setting up the service layer mocks List portalUsersResponse = PortalUserController.getAllPortalUsers(); // 5. Assert the response Assert.areEqual( portalUsers.size(), portalUsersResponse.size(), 'Response users does not match expected size.' ); // NOTE: we're using the new Winter '23 Apex assert syntax here // this may also be written as System.assertEquals( portalUsers.size(), portalUsersResponse.size(), 'Response users does not match expected size.' ); } } ``` -------------------------------- ### Implement UserSelector with IsActive Filter in Apex Source: https://fflib.dev/docs/selector-layer/advanced-usage/extra-queries This Apex code defines a UserSelector class that extends ApplicationSObjectSelector and implements IUserSelector. It includes functionality to filter users based on their 'IsActive' status, demonstrating the 'Extra Queries (Generic Flags)' pattern. The selector defines additional fields to query and provides methods to set and retrieve the 'IsActive' filter. ```apex public inherited sharing class UserSelector extends ApplicationSObjectSelector implements IUserSelector { private List additionalSObjectFieldList = new List{ 'Id', 'IsActive', 'Name', 'CommunityNickname', 'Contact.AccountId', 'Contact.Email' }; // selector boilerplate removed for brevity. See `https://fflib.dev/docs/selector-layer/example` for source. /* Selector Methods */ public List selectById(Set idSet) { if (idSet.isEmpty()) { return new List(); } fflib_QueryFactory qf = getQueryFactory(); qf.selectFields(getSObjectFieldListWithRelatedFields()); qf.setCondition('Id IN :idSet' + getExtraQueries()); return Database.query(qf.toSOQL()); } public User selectById(Id recordId) { List recordList = selectById(new Set{ recordId }); return recordList.isEmpty() ? null : recordList[0]; } public List selectByContactId(Set idSet) { if (idSet.isEmpty()) { return new List(); } fflib_QueryFactory qf = getQueryFactory(); qf.selectFields(getSObjectFieldListWithRelatedFields()); qf.setCondition('ContactId IN :idSet ' + getExtraQueries()); return Database.query(qf.toSOQL()); } public User selectByContactId(Id recordId) { List recordList = selectByContactId(new Set{ recordId }); return recordList.isEmpty() ? null : recordList[0]; } /** * Extra Query Flags */ private Boolean filterIsActive = true; /** * @param isActive - boolean of the IsActive user state to query for */ public void setFilterIsActive(Boolean isActive) { this.filterIsActive = isActive; } private String getFilterIsActive() { return this.filterIsActive == true ? ' AND IsActive = TRUE ' : ' '; } /** * Test visible so we can assert our expected queries */ @TestVisible private String getExtraQueries(Boolean removeFirstAnd) { // add more `getFilter*` methods here String extraQueries = getFilterIsActive(); return removeFirstAnd ? extraQueries.replaceFirst('AND', ' ') : extraQueries; } private String getExtraQueries() { return getExtraQueries(false); } } ``` -------------------------------- ### Disable IsActive Filter for User Selection in Apex Source: https://fflib.dev/docs/selector-layer/advanced-usage/extra-queries This Apex code demonstrates how to use the UserSelector to fetch all users, regardless of their active status, by disabling the default 'IsActive' filter. It shows instantiating the selector, setting the filter to false, and then performing a query by ID. This highlights the flexibility of the 'Extra Queries (Generic Flags)' pattern. ```apex /* PortalUserService.cls */ IUserSelector userSelector = (IUserSelector)Application.Selector.newInstance( User.SObjectType ); // set the filter to `false` as we want to fetch all Users, regardless of it they're active or not userSelector.setFilterIsActive(false); List users = userSelector.selectById( new Set{'SF_RECORD_ID'} ); ``` -------------------------------- ### fflib AccountSelector with Child Accounts and Contacts Source: https://fflib.dev/docs/selector-layer/advanced-usage/child-selectors Shows an fflib `AccountSelector` class implementation that allows for conditionally querying child relationships like 'ChildAccounts' and 'Contacts'. It includes methods to set flags for enabling these sub-selects and a private method to manage the query factory configuration. ```apex public inherited sharing class AccountSelector extends ApplicationSObjectSelector implements IAccountSelector { private List additionalSObjectFieldList = new List{ 'Id', 'Name', 'ParentId', }; // selector boilerplate removed for brevity. See `https://fflib.dev/docs/selector-layer/example` for source. public List selectById(Set idSet) { if (idSet.isEmpty()) { return new List(); } fflib_QueryFactory qf = getQueryFactory(); qf.selectFields(getSObjectFieldListWithRelatedFields()); qf.setCondition('Id IN :idSet'); // this line should be added to all `select*` methods on this selector // to allow any query to also query for child relationships. checkWithSubSelect(qf); return Database.query(qf.toSOQL()); } public Account selectById(Id recordId) { List recordList = selectById(new Set{ recordId }); return recordList.isEmpty() ? null : recordList[0]; } // more select methods here /** * Child Relationships */ private Boolean withChildAccounts = false; private Boolean withContacts = false; /** * @description Add ChildAccounts to this query. Default to `false` * @param withChildAccounts - Boolean to adjust the withChildAccounts */ public void setWithChildAccounts(Boolean withChildAccounts) { this.withChildAccounts = withChildAccounts; } /** * @description Add Contacts to this query. Default to `false` * @param withContacts - Boolean to adjust the withChildAccounts */ public void setWithContacts(Boolean withContacts) { this.withContacts = withContacts; } /** * Checks if and which child relationships should be queried for. * @param qf - current QueryFactory */ private void checkWithSubSelect(fflib_QueryFactory qf) { if (withChildAccounts == true) { new AccountSelector().addQueryFactorySubselect(qf, 'ChildAccounts'); } if (withContacts == true) { // NOTE: we're calling a ContactSelector (not explicitly // shown - but there is no magic happening here) new ContactSelector().addQueryFactorySubselect(qf, 'Contacts') // only select a subset of the fields that the selector has // we don't need to query for all of the fields on this sub selector .selectFields( new List{ 'LastName', 'AccountId' } ); } // add more if checks here to allow for more child sub selects to be added } } ``` -------------------------------- ### Apex Selector Test Class Template Source: https://fflib.dev/docs/selector-layer/test-classes A template for Apex test classes to test selector methods. It allows for testing without inserting or mocking data, catching invalid fields or SOQL queries. Key variables like SOBJECT_TYPE and EMPTY_LIST can be customized for generic selector tests. ```Apex /* PortalUserSelectorTest.cls */ @IsTest(IsParallel=true) private class PortalUserSelectorTest { public final static SObjectType SOBJECT_TYPE = PortalUser__c.SObjectType; public static final List EMPTY_LIST = new List(); /* Generic tests all selectors have */ @IsTest static void shouldReturnRecordSObjectType() { PortalUserSelector selector = PortalUserSelector.newInstance(); System.assertEquals( SOBJECT_TYPE, selector.getSObjectType(), 'Expected object type returned correctly' ); } @IsTest static void shouldReturnQueryFactory() { PortalUserSelector selector = PortalUserSelector.newInstance(); System.assertNotEquals( null, selector.getQueryFactory(), 'Expected a query factory returned' ); } @IsTest static void shouldReturnObjectFieldList() { PortalUserSelector selector = PortalUserSelector.newInstance(); System.assertNotEquals( null, selector.getSObjectFieldList(), 'Expected field list returned' ); } @IsTest static void shouldSetAndGetSObjectFieldListWithRelatedFields() { PortalUserSelector selector = PortalUserSelector.newInstance(); selector.setSObjectFieldListWithRelatedFields(new List{ 'test' }); List result = selector.getSObjectFieldListWithRelatedFields(); System.assert(!result.isEmpty()); } @IsTest static void shouldNotGetErrorsOnGettingAdditionalFieldsList() { PortalUserSelector selector = PortalUserSelector.newInstance(); selector.getAdditionalSObjectFieldList(); System.assert(true, 'Expected no errors'); } @IsTest static void shouldReturnEmptyListWhenSelectByIdHasEmptySetParameterVal() { PortalUserSelector selector = PortalUserSelector.newInstance(); System.assertEquals( EMPTY_LIST, selector.selectById(new Set()), 'Expected empty list because there is no id values in the Set' ); } @IsTest static void shouldReturnEmptyListWhenSelectByIdSetDoesNotExist() { PortalUserSelector selector = PortalUserSelector.newInstance(); System.assertEquals( EMPTY_LIST, selector.selectById( new Set{ fflib_IDGenerator.generate(SOBJECT_TYPE) } ), 'Expected empty list because record id value does not exist' ); } @IsTest static void shouldReturnEmptyListWhenSelectByIdDoesNotExist() { PortalUserSelector selector = PortalUserSelector.newInstance(); System.assertEquals( null, selector.selectById(fflib_IDGenerator.generate(SOBJECT_TYPE)), 'Expected null because record id value does not exist' ); } @IsTest static void shouldReturnEmptyListWhenSelectSObjectsByIdSetDoesNotExist() { PortalUserSelector selector = PortalUserSelector.newInstance(); System.assertEquals( new List(), selector.selectSObjectsById( new Set{ fflib_IDGenerator.generate(SOBJECT_TYPE) } ), 'Expected empty list because record id value does not exist' ); } /* Selector specific tests */ @IsTest static void testSelectAll() { PortalUserSelector selector = PortalUserSelector.newInstance(); System.assertEquals( EMPTY_LIST, selector.selectAll(), 'Expected empty list because there have been no test records inserted' ); } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.