Merge pull request #1 from wimvelzeboer/ApplicationFactory

Application factory
This commit is contained in:
William Velzeboer
2021-06-25 16:05:40 +01:00
committed by GitHub
19 changed files with 1011 additions and 0 deletions
+1
View File
@@ -9,6 +9,7 @@ This extension package is dependent on the following packages:
## Contents ## Contents
This extension pack includes the following features This extension pack includes the following features
- [Application Class](.docs/application-factories.md) based on interface structure
- [Primitive domains](./docs/primitive-domains.md) - [Primitive domains](./docs/primitive-domains.md)
- [A common criteria based filter](./docs/criteria-based-filter.md) for Domains and Selector - [A common criteria based filter](./docs/criteria-based-filter.md) for Domains and Selector
+182
View File
@@ -0,0 +1,182 @@
# fflib-apex-extensions
## Application Factory Interface Structure
1. [Interface structure](#interface-structure)
1. [Classic](#classic), a backwards compatible implementation
1. Dependency Injection, a dynamic factory that can be configured instead of using hard reference maps
### Interface structure
The existing Application factories of the
[apex-commons](https://github.com/apex-enterprise-patterns/fflib-apex-common)
do not have interfaces, therefore it is hard to replace their implementations. The fflib-apex-extensions add an interface structure and includes multiple implementations for you to choose from.
The [classic](#classic) implementation is fully backward compatible and in the well known familiar structure.
The interfaces adds the following added features
- fflib_IServiceFactory
- [replaceWith](#fflib_iservicefactory---replacewith)
- fflib_ISelectorFactory
- [selectById](#fflib_iselectorfactory---selectbyid) _(method overload)_
- [replaceWith](#fflib_iselectorfactory---replacewith)
- [setMock](#fflib_iselectorfactory---setmock) _(method overload)_
- fflib_IDomainFactory
- [newInstance](#fflib_idomainfactory---newinstance) _(method overload)_
- [replaceWith](#fflib_idomainfactory---replacewith)
- [setMock](#fflib_idomainfactory---setmock) _(method overload)_
##### fflib_IServiceFactory - replaceWith
This will create or replaces an existing binding for another.
###### Syntax
`void replaceWith(Type serviceInterfaceType, Type replacementImplType)`
###### Example
Let's assume we have two implementation for AccountsService `AccountsServiceImpl` and `AlternativeAccountsServiceImpl`.
In the Service Factory `IAccountsService` is bound to the `AccountsServiceImpl` implementation.
```apex
IAccountsService accountsService = (IAccountsService) Application.Service.newInstance();
System.assert(accountsService instanceof AccountsServiceImpl);
// Replace the implementation binding
Application.Service.replaceWith(IAccountsService.class, MyAlternateAccountsServiceImpl.class);
IAccountsService accountsService = (IAccountsService) Application.Service.newInstance();
System.assert(accountsService instanceof AlternativeAccountsServiceImpl);
```
##### fflib_ISelectorFactory - selectById
This method overload accepts an extra argument named `sObjectType`.
By providing the SObjectType, the method assumes that all the provided Ids are of the given SObjectType.
Thereby executing faster as the original method doesn't need to iterate over all the ids
to validate that they are all from the same SObjectType.
###### Syntax
`List<SObject> selectById(Set<Id> recordIds, SObjectType sObjectType)`
##### fflib_ISelectorFactory - replaceWith
This will create or replaces an existing binding for another.
###### Syntax
`void replaceWith(SObjectType sObjectType, Type replacementImplType)`
##### fflib_ISelectorFactory - setMock
This method overload avoids the need to stub the selector mock to return its SObjectType
###### Syntax
`void setMock(SObjectType sObjectType, fflib_ISObjectSelector selectorInstance)`
###### Example
Instead of doing this:
```apex
fflib_ApexMocks mocks = new fflib_ApexMocks();
AccountsSelector serviceMock = (AccountsSelector) mocks.mock(AccountsSelector.class);
mocks.startStubbing();
mocks.when(selectorMock.sObjectType()).thenReturn(Schema.Account.SObjectType);
mocks.stopStubbing();
Application.Selector.setMock(serviceMock);
```
You can now do the same without the need to stub it:
```apex
fflib_ApexMocks mocks = new fflib_ApexMocks();
AccountsSelector serviceMock = (AccountsSelector) mocks.mock(AccountsSelector.class);
Application.Selector.setMock(Schema.Account.SObjectType, serviceMock);
```
##### fflib_IDomainFactory - newInstance
The added argument `sObjectType` avoids the selector to iterate over the given record Ids to validate them.
###### Syntax
`fflib_IDomain newInstance(Set<Id> recordIds, Schema.SObjectType sObjectType)`
##### fflib_IDomainFactory - replaceWith
This will create or replaces an existing binding for another.
###### Syntax
`void replaceWith(Schema.SObjectType sObjectType, Type replacementImplType)`
##### fflib_IDomainFactory - setMock
This method overload avoids the need to stub the selector mock to return its SObjectType
###### Syntax
`void setMock(Schema.SObjectType sObjectType, fflib_ISObjectDomain mockDomain)`
###### Example
Instead of doing this:
```apex
fflib_ApexMocks mocks = new fflib_ApexMocks();
IAccounts domainMock = (IAccounts) mocks.mock(IAccounts.class);
mocks.startStubbing();
mocks.when(domainMock.getType()).thenReturn(Schema.Account.SObjectType);
mocks.stopStubbing();
Application.Domain.setMock(domainMock);
```
You can now do the same without the need to stub it:
```apex
fflib_ApexMocks mocks = new fflib_ApexMocks();
IAccounts domainMock = (IAccounts) mocks.mock(IAccounts.class);
Application.Domain.setMock(Schema.Account.SObjectType, domainMock);
```
### Classic
This is the implementation you are looking for when you are used to the
[Application Factories](https://github.com/apex-enterprise-patterns/fflib-apex-common/blob/master/sfdx-source/apex-common/main/classes/fflib_Application.cls)
of the
[apex-commons](https://github.com/apex-enterprise-patterns/fflib-apex-common)
and you do not want to change anything about the structure based on maps,
but do like to use the added features of fflib-apex-extensions.
It is fully backwards compatible, and you only need to make a few small changes to your existing Application class, to use the added features.
#### Application Class
The Application class is slightly different than the stafactories in the fflib_Application are replaced by an interface structure.
To use the backwards compatible version of the factories, change your Application class into the example below.
Pay special attention to the interface types and implementation classes of the factories.
**Example**
```apex
public class Application
{
public static final fflib_IUnitOfWorkFactory UnitOfWork =
new fflib_ClassicUnitOfWorkFactory(
new List<SObjectType>
{
Schema.Account.SObjectType,
Schema.Contact.SObjectType,
...
}
);
public static final fflib_IServiceFactory Service =
new fflib_ClassicServiceFactory(
new Map<Type, Type>
{
IAccountsService.class => AccountsServiceImpl.class,
IContactsService.class => ContactsServiceImpl.class,
...
}
);
public static final fflib_ISelectorFactory Selector =
new fflib_ClassicSelectorFactory(
new Map<SObjectType, Type>
{
Schema.Account.SObjectType => AccountsSelector.class,
Schema.Contact.SObjectType => ContactsSelector.class,
...
}
);
public static final fflib_IDomainFactory Domain =
new fflib_ClassicDomainFactory(
Application.Selector,
new Map<SObjectType, Type>
{
Schema.Account.SObjectType => Accounts.Constructor.class,
Schema.Contact.SObjectType => Contacts.Constructor.class,
...
}
);
}
```
+57
View File
@@ -3,6 +3,63 @@
## How to adapt ## How to adapt
When you are familiar with using fflib-apex-common, then you need to be aware of a few differences that you will encounter when adopting this extension package. When you are familiar with using fflib-apex-common, then you need to be aware of a few differences that you will encounter when adopting this extension package.
### Contents
1. [The Application class](#changes-to-the-application)
1. [Domain class changes](#changes-to-the-domain)
### Changes to the Application
The factories in the fflib_Application are replaced by an interface structure.
To use the backwards compatible version of the factories, change your Application class into the example below.
Pay special attention to the interface types and implementation classes of the factories.
```apex
public class Application
{
public static final fflib_IUnitOfWorkFactory UnitOfWork =
new fflib_ClassicUnitOfWorkFactory(
new List<SObjectType>
{
Schema.Account.SObjectType,
Schema.Contact.SObjectType,
...
}
);
public static final fflib_IServiceFactory Service =
new fflib_ClassicServiceFactory(
new Map<Type, Type>
{
IAccountsService.class => AccountsServiceImpl.class,
IContactsService.class => ContactsServiceImpl.class,
...
}
);
public static final fflib_ISelectorFactory Selector =
new fflib_ClassicSelectorFactory(
new Map<SObjectType, Type>
{
Schema.Account.SObjectType => AccountsSelector.class,
Schema.Contact.SObjectType => ContactsSelector.class,
...
}
);
public static final fflib_IDomainFactory Domain =
new fflib_ClassicDomainFactory(
Application.Selector,
new Map<SObjectType, Type>
{
Schema.Account.SObjectType => Accounts.Constructor.class,
Schema.Contact.SObjectType => Contacts.Constructor.class,
...
}
);
}
```
### Changes to the domain ### Changes to the domain
A Domain class is extended from the domain class `SObjects` instead of `fflib_SObjects`. A Domain class is extended from the domain class `SObjects` instead of `fflib_SObjects`.
@@ -0,0 +1,157 @@
/**
* File Name: fflib_ClassicDomainFactory
* Description:
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual class fflib_ClassicDomainFactory
extends fflib_Application.DomainFactory
implements fflib_IDomainFactory
{
protected fflib_ISelectorFactory selectorFactory;
/**
* Constructs a Domain factory
**/
public fflib_ClassicDomainFactory() {}
/**
* Constructs a Domain factory, using an instance of the Selector Factory
* and a map of Apex classes implementing fflib_ISObjectDomain by SObjectType
* Note this will not check the Apex classes provided actually implement the interfaces
* since this is not possible in the Apex runtime at present
*
* @param selectorFactory , e.g. Application.Selector
* @param constructorTypeByObject Map of Domain classes by ObjectType
**/
public fflib_ClassicDomainFactory(
fflib_ISelectorFactory selectorFactory,
Map<Object, Type> constructorTypeByObject)
{
selectorFactory = selectorFactory;
this.constructorTypeByObject = constructorTypeByObject;
this.mockDomainByObject = new Map<Object, fflib_IDomain>();
}
/**
* Constructs a Domain factory, using an instance of the Selector Factory
* and a map of Apex classes implementing fflib_ISObjectDomain by SObjectType
* Note this will not check the Apex classes provided actually implement the interfaces
* since this is not possible in the Apex runtime at present
*
* @param selectorFactory , e.g. Application.Selector
* @param sObjectByDomainConstructorType Map of Apex classes by SObjectType
**/
public fflib_ClassicDomainFactory(fflib_ISelectorFactory selectorFactory,
Map<SObjectType, Type> sObjectByDomainConstructorType)
{
selectorFactory = selectorFactory;
this.constructorTypeByObject = getConstructorTypeByObject(sObjectByDomainConstructorType);
this.mockDomainByObject = new Map<Object, fflib_IDomain>();
}
/**
* Dynamically constructs an instance of a Domain class for the given record Ids
* Internally uses the Selector Factory to query the records before passing to a
* dynamically constructed instance of the application Apex Domain class
*
* @param recordIds A list of Id's of the same type
*
* @return Instance of a Domain containing the queried records
* @exception Throws an exception via the Selector Factory if the Ids are not all of the same SObjectType
**/
public virtual override fflib_IDomain newInstance(Set<Id> recordIds)
{
return newInstance(selectorFactory.selectById(recordIds));
}
/**
* Dynamically constructs an instance of a Domain class for the given record Ids
* Internally uses the Selector Factory to query the records before passing to a
* dynamically constructed instance of the application Apex Domain class
*
* @param recordIds A list of Id's of the same type
* @param sObjectType The SObjectType of the given record Ids
*
* @return Instance of a Domain containing the queried records
* @exception Throws an exception via the Selector Factory if the Ids are not all of the same SObjectType
**/
public virtual fflib_IDomain newInstance(Set<Id> recordIds, Schema.SObjectType sObjectType)
{
return newInstance(selectorFactory.selectById(recordIds, sObjectType));
}
/**
* Creates or replaces an existing binding for another
*
* @param sObjectType The SObjectType of the selector to replace
* @param replacementImplType The implementation type of the replacement
*/
public virtual void replaceWith(Schema.SObjectType sObjectType, Type replacementImplType)
{
this.constructorTypeByObject.put(
(Object) sObjectType,
replacementImplType
);
}
/**
* @param mockDomain The instance of the Domain mock
*/
public virtual override void setMock(fflib_ISObjectDomain mockDomain)
{
super.setMock(mockDomain);
}
/**
* @param sObjectType The SObjectType of the Domain mock,
* avoids the need to stub the mock to return its SObjectType
* @param mockDomain The instance of the Domain mock
*/
public virtual void setMock(Schema.SObjectType sObjectType, fflib_ISObjectDomain mockDomain)
{
mockDomainByObject.put((Object) sObjectType, mockDomain);
}
/**
* @param mockDomain The instance of the Domain mock
*/
public virtual override void setMock(fflib_IDomain mockDomain)
{
super.setMock(mockDomain);
}
/**
* @param domainType The ObjectType of the Domain mock,
* avoids the need to stub the mock to return its ObjectType
* @param mockDomain The instance of the Domain mock
*/
public virtual void setMock(Type domainType, fflib_IDomain mockDomain)
{
mockDomainByObject.put(domainType, mockDomain);
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,101 @@
/**
* File Name: fflib_ClassicSelectorFactory
* Description:
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual class fflib_ClassicSelectorFactory
extends fflib_Application.SelectorFactory
implements fflib_ISelectorFactory
{
/**
* Constructs a simple Selector Factory
**/
public fflib_ClassicSelectorFactory() {}
/**
* Constructs a Selector Factory linking SObjectType's with Apex Classes implement the fflib_ISObjectSelector interface
* Note that the factory does not check the given Apex Classes implement the interface
* currently this is not possible in Apex.
*
* @param sObjectBySelectorType Map of SObjectType's to Selector Apex Classes
**/
public fflib_ClassicSelectorFactory(Map<SObjectType, Type> sObjectBySelectorType)
{
super(sObjectBySelectorType);
}
/**
* Helper method to query the given SObject records
* Internally creates an instance of the registered Selector and calls its
* selectSObjectById method.
* It assumes that all Ids are of the given SObjectType, no additional validation is done.
*
* @param recordIds The recordIds to query
* @param sObjectType The SObjectType of the Ids
*
* @return The queried records
* @exception fflib_Application.DeveloperException is thrown if the Ids set is empty
*/
public virtual List<SObject> selectById(Set<Id> recordIds, SObjectType sObjectType)
{
if (recordIds == null || recordIds.size() == 0)
throw new fflib_Application.DeveloperException('Invalid record Id\'s set');
return newInstance(sObjectType)
.selectSObjectsById(recordIds);
}
/**
* Creates or replaces an existing binding for another
*
* @param sObjectType The SObjectType of the selector to replace
* @param replacementImplType The implementation type of the replacement
*/
public virtual void replaceWith(SObjectType sObjectType, Type replacementImplType)
{
this.m_sObjectBySelectorType.put(sObjectType, replacementImplType);
}
/**
* @param selectorInstance The instance of the mocked selector
*/
public virtual override void setMock(fflib_ISObjectSelector selectorInstance)
{
super.setMock(selectorInstance);
}
/**
* @param sObjectType The SObjectType of the selector mock,
* avoids the need to stub the mock to return its SObjectType
* @param selectorInstance The instance of the mocked selector
*/
public virtual void setMock(SObjectType sObjectType, fflib_ISObjectSelector selectorInstance)
{
this.m_sObjectByMockSelector.put(sObjectType, selectorInstance);
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,75 @@
/**
* File Name: fflib_ClassicServiceFactory
* Description:
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual class fflib_ClassicServiceFactory
extends fflib_Application.ServiceFactory
implements fflib_IServiceFactory
{
/**
* Constructs a simple Service Factory
**/
public fflib_ClassicServiceFactory() {}
/**
* Constructs a simple Service Factory,
* using a Map of Apex Interfaces to Apex Classes implementing the interface
* Note that this will not check the Apex Classes given actually implement the interfaces
* as this information is not presently available via the Apex runtime
*
* @param serviceInterfaceTypeByServiceImplType Map ofi interfaces to classes
**/
public fflib_ClassicServiceFactory(Map<Type, Type> serviceInterfaceTypeByServiceImplType)
{
super(serviceInterfaceTypeByServiceImplType);
}
/**
* Creates or replaces an existing binding for another
*
* @param serviceInterfaceType The Interface type to replace its implementation
* @param replacementImplType The implementation type of the replacement
*/
public virtual void replaceWith(Type serviceInterfaceType, Type replacementImplType)
{
this.m_serviceInterfaceTypeByServiceImplType.put(
serviceInterfaceType,
replacementImplType
);
}
/**
* @param serviceInterfaceType The interface type to mock
* @param serviceImpl The mock implementation
*/
public virtual override void setMock(Type serviceInterfaceType, Object serviceImpl)
{
super.setMock(serviceInterfaceType, serviceImpl);
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,57 @@
/**
* File Name: fflib_ClassicUnitOfWorkFactory
* Description:
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public virtual class fflib_ClassicUnitOfWorkFactory
extends fflib_Application.UnitOfWorkFactory
implements fflib_IUnitOfWorkFactory
{
/**
* Constructs a Unit Of Work factory
**/
public fflib_ClassicUnitOfWorkFactory()
{
super();
}
/**
* Constructs a Unit Of Work factory
*
* @param objectTypes List of SObjectTypes in dependency order
**/
public fflib_ClassicUnitOfWorkFactory(List<SObjectType> objectTypes)
{
super(objectTypes);
}
public virtual override void setMock(fflib_ISObjectUnitOfWork mockUow)
{
super.setMock(mockUow);
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,99 @@
/**
* File Name: fflib_IDomainFactory
* Description: Interface for creating instances of Service classes
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public interface fflib_IDomainFactory
{
/**
* Dynamically constructs an instance of a Domain class for the given record Ids
* Internally uses the Selector Factory to query the records before passing to a
* dynamically constructed instance of the application Apex Domain class
*
* @param recordIds A list of Id's of the same type
* @exception Throws an exception via the Selector Factory if the Ids are not all of the same SObjectType
*
* @return Instance of the Domain
**/
fflib_IDomain newInstance(Set<Id> recordIds);
fflib_IDomain newInstance(Set<Id> recordIds, Schema.SObjectType objectType);
/**
* Dynamically constructs an instance of the Domain class for the given records
* Will return a Mock implementation if one has been provided via setMock
*
* @param records A concrete list (e.g. List<Account> vs List<SObject>) of records
* @exception Throws an exception if the SObjectType cannot be determined from the list
* or the constructor for Domain class was not registered for the SObjectType
*
* @return Instance of the Domain
**/
fflib_IDomain newInstance(List<SObject> records);
fflib_IDomain newInstance(List<Object> objects, Object objectType);
/**
* Dynamically constructs an instance of the Domain class for the given records and SObjectType
* Will return a Mock implementation if one has been provided via setMock
*
* @param records A list records
* @param domainSObjectType SObjectType for list of records
* @exception Throws an exception if the SObjectType is not specified or if constructor for Domain class was not registered for the SObjectType
*
* @remark Will support List<SObject> but all records in the list will be assumed to be of
* the type specified in sObjectType
*
* @return Instance of the Domain
**/
fflib_IDomain newInstance(List<SObject> records, SObjectType domainSObjectType);
/**
* @param mockDomain The instance of the Domain mock
*/
void setMock(fflib_ISObjectDomain mockDomain);
/**
* @param sObjectType The SObjectType of the Domain mock,
* avoids the need to stub the mock to return its SObjectType
* @param mockDomain The instance of the Domain mock
*/
void setMock(Schema.SObjectType sObjectType, fflib_ISObjectDomain mockDomain);
/**
* @param mockDomain The instance of the Domain mock
*/
void setMock(fflib_IDomain mockDomain);
/**
* @param domainType The ObjectType of the Domain mock,
* avoids the need to stub the mock to return its ObjectType
* @param mockDomain The instance of the Domain mock
*/
void setMock(Type domainType, fflib_IDomain mockDomain);
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,104 @@
/**
* File Name: fflib_ISelectorFactory
* Description: Interface for creating instances of Selector classes
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public interface fflib_ISelectorFactory
{
/**
* Creates a new instance of the associated Apex Class implementing fflib_ISObjectSelector
* for the given SObjectType, or if provided via setMock returns the Mock implementation
*
* @param sObjectType An SObjectType token, e.g. Account.SObjectType
*
* @return Instance of fflib_ISObjectSelector
**/
fflib_ISObjectSelector newInstance(Schema.SObjectType sObjectType);
/**
* Helper method to query the given SObject records
* Internally creates an instance of the registered Selector and calls its
* selectSObjectById method
*
* @param recordIds The SObject record Ids, must be all the same SObjectType
* @exception Is thrown if the record Ids are not all the same or the SObjectType is not registered
*
* @return List of queried records
**/
List<SObject> selectById(Set<Id> recordIds);
/**
* Helper method to query the given SObject records
* Internally creates an instance of the registered Selector and calls its
* selectSObjectById method
*
* @param recordIds The SObject record Ids, must be all the same SObjectType
* @exception Is thrown if the record Ids are not all the same or the SObjectType is not registered
* @param sObjectType The SObjectType of the provided Ids
*
* @return List of queried records
**/
List<SObject> selectById(Set<Id> recordIds, Schema.SObjectType sObjectType);
/**
* Helper method to query related records to those provided, for example
* if passed a list of Opportunity records and the Account Id field will
* construct internally a list of Account Ids and call the registered
* Account selector to query the related Account records, e.g.
*
* List<Account> accounts =
* (List<Account>) Application.Selector.selectByRelationship(myOpps, Opportunity.AccountId);
*
* @param relatedRecords used to extract the related record Ids, e.g. Opportunity records
* @param relationshipField field in the passed records that contains the relationship records to query, e.g. Opportunity.AccountId
*
* @return List of queried records
**/
List<SObject> selectByRelationship(List<SObject> relatedRecords, SObjectField relationshipField);
/**
* Creates or replaces an existing binding for another
*
* @param sObjectType The SObjectType of the selector to replace
* @param replacementImplType The implementation type of the replacement
*/
void replaceWith(Schema.SObjectType sObjectType, Type replacementImplType);
/**
* @param selectorInstance The instance of the mocked selector
*/
void setMock(fflib_ISObjectSelector selectorInstance);
/**
*
* @param sObjectType The SObjectType of the selector mock,
* avoids the need to stub the mock to return its SObjectType
* @param selectorInstance The instance of the mocked selector
*/
void setMock(Schema.SObjectType sObjectType, fflib_ISObjectSelector selectorInstance);
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,58 @@
/**
* File Name: fflib_IServiceFactory
* Description: Interface for creating instances of Service classes
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public interface fflib_IServiceFactory
{
/**
* Returns a new instance of the Apex class associated with the given Apex interface
* Will return any mock implementation of the interface provided via setMock
* Note that this method will not check the configured Apex class actually implements the interface
*
* @param serviceInterfaceType Apex interface type
* @exception Is thrown if there is no registered Apex class for the interface type
*
* @return Instance of the requested service class interface type
**/
Object newInstance(Type serviceInterfaceType);
/**
* Creates or replaces an existing binding for another
*
* @param serviceInterfaceType The Interface type to replace its implementation
* @param replacementImplType The implementation type of the replacement
*/
void replaceWith(Type serviceInterfaceType, Type replacementImplType);
/**
* @param serviceInterfaceType The interface type to mock
* @param serviceImpl The mock implementation
*/
void setMock(Type serviceInterfaceType, Object serviceImpl);
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>
@@ -0,0 +1,80 @@
/**
* File Name: fflib_IUnitOfWorkFactory
* Description: Interface for creating instances of fflib_ISObjectUnitOfWork
*
* @author : architect ir. Wilhelmus G.J. Velzeboer
*
* Copyright (c), W.G.J. Velzeboer,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above author notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public interface fflib_IUnitOfWorkFactory
{
/**
* Returns a new fflib_SObjectUnitOfWork configured with the
* SObjectType list provided in the constructor, returns a Mock implementation
* if set via the setMock method
*
* @return Instance of fflib_ISObjectUnitOfWork
**/
fflib_ISObjectUnitOfWork newInstance();
/**
* Returns a new fflib_SObjectUnitOfWork configured with the
* SObjectType list provided in the constructor, returns a Mock implementation
* if set via the setMock method
*
* @param dml A custom implementation of the IDML to perform the database operations
*
* @return Instance of fflib_ISObjectUnitOfWork
**/
fflib_ISObjectUnitOfWork newInstance(fflib_SObjectUnitOfWork.IDML dml);
/**
* Returns a new fflib_SObjectUnitOfWork configured with the
* SObjectType list specified, returns a Mock implementation
* if set via the setMock method
*
* @param objectTypes The hierarchical structure of the SObjectTypes
*
* @return Instance of fflib_ISObjectUnitOfWork
**/
fflib_ISObjectUnitOfWork newInstance(List<Schema.SObjectType> objectTypes);
/**
* Returns a new fflib_SObjectUnitOfWork configured with the
* SObjectType list specified, returns a Mock implementation
* if set via the setMock method
*
* @param objectTypes The hierarchical structure of the SObjectTypes
* @param dml A custom implementation of the IDML to perform the database operations
*
* @return Instance of fflib_ISObjectUnitOfWork
**/
fflib_ISObjectUnitOfWork newInstance(List<Schema.SObjectType> objectTypes, fflib_SObjectUnitOfWork.IDML dml);
/**
* @param mockUow A mock implementation for the unitOfWork factory
*/
void setMock(fflib_ISObjectUnitOfWork mockUow);
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>51.0</apiVersion>
<status>Active</status>
</ApexClass>