Add Dynamic Application Factory
This enabled realtime dependency injection for the fflib application. By default the configuration comes from the Custom Metadata object fflib_AppBinding__mdt, but can be fully customised and extended. Initial stuff
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
name: Create a Scratch Org, Push Source and Run Apex Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request_target:
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
################################################################################
|
||||
# ALLOW all files and folders in this directory, other than...
|
||||
# - local-config.sh
|
||||
# - custom_*
|
||||
#
|
||||
# This file (local-config.sh) is used by the shell scripts found in ./dev-tools
|
||||
# to provide customized settings for each developer working on an SFDX-Falcon
|
||||
# based project. Because these variables are customized per developer, this
|
||||
# local-config file should NOT be tracked in source control.
|
||||
#
|
||||
# The same holds for any custom libraries that an indivisual developer would
|
||||
# like to make. If you want to build something that wont' be tracked, just
|
||||
# prepend the filename with "custom_" and it will be ignored.
|
||||
################################################################################
|
||||
|
||||
#Ignore local-config.sh
|
||||
local-config.sh
|
||||
|
||||
# Ignore any files or folders that start with "custom_" (case insensitive)
|
||||
custom_*
|
||||
@@ -0,0 +1,551 @@
|
||||
#!/bin/bash
|
||||
####################################################################################################
|
||||
#
|
||||
# FILENAME: shared-functions.sh
|
||||
#
|
||||
# PURPOSE: Common header file for all dev-tools scripts. Contains shared functions.
|
||||
#
|
||||
# DESCRIPTION: Contains shared functions used by all of the dev-tools shell scripts.
|
||||
#
|
||||
# INSTRUCTIONS: This script should be sourced at the top of all dev-tools shell scripts.
|
||||
# Do not source this script manually from the command line. If you do, all of the
|
||||
# shell variables set by this script (including those from local-config.sh) will be
|
||||
# set in the user's shell, and any changes to local-config.sh may not be picked up
|
||||
# until the user manually exits their shell and opens a new one.
|
||||
#
|
||||
#
|
||||
####################################################################################################
|
||||
#
|
||||
##
|
||||
###
|
||||
#### PREVENT RELOAD OF THIS LIBRARY ################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
if [ "$SFDX_FALCON_FRAMEWORK_SHELL_VARS_SET" = "true" ]; then
|
||||
# The SFDX_FALCON_FRAMEWORK_SHELL_VARS_SET variable is defined as part of
|
||||
# this project's local configuration script (local-config.sh). If this
|
||||
# variable holds the string "true" then it means that local-config.sh has
|
||||
# already been sourced (loaded). Since this is exactly what THIS script
|
||||
# (shared-functions.sh) is supposed to do it means that this library has
|
||||
# already been loaded.
|
||||
#
|
||||
# We DO NOT want to load shared-functions.sh a second time, so we'll RETURN
|
||||
# (not EXIT) gracefully so the caller can continue as if they were the
|
||||
# first to load this.
|
||||
return 0
|
||||
fi
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: askUserForStringValue ###############################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
askUserForStringValue () {
|
||||
# If a second argument was provided, echo its
|
||||
# value before asking the user for input.
|
||||
if [ "$2" != "" ]; then
|
||||
echo $2 "\n"
|
||||
fi
|
||||
|
||||
# Create a local variable to store the value of
|
||||
# the variable provided by the first argument.
|
||||
eval "local LOCAL_VALUE=\$$1"
|
||||
|
||||
# Create a local variable to store the default error message.
|
||||
local LOCAL_ERROR_MSG="You must provide a value at the prompt."
|
||||
|
||||
# Do not allow the user to continue unless they
|
||||
# provide a value when prompted.
|
||||
while [ "$LOCAL_VALUE" = "" ]; do
|
||||
eval "read -p \"$1: \" $1"
|
||||
eval "LOCAL_VALUE=\$$1"
|
||||
|
||||
if [ "$LOCAL_VALUE" = "" ]; then
|
||||
# If the caller specified a custom error message, use it.
|
||||
if [ "$3" != "" ]; then
|
||||
eval "LOCAL_ERROR_MSG=\"$3\""
|
||||
fi
|
||||
echoErrorMsg "$LOCAL_ERROR_MSG"
|
||||
fi
|
||||
done
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: confirmChoice #######################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
confirmChoice () {
|
||||
# Local variable will store the user's response.
|
||||
local USER_RESPONSE=""
|
||||
# Show the question being asked.
|
||||
echo "`tput rev`$2`tput sgr0`"
|
||||
# Prompt the user for a response and read their input.
|
||||
read -p "$3" USER_RESPONSE
|
||||
# Save the user's response to the variable provided by the caller.
|
||||
eval "$1=\"$USER_RESPONSE\""
|
||||
# Add a line break
|
||||
echo ""
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: confirmScriptExecution ##############################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
confirmScriptExecution () {
|
||||
if [ ! -z "$CONFIRM_EXECUTION" ]; then
|
||||
# The user has already been asked to confirm execution.
|
||||
# If confirmScriptExecution() is getting called again, it means that
|
||||
# one or more scripts are being sourced and run by a parent script.
|
||||
# We don't want to keep throwing confirmation messages to the user,
|
||||
# so we'll just return 0 to silently continue.
|
||||
return 0
|
||||
fi
|
||||
echo "`tput rev`$1`tput sgr0`"
|
||||
read -p "(type YES to confirm, or hit ENTER to cancel) " CONFIRM_EXECUTION
|
||||
if [ "$CONFIRM_EXECUTION" != "YES" ]; then
|
||||
echo "\nScript aborted\n"
|
||||
exit 0
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: createScratchOrg () #################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
createScratchOrg() {
|
||||
# Declare a local variable to store the Alias of the org to CREATE
|
||||
local ORG_ALIAS_TO_CREATE=""
|
||||
|
||||
# Check if a value was passed to this function in Argument 1.
|
||||
# If there was we will make that the org alias to CREATE.
|
||||
if [ ! -z $1 ]; then
|
||||
ORG_ALIAS_TO_CREATE="$1"
|
||||
elif [ ! -z $TARGET_ORG_ALIAS ]; then
|
||||
ORG_ALIAS_TO_CREATE="$TARGET_ORG_ALIAS"
|
||||
else
|
||||
# Something went wrong. No argument was provided and the TARGET_ORG_ALIAS
|
||||
# has not yet been set or is an empty string. Raise an error message and
|
||||
# then exit 1 to kill the script.
|
||||
echoErrorMsg "Could not execute createScratchOrg(). Unknown target org alias."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create a new scratch org using the scratch-def.json locally configured for this project.
|
||||
echoStepMsg "Create a new $ORG_ALIAS_TO_CREATE scratch org"
|
||||
echo "Executing force:org:create -f $SCRATCH_ORG_CONFIG -a $ORG_ALIAS_TO_CREATE -v $DEV_HUB_ALIAS -s -d 29"
|
||||
(cd $PROJECT_ROOT && exec sfdx force:org:create -f $SCRATCH_ORG_CONFIG -a $ORG_ALIAS_TO_CREATE -v $DEV_HUB_ALIAS -s -d 29)
|
||||
if [ $? -ne 0 ]; then
|
||||
echoErrorMsg "Scratch org \"$ORG_ALIAS_TO_CREATE\"could not be created. Aborting Script."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: deleteScratchOrg () #################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
deleteScratchOrg () {
|
||||
# Declare a local variable to store the Alias of the org to delete
|
||||
local ORG_ALIAS_TO_DELETE=""
|
||||
|
||||
# Check if a value was passed to this function in Argument 1.
|
||||
# If there was we will make that the org alias to delete.
|
||||
if [ ! -z $1 ]; then
|
||||
ORG_ALIAS_TO_DELETE="$1"
|
||||
elif [ ! -z $TARGET_ORG_ALIAS ]; then
|
||||
ORG_ALIAS_TO_DELETE="$TARGET_ORG_ALIAS"
|
||||
else
|
||||
# Something went wrong. No argument was provided and the TARGET_ORG_ALIAS
|
||||
# has not yet been set or is an empty string. Raise an error message and
|
||||
# then exit 1 to kill the script.
|
||||
echoErrorMsg "Could not execute deleteScratchOrg(). Unknown target org alias."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Delete the current scratch org.
|
||||
echoStepMsg "Delete the $ORG_ALIAS_TO_DELETE scratch org"
|
||||
echo "Executing force:org:delete -p -u $ORG_ALIAS_TO_DELETE -v $DEV_HUB_ALIAS"
|
||||
(cd $PROJECT_ROOT && exec sfdx force:org:delete -p -u $ORG_ALIAS_TO_DELETE -v $DEV_HUB_ALIAS )
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: determineTargetOrgAlias () ##########################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
determineTargetOrgAlias () {
|
||||
# Start by clearing TARGET_ORG_ALIAS so we'll know for sure if a new value was provided
|
||||
TARGET_ORG_ALIAS=""
|
||||
|
||||
# If no value was provided for $REQUESTED_OPERATION, set defaults and return success.
|
||||
if [ -z "$REQUESTED_OPERATION" ]; then
|
||||
PARENT_OPERATION="NOT_SPECIFIED"
|
||||
TARGET_ORG_ALIAS="NOT_SPECIFIED"
|
||||
return 0
|
||||
else
|
||||
case "$REQUESTED_OPERATION" in
|
||||
"REBUILD_SCRATCH_ORG")
|
||||
TARGET_ORG_ALIAS="$SCRATCH_ORG_ALIAS"
|
||||
;;
|
||||
"VALIDATE_PACKAGE_SOURCE")
|
||||
TARGET_ORG_ALIAS="$PACKAGING_ORG_ALIAS"
|
||||
;;
|
||||
"DEPLOY_PACKAGE_SOURCE")
|
||||
TARGET_ORG_ALIAS="$PACKAGING_ORG_ALIAS"
|
||||
;;
|
||||
"INSTALL_PACKAGE")
|
||||
TARGET_ORG_ALIAS="$SUBSCRIBER_ORG_ALIAS"
|
||||
;;
|
||||
esac
|
||||
# Make sure that TARGET_ORG_ALIAS was set. If not, it means an unexpected PARENT_OPERATION
|
||||
# was provided. In that case, raise an error and abort the script.
|
||||
if [ -z "$TARGET_ORG_ALIAS" ]; then
|
||||
echo "\nFATAL ERROR: `tput sgr0``tput setaf 1`\"$REQUESTED_OPERATION\" is not a valid installation option.\n"
|
||||
exit 1
|
||||
fi
|
||||
# If we get this far, it means that the REQUESTED_OPERATION was valid.
|
||||
# We can now assign that to the PARENT_OPERATION variable and return success.
|
||||
PARENT_OPERATION="$REQUESTED_OPERATION"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: echoConfigVariables () ##############################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
echoConfigVariables () {
|
||||
echo ""
|
||||
echo "`tput setaf 7`PROJECT_ROOT -------------->`tput sgr0` " $PROJECT_ROOT
|
||||
echo "`tput setaf 7`NAMESPACE_PREFIX ---------->`tput sgr0` " $NAMESPACE_PREFIX
|
||||
echo "`tput setaf 7`PACKAGE_NAME -------------->`tput sgr0` " $PACKAGE_NAME
|
||||
echo "`tput setaf 7`DEFAULT_PACKAGE_DIR_NAME -->`tput sgr0` " $DEFAULT_PACKAGE_DIR_NAME
|
||||
echo "`tput setaf 7`TARGET_ORG_ALIAS ---------->`tput sgr0` " $TARGET_ORG_ALIAS
|
||||
echo "`tput setaf 7`DEV_HUB_ALIAS ------------->`tput sgr0` " $DEV_HUB_ALIAS
|
||||
echo "`tput setaf 7`SCRATCH_ORG_ALIAS --------->`tput sgr0` " $SCRATCH_ORG_ALIAS
|
||||
echo "`tput setaf 7`PACKAGING_ORG_ALIAS ------->`tput sgr0` " $PACKAGING_ORG_ALIAS
|
||||
echo "`tput setaf 7`SUBSCRIBER_ORG_ALIAS ------>`tput sgr0` " $SUBSCRIBER_ORG_ALIAS
|
||||
echo "`tput setaf 7`METADATA_PACKAGE_ID ------->`tput sgr0` " $METADATA_PACKAGE_ID
|
||||
echo "`tput setaf 7`PACKAGE_VERSION_ID -------->`tput sgr0` " $PACKAGE_VERSION_ID
|
||||
echo "`tput setaf 7`SCRATCH_ORG_CONFIG -------->`tput sgr0` " $SCRATCH_ORG_CONFIG
|
||||
echo "`tput setaf 7`GIT_REMOTE_URI ------------>`tput sgr0` " $GIT_REMOTE_URI
|
||||
echo "`tput setaf 7`ECHO_LOCAL_CONFIG_VARS ---->`tput sgr0` " $ECHO_LOCAL_CONFIG_VARS
|
||||
echo ""
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: echoErrorMsg () #####################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
echoErrorMsg () {
|
||||
tput sgr 0; tput setaf 7; tput bold;
|
||||
printf "\n\nERROR: "
|
||||
tput sgr 0; tput setaf 1;
|
||||
printf "%b\n\n" "$1"
|
||||
tput sgr 0;
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: echoQuestion () #####################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
echoQuestion () {
|
||||
tput sgr 0; tput rev;
|
||||
printf "\nQuestion $CURRENT_QUESTION of $TOTAL_QUESTIONS:"
|
||||
printf " %b\n\n" "$1"
|
||||
tput sgr 0;
|
||||
let CURRENT_QUESTION++
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: echoScriptCompleteMsg () ############################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
echoScriptCompleteMsg () {
|
||||
tput sgr 0; tput setaf 7; tput bold;
|
||||
printf "\n\nScript Complete: "
|
||||
tput sgr 0;
|
||||
printf "%b\n\n" "$1"
|
||||
tput sgr 0;
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: echoStepMsg () ######################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
echoStepMsg () {
|
||||
tput sgr 0; tput setaf 7; tput bold;
|
||||
if [ $TOTAL_STEPS -gt 0 ]; then
|
||||
## This is one of a sequence of steps
|
||||
printf "\nStep $CURRENT_STEP of $TOTAL_STEPS:"
|
||||
else
|
||||
# This is likely a preliminary step, coming before a sequence.
|
||||
printf "\nPreliminary Step $CURRENT_STEP:"
|
||||
fi
|
||||
tput sgr 0;
|
||||
printf " %b\n\n" "$1"
|
||||
tput sgr 0;
|
||||
let CURRENT_STEP++
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: echoWarningMsg () ###################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
echoWarningMsg () {
|
||||
tput sgr 0; tput setaf 7; tput bold;
|
||||
printf "\n\nWARNING: "
|
||||
tput sgr 0;
|
||||
printf "%b\n\n" "$1"
|
||||
tput sgr 0;
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: findProjectRoot () ##################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
findProjectRoot () {
|
||||
# Detect the path to the directory that the running script was called from.
|
||||
local PATH_TO_RUNNING_SCRIPT="$( cd "$(dirname "$0")" ; pwd -P )"
|
||||
|
||||
# Grab the last 10 characters of the detected path. This should be "/dev-tools".
|
||||
local DEV_TOOLS_SLICE=${PATH_TO_RUNNING_SCRIPT: -10}
|
||||
|
||||
# Make sure the last 10 chars of the path are "/dev-tools".
|
||||
# Kill the script with an error if not.
|
||||
if [[ $DEV_TOOLS_SLICE != "/dev-tools" ]]; then
|
||||
echoErrorMsg "Script was not executed within the <project-root>/dev-tools directory."
|
||||
tput sgr 0; tput bold;
|
||||
echo "Shell scripts that utilize FALCON Developer Tools must be executed from"
|
||||
echo "inside the dev-tools directory found at the root of your SFDX project.\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Calculate the Project Root path by going up one level from the path currently
|
||||
# held in the PATH_TO_RUNNING_SCRIPT variable
|
||||
local PATH_TO_PROJECT_ROOT="$( cd "$PATH_TO_RUNNING_SCRIPT" ; cd .. ; pwd -P )"
|
||||
|
||||
# Pass the value of the "detected path" back out to the caller by setting the
|
||||
# value of the first argument provided when the function was called.
|
||||
eval "$1=\"$PATH_TO_PROJECT_ROOT\""
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: initializeHelperVariables () ########################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
initializeHelperVariables () {
|
||||
CONFIRM_EXECUTION="" # Indicates the user's choice whether to execute a script or not
|
||||
PROJECT_ROOT="" # Path to the root of this SFDX project
|
||||
TARGET_ORG_ALIAS="" # Target of all Salesforce CLI commands during this run
|
||||
LOCAL_CONFIG_FILE_NAME=dev-tools/lib/local-config.sh # Name of the file that contains local config variables
|
||||
CURRENT_STEP=1 # Used by echoStepMsg() to indicate the current step
|
||||
TOTAL_STEPS=0 # Used by echoStepMsg() to indicate total num of steps
|
||||
CURRENT_QUESTION=1 # Used by echoQuestion() to indicate the current question
|
||||
TOTAL_QUESTIONS=1 # Used by echoQuestion() to indicate total num of questions
|
||||
|
||||
# Call findProjectRoot() to dynamically determine
|
||||
# the path to the root of this SFDX project
|
||||
findProjectRoot PROJECT_ROOT
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: installPackage () ###################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
installPackage () {
|
||||
# Delcare a local variable to store the Alias of the target install org.
|
||||
local PACKAGE_INSTALL_TARGET_ALIAS=""
|
||||
|
||||
# Check if a target org was provided as the FOURTH argument. If there
|
||||
# is no FOURTH argument, go with whatever is set in the TARGET_ORG_ALIAS
|
||||
# variable. If that is empty, then exit with an error.
|
||||
if [ ! -z $4 ]; then
|
||||
PACKAGE_INSTALL_TARGET_ALIAS="$4"
|
||||
elif [ ! -z $TARGET_ORG_ALIAS ]; then
|
||||
PACKAGE_INSTALL_TARGET_ALIAS="$TARGET_ORG_ALIAS"
|
||||
else
|
||||
# Something went wrong. No FOURTH argument was provided and the TARGET_ORG_ALIAS
|
||||
# has not yet been set or is an empty string. Raise an error message and
|
||||
# then exit 1 to kill the script.
|
||||
echoErrorMsg "Could not execute installPackage(). Unknown target org alias."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Echo the string provided by argument three. This string should provide the
|
||||
# user with an easy-to-understand idea of what package is being installed.
|
||||
echoStepMsg "$3"
|
||||
|
||||
# Print the time (HH:MM:SS) when the installation started.
|
||||
echo "Executing force:package:install --package $1 --publishwait 5 --wait 10 -u $PACKAGE_INSTALL_TARGET_ALIAS"
|
||||
echo "\n`tput bold`Package installation started at `date +%T``tput sgr0`\n"
|
||||
local startTime=`date +%s`
|
||||
|
||||
# Perform the package installation. If the installation fails abort the script.
|
||||
(cd $PROJECT_ROOT && exec sfdx force:package:install --package $1 --publishwait 5 --wait 10 -u $PACKAGE_INSTALL_TARGET_ALIAS)
|
||||
if [ $? -ne 0 ]; then
|
||||
echoErrorMsg "$2 could not be installed. Aborting Script."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Print the time (HH:MM:SS) when the installation completed.
|
||||
echo "\n`tput bold`Package installation completed at `date +%T``tput sgr0`"
|
||||
local endTime=`date +%s`
|
||||
|
||||
# Determine the total runtime (in seconds) and show the user.
|
||||
local totalRuntime=$((endTime-startTime))
|
||||
echo "Total runtime for package installation was $totalRuntime seconds."
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: resetQuestionCounter () #############################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
resetQuestionCounter () {
|
||||
CURRENT_QUESTION=1
|
||||
TOTAL_QUESTIONS=$1
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: resetStepMsgCounter () ##############################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
resetStepMsgCounter () {
|
||||
CURRENT_STEP=1
|
||||
TOTAL_STEPS=$1
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: showPressAnyKeyPrompt ###############################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
showPressAnyKeyPrompt () {
|
||||
read -n 1 -sr -p "-- Press any Key to Continue --"
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: suggestDefaultValue #################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
suggestDefaultValue () {
|
||||
# Make sure a value was provided for the
|
||||
# second argument of this function.
|
||||
if [ "$2" = "" ]; then
|
||||
echoErrorMsg "You must provide two arguments to suggestDefaultValue. Terminating script."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create local variables to store the value of
|
||||
# the variable provided by the first argument and the
|
||||
# value of the second argument (proposed default)
|
||||
eval "local LOCAL_VALUE=\$$1"
|
||||
eval "local LOCAL_DEFAULT=\"$2\""
|
||||
|
||||
# Set a defualt prompt message in case one is not provided.
|
||||
local INTERNAL_USER_PROMPT="Would you like to accept the following default value?"
|
||||
|
||||
# If the caller supplied a third argument, it means they want
|
||||
# a specific message to be shown before accepting the default.
|
||||
# If they did now, we will use owr own "default" message.
|
||||
if [ ! -z "$3" ]; then
|
||||
INTERNAL_USER_PROMPT="$3"
|
||||
fi
|
||||
|
||||
# Show prompt and display what the default var assignment would be.
|
||||
echo $INTERNAL_USER_PROMPT
|
||||
echo "\n"$1=$LOCAL_DEFAULT"\n"
|
||||
|
||||
# Ask user to confirm or reject the proposed value.
|
||||
local ACCEPT_DEFAULT=""
|
||||
read -p "(type YES to accept, NO to provide a different value) " ACCEPT_DEFAULT
|
||||
if [ "$ACCEPT_DEFAULT" != "YES" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Store the value from arg 2 into arg 1, basically
|
||||
# using the "default" value for the main value.
|
||||
eval "$1=\"$2\""
|
||||
|
||||
return 0
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### BEGIN MAIN EXECUTION BLOCK ####################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
# INITIALIZE HELPER VARIABLES
|
||||
initializeHelperVariables
|
||||
|
||||
# CHECK IF LOCAL CONFIG SHOULD BE SUPPRESSED.
|
||||
# If $SUPPRESS_LOCAL_CONFIG has been set to "true" DO NOT load the local configuration
|
||||
# variables. A script that includes shared-functions.sh can set this variable to
|
||||
# force this behavior (dev-tools/setup-core-project for example).
|
||||
if [ "$SUPPRESS_LOCAL_CONFIG" = "true" ]; then
|
||||
# Comment out the following line unless you're debugging setup-core-project.
|
||||
# echo "Local dev-tools configuration (local-config.sh) has been suppressed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# CHECK IF LOCAL CONFIG FILE EXISTS
|
||||
# Look for the local config variables script local-config.sh. If the developer has not created a
|
||||
# local-config.sh file in dev-tools/lib then EXIT from the shell script with an error message.
|
||||
if [ ! -r "$PROJECT_ROOT/$LOCAL_CONFIG_FILE_NAME" ]; then
|
||||
echoErrorMsg "Local dev-tools configuration file not found"
|
||||
tput sgr 0; tput bold;
|
||||
echo "Please create a local-config.sh file in your dev-tools/lib directory by copying"
|
||||
echo "dev-tools/templates/local-config-template.sh and customizing it with your local settings\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# LOAD THE LOCAL CONFIG VARIABLES
|
||||
# The local-config.sh file was found and is readable. Source (execute) it the current shell process.
|
||||
# This will make all the variables defined in local-config.sh available to all commands that come
|
||||
# after it in this shell.
|
||||
source "$PROJECT_ROOT/$LOCAL_CONFIG_FILE_NAME"
|
||||
|
||||
# MARK THAT LOCAL CONFIG VARIABLES HAVE BEEN SET.
|
||||
# Indicates that local config variables have been successfully set.
|
||||
SFDX_FALCON_FRAMEWORK_SHELL_VARS_SET="true"
|
||||
|
||||
|
||||
##END##
|
||||
Executable
+262
@@ -0,0 +1,262 @@
|
||||
#!/bin/bash
|
||||
####################################################################################################
|
||||
#
|
||||
# FILENAME: rebuild-scratch-org
|
||||
#
|
||||
# PURPOSE: Deletes then recreates a scratch org based on the SFDX source in this project.
|
||||
#
|
||||
# DESCRIPTION: Executing this script will first delete the exisisting default scratch org for
|
||||
# this project (if it exists), then create a new one using the source and config
|
||||
# information defined in your dev-tools/lib/local-config.sh file.
|
||||
#
|
||||
# INSTRUCTIONS: Execute the following command from the root of your SFDX project directory.
|
||||
# ./dev-tools/rebuild-scratch-org
|
||||
#
|
||||
####################################################################################################
|
||||
#
|
||||
##
|
||||
###
|
||||
#### LOAD SHARED FUNCTIONS LIBRARY #################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
# Make sure that the shared-functions.sh script exists.
|
||||
if [ ! -r `dirname $0`/lib/shared-functions.sh ]; then
|
||||
echo "\nFATAL ERROR: `tput sgr0``tput setaf 1`Could not load dev-tools/lib/shared-functions.sh. File not found.\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Indicate the operation being carried out by this script.
|
||||
REQUESTED_OPERATION="REBUILD_SCRATCH_ORG"
|
||||
|
||||
# Load the shared-functions.sh library. This action will also cause the
|
||||
# config variables from dev-tools/lib/local-config.sh to be loaded.
|
||||
source `dirname $0`/lib/shared-functions.sh
|
||||
#
|
||||
##
|
||||
###
|
||||
#### CONFIRM SCRIPT EXECUTION ######################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
confirmScriptExecution "Do you want to rebuild your scratch org?"
|
||||
#
|
||||
##
|
||||
###
|
||||
#### CREATE LOCAL VARIABLES ########################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
# The default version of this script does not require additional local
|
||||
# variables. If your customized script does require them, this is where
|
||||
# you would define and initialize them.
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: assignPermset () ####################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
assignPermset () {
|
||||
# Assign permission sets to the scratch org's Admin user.
|
||||
echoStepMsg "Assign the $1 permission set to the scratch org's Admin user"
|
||||
echo \
|
||||
"Executing force:user:permset:assign \\
|
||||
--permsetname "$1" \\
|
||||
--targetusername $SCRATCH_ORG_ALIAS \\
|
||||
--loglevel error\n"
|
||||
(cd $PROJECT_ROOT && exec sfdx force:user:permset:assign \
|
||||
--permsetname "$1" \
|
||||
--targetusername $SCRATCH_ORG_ALIAS \
|
||||
--loglevel error)
|
||||
if [ $? -ne 0 ]; then
|
||||
echoErrorMsg "Permission set \"$1\" could not be assigned to the admin user. Aborting Script."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: createScratchOrg () #################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
createScratchOrg() {
|
||||
# Create a new scratch org using the scratch-def.json locally configured for this project.
|
||||
echoStepMsg "Create a new $SCRATCH_ORG_ALIAS scratch org"
|
||||
echo "Executing force:org:create -f $SCRATCH_ORG_CONFIG -a $SCRATCH_ORG_ALIAS -v $DEV_HUB_ALIAS -s -d 29"
|
||||
(cd $PROJECT_ROOT && exec sfdx force:org:create -f $SCRATCH_ORG_CONFIG -a $SCRATCH_ORG_ALIAS -v $DEV_HUB_ALIAS -s -d 29)
|
||||
if [ $? -ne 0 ]; then
|
||||
echoErrorMsg "Scratch org could not be created. Aborting Script."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: deleteScratchOrg () #################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
deleteScratchOrg () {
|
||||
# Delete the current scratch org.
|
||||
echoStepMsg "Delete the $SCRATCH_ORG_ALIAS scratch org"
|
||||
echo "Executing force:org:delete -p -u $SCRATCH_ORG_ALIAS -v $DEV_HUB_ALIAS"
|
||||
(cd $PROJECT_ROOT && exec sfdx force:org:delete -p -u $SCRATCH_ORG_ALIAS -v $DEV_HUB_ALIAS )
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: importData () #######################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
importData () {
|
||||
# Setup development data
|
||||
echoStepMsg "Import data from $1"
|
||||
echo \
|
||||
"Executing force:data:tree:import \\
|
||||
--plan \"$1\" \\
|
||||
--targetusername $SCRATCH_ORG_ALIAS \\
|
||||
--loglevel error)\n"
|
||||
(cd $PROJECT_ROOT && exec sfdx force:data:tree:import \
|
||||
--plan "$1" \
|
||||
--targetusername $SCRATCH_ORG_ALIAS \
|
||||
--loglevel error)
|
||||
if [ $? -ne 0 ]; then
|
||||
echoErrorMsg "Data import failed. Aborting Script."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: installPackage () ###################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
installPackage () {
|
||||
# Echo the string provided by argument three. This string should provide the
|
||||
# user with an easy-to-understand idea of what package is being installed.
|
||||
echoStepMsg "$3"
|
||||
|
||||
# Print the time (HH:MM:SS) when the installation started.
|
||||
echo "Executing force:package:install -i $1 -p 5 -w 10 -u $SCRATCH_ORG_ALIAS"
|
||||
echo "\n`tput bold`Package installation started at `date +%T``tput sgr0`\n"
|
||||
local startTime=`date +%s`
|
||||
|
||||
# Perform the package installation. If the installation fails abort the script.
|
||||
(cd $PROJECT_ROOT && exec sfdx force:package:install -i $1 -p 5 -w 10 -u $SCRATCH_ORG_ALIAS)
|
||||
if [ $? -ne 0 ]; then
|
||||
echoErrorMsg "$2 could not be installed. Aborting Script."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Print the time (HH:MM:SS) when the installation completed.
|
||||
echo "\n`tput bold`Package installation completed at `date +%T``tput sgr0`"
|
||||
local endTime=`date +%s`
|
||||
|
||||
# Determine the total runtime (in seconds) and show the user.
|
||||
local totalRuntime=$((endTime-startTime))
|
||||
echo "Total runtime for package installation was $totalRuntime seconds."
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: pushMetadata () #####################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
pushMetadata () {
|
||||
# Push metadata to the new Scratch Org.
|
||||
echoStepMsg "Push metadata to the new scratch org"
|
||||
echo "Executing force:source:push -u $SCRATCH_ORG_ALIAS"
|
||||
(cd $PROJECT_ROOT && exec sfdx force:source:push -u $SCRATCH_ORG_ALIAS)
|
||||
if [ $? -ne 0 ]; then
|
||||
echoErrorMsg "SFDX source could not be pushed to the scratch org. Aborting Script."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### FUNCTION: validateScratchOrgDeletion () #######################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
validateScratchOrgDeletion () {
|
||||
# Confirm that the scratch org is no longer the default username in SFDX local config.
|
||||
echoStepMsg "Validate deletion of the scratch org"
|
||||
echo "Executing sfdx force:config:list to confirm deletion from project local config"
|
||||
(cd $PROJECT_ROOT && exec sfdx force:config:list)
|
||||
}
|
||||
#
|
||||
##
|
||||
###
|
||||
#### SCRATCH ORG SETUP (DELETE/CREATE/PUSH) ########################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
# STEP 0
|
||||
# Reset the Step Message counter to reflect the number of TOTAL STEPS
|
||||
# in your rebuild process. For the baseline SFDX-Falcon template it's 4.
|
||||
resetStepMsgCounter 5
|
||||
|
||||
# STEPS 1 and 2
|
||||
# Delete the current scratch org.
|
||||
deleteScratchOrg
|
||||
|
||||
# STEP 3
|
||||
# Create a new scratch org using the scratch-def.json locally configured for this project.
|
||||
createScratchOrg
|
||||
|
||||
# STEP 4 through ???
|
||||
# Install any packages (managed or unmanaged).
|
||||
# Template for calling this function:
|
||||
# installPackage #PACKAGE_VERSION_ID# \
|
||||
# "#PACKAGE_NAME#" \
|
||||
# "#STEP_MESSAGE#"
|
||||
echoStepMsg "Installing fflib-apex-mocks and fflib-apex-common to $SCRATCH_ORG_ALIAS scratch org"
|
||||
mkdir $PROJECT_ROOT/temp
|
||||
cd $PROJECT_ROOT/temp
|
||||
rm -Rf fflib-apex-mocks/
|
||||
rm -Rf fflib-apex-common/
|
||||
git clone https://github.com/apex-enterprise-patterns/fflib-apex-mocks.git
|
||||
git clone https://github.com/apex-enterprise-patterns/fflib-apex-common.git
|
||||
|
||||
sfdx force:source:deploy -p ./fflib-apex-mocks/sfdx-source -u $SCRATCH_ORG_ALIAS
|
||||
sfdx force:source:deploy -p ./fflib-apex-common/sfdx-source -u $SCRATCH_ORG_ALIAS
|
||||
|
||||
|
||||
# STEP 5 through ???
|
||||
# Assign any permission sets that were added by installed packages.
|
||||
# Template for calling this function:
|
||||
# assignPermset #PACKAGED_PERMSET_NAME#
|
||||
|
||||
# STEP 6
|
||||
# Push metadata to the new Scratch Org.
|
||||
pushMetadata
|
||||
|
||||
# STEP 7 through ????
|
||||
# Assign any permission sets that were added by your Source Push.
|
||||
# Template for calling this function:
|
||||
# assignPermset #PERMSET_NAME#
|
||||
|
||||
# STEP 8 through ????
|
||||
# Import data used during development. You may need to make multiple calls
|
||||
# Template for calling this function:
|
||||
# importData "$PROJECT_ROOT/data/#DATA_PLAN_JSON#"
|
||||
|
||||
#
|
||||
##
|
||||
###
|
||||
#### ECHO CLOSING MESSAGE ##########################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
echoScriptCompleteMsg \
|
||||
"Rebuild of scratch org $SCRATCH_ORG_ALIAS completed successfully."
|
||||
|
||||
exit 0
|
||||
|
||||
##END##
|
||||
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
#<%%#
|
||||
####################################################################################################
|
||||
#
|
||||
# FILENAME: local-config-template.sh.ejs
|
||||
#
|
||||
# PURPOSE: Template for creating a personalized local-config.sh file.
|
||||
#
|
||||
# DESCRIPTION: All shell scripts in the dev-tools directory require several configuration values
|
||||
# to run correctly (eg. the path to your project's root directory or the alias of
|
||||
# the DevHub that you want to use. These customizations can be specific to each
|
||||
# individual developer, and therefore should not be tracked by the project's VCS.
|
||||
#
|
||||
# This file serves as a template that Release Managers can use to establish baseline
|
||||
# values for their project. When individaul developers clone the repo and initialize
|
||||
# their local, personal version of the project this template is used to create a
|
||||
# customized local-config.sh file at <project-root>/dev-tools/lib/local-config.sh
|
||||
#
|
||||
# INSTRUCTIONS: 1. Inside of the dev-tools directory, execute the following command
|
||||
# cp ./templates/local-config-template.sh.ejs ./lib/local-config.sh
|
||||
# 2. Edit the default values in your local-config.sh to meet the needs of your local
|
||||
# environment and project setup.
|
||||
#
|
||||
####################################################################################################
|
||||
#%>
|
||||
##
|
||||
###
|
||||
#### DEFINE LOCAL CONFIGURATION VARIABLES ##########################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
# Alias for the Dev Hub that should be used when creating scratch orgs for this project.
|
||||
# This variable will always need to be customized for individual developers.
|
||||
DEV_HUB_ALIAS="<%%-userAnswers.devHubAlias%>"
|
||||
|
||||
# Namespace Prefix. Set to empty string ("") if this project is not building a managed package.
|
||||
NAMESPACE_PREFIX="<%-userAnswers.namespacePrefix%>"
|
||||
|
||||
# Package Name. Specified as part of the Package Detail info in your packaging org.
|
||||
# Surround this value with double-quotes if your package name contains space characters.
|
||||
# Set to empty string ("") if this project is not building a managed package.
|
||||
PACKAGE_NAME="<%-userAnswers.packageName%>"
|
||||
|
||||
# Metadata Package ID. Refers to the metadata package as a whole. Must begin with "033".
|
||||
# Set to empty string ("") if this project is not building a managed package.
|
||||
METADATA_PACKAGE_ID="<%-userAnswers.metadataPackageId%>"
|
||||
|
||||
# Package Version ID. Refers to a specific, installable version of a package. Must begin with "04t".
|
||||
# Set to empty string ("") if this project is not building a managed package.
|
||||
PACKAGE_VERSION_ID="<%-userAnswers.packageVersionId%>"
|
||||
|
||||
# Default Package Directory. Should match what is set in sfdx-project.json.
|
||||
DEFAULT_PACKAGE_DIR_NAME="<%-userAnswers.packageDirectory%>"
|
||||
|
||||
# Alias for the primary Scratch Org used by this project.
|
||||
SCRATCH_ORG_ALIAS="$NAMESPACE_PREFIX-SCRATCH"
|
||||
|
||||
# Alias for the packaging org for this project.
|
||||
PACKAGING_ORG_ALIAS="$NAMESPACE_PREFIX-PACKAGE"
|
||||
|
||||
# Alias for the subscriber test org used to test managed-beta package installs.
|
||||
SUBSCRIBER_ORG_ALIAS="$NAMESPACE_PREFIX-SUBSCRIBER"
|
||||
|
||||
# Git Remote URI. SSH or HTTPS URI that points to the Git remote repo used by this project.
|
||||
# GitHub is used as an example here, but any Git remote (ie. BitBucket) can be used.
|
||||
# Set to empty string ("") if this project is not being tracked in a remote repository.
|
||||
GIT_REMOTE_URI="<%-userAnswers.gitRemoteUri%>"
|
||||
|
||||
# Location of the primary scratch-def.json file that should be used by SFDX-Falcon scripts that
|
||||
# create scratch orgs (eg. rebuild-scratch-org).
|
||||
SCRATCH_ORG_CONFIG="$PROJECT_ROOT/config/project-scratch-def.json"
|
||||
|
||||
# Echo the variables set by this script prior to exiting. Specify "false" to suppress the
|
||||
# display of local config that normally occurs when executing SFDX-Falcon based scripts.
|
||||
ECHO_LOCAL_CONFIG_VARS="true"
|
||||
#
|
||||
##
|
||||
###
|
||||
#### ECHO ALL VARIABLES ############################################################################
|
||||
###
|
||||
##
|
||||
#
|
||||
if [ "$ECHO_LOCAL_CONFIG_VARS" = "true" ]; then
|
||||
echo "\n`tput setaf 7``tput bold`Local configuration variables set by `dirname $0`/lib/local-config.sh`tput sgr0`\n"
|
||||
echoConfigVariables
|
||||
fi
|
||||
##END##
|
||||
+1
-1
@@ -150,7 +150,7 @@ public virtual class fflib_ClassicDomainFactory
|
||||
* 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)
|
||||
public virtual void setMock(Object domainType, fflib_IDomain mockDomain)
|
||||
{
|
||||
mockDomainByObject.put(domainType, mockDomain);
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* File Name: fflib_AppBinding
|
||||
* Description: Definition for an Application Binding
|
||||
*
|
||||
* @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_AppBinding
|
||||
implements fflib_IAppBinding, Comparable
|
||||
{
|
||||
protected Object bindingObject { get; set; }
|
||||
protected Decimal bindingSequence { get; set; }
|
||||
protected fflib_AppBindingType bindingType { get; set; }
|
||||
protected System.Type implementationType { get; set; }
|
||||
protected System.Type interfaceType { get; set; }
|
||||
protected String namespacePrefix { get; set; }
|
||||
protected fflib_SharingMode sharingMode { get; set; }
|
||||
|
||||
public Integer compareTo(Object compareTo)
|
||||
{
|
||||
fflib_IAppBinding compareToEmp = (fflib_IAppBinding) compareTo;
|
||||
if (getSequence() == compareToEmp.getSequence()) return 0;
|
||||
if (getSequence() > compareToEmp.getSequence()) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public Object getBindingObject()
|
||||
{
|
||||
return this.bindingObject;
|
||||
}
|
||||
|
||||
public virtual fflib_AppBindingType getBindingType()
|
||||
{
|
||||
return this.bindingType;
|
||||
}
|
||||
|
||||
public virtual System.Type getImplementationType()
|
||||
{
|
||||
return this.implementationType;
|
||||
}
|
||||
|
||||
public Type getInterfaceType()
|
||||
{
|
||||
return this.interfaceType;
|
||||
}
|
||||
|
||||
public String getNamespacePrefix()
|
||||
{
|
||||
return this.namespacePrefix;
|
||||
}
|
||||
|
||||
public Decimal getSequence()
|
||||
{
|
||||
return this.bindingSequence;
|
||||
}
|
||||
|
||||
public fflib_SharingMode getSharingMode()
|
||||
{
|
||||
return this.sharingMode;
|
||||
}
|
||||
|
||||
public virtual Object newImplInstance()
|
||||
{
|
||||
return implementationType.newInstance();
|
||||
}
|
||||
|
||||
public virtual fflib_IAppBinding setBindingObject(Object bindingObject)
|
||||
{
|
||||
this.bindingObject = bindingObject;
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual fflib_IAppBinding setBindingType(fflib_AppBindingType bindingType)
|
||||
{
|
||||
this.bindingType = bindingType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual fflib_IAppBinding setNamespacePrefix(String namespacePrefix)
|
||||
{
|
||||
this.namespacePrefix = namespacePrefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual fflib_IAppBinding setImplementationType(System.Type implementationType)
|
||||
{
|
||||
this.implementationType = implementationType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual fflib_IAppBinding setInterfaceType(Type interfaceType)
|
||||
{
|
||||
this.interfaceType = interfaceType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual fflib_IAppBinding setSequence(Decimal sequence)
|
||||
{
|
||||
this.bindingSequence = sequence;
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual fflib_IAppBinding setSharingMode(fflib_SharingMode sharingMode)
|
||||
{
|
||||
this.sharingMode = sharingMode;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* File Name: fflib_AppBindingMetaDataModule
|
||||
* Description: An application module responsible for loading the application bindings
|
||||
*
|
||||
* @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 with sharing class fflib_AppBindingMetaDataModule
|
||||
extends fflib_AppBindingModule
|
||||
{
|
||||
public override void init()
|
||||
{
|
||||
this.bindings = new List<fflib_IAppBinding>();
|
||||
for (fflib_AppBinding__mdt binding : fflib_AppBindingsSelector.newInstance().selectAll())
|
||||
{
|
||||
addBinding(
|
||||
new fflib_AppBinding()
|
||||
.setBindingObject(getBindingObject(binding))
|
||||
.setBindingType(getBindingType(binding))
|
||||
.setImplementationType(getSystemType(binding, fflib_AppBinding__mdt.ImplementationType__c))
|
||||
.setInterfaceType(getSystemType(binding, fflib_AppBinding__mdt.InterfaceType__c))
|
||||
.setNamespacePrefix(binding.NamespacePrefix)
|
||||
.setSequence(binding.BindingSequence__c)
|
||||
.setSharingMode(getSharingModeFromString(binding.SharingMode__c))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private Object getBindingObject(fflib_AppBinding__mdt binding)
|
||||
{
|
||||
if (String.isBlank(binding.BindingObject__c) && String.isBlank(binding.BindingObjectAlternate__c)) return null;
|
||||
|
||||
String bindingObjectApiName = String.isNotBlank(binding.BindingObject__c)
|
||||
? binding.BindingObject__r.QualifiedApiName.toLowerCase().trim()
|
||||
: binding.BindingObjectAlternate__c.toLowerCase().trim();
|
||||
|
||||
// Assume its an SObjectType
|
||||
List<Schema.DescribeSObjectResult> schemaDescribes = Schema.describeSObjects(new List<String> {bindingObjectApiName});
|
||||
if (schemaDescribes.size() == 1)
|
||||
{
|
||||
return schemaDescribes.get(0).getSObjectType();
|
||||
}
|
||||
else
|
||||
{
|
||||
// check if its an Object (class)
|
||||
Type objectType = System.Type.forName(bindingObjectApiName);
|
||||
if (objectType == null)
|
||||
throw new DeveloperException('Failed to find (S)Object ' + bindingObjectApiName + ' referenced by binding ' + binding.DeveloperName);
|
||||
|
||||
return objectType;
|
||||
}
|
||||
}
|
||||
|
||||
private fflib_AppBindingType getBindingType(fflib_AppBinding__mdt binding)
|
||||
{
|
||||
Map<String, fflib_AppBindingType> bindingTypeByStrings = new Map<String, fflib_AppBindingType>();
|
||||
for (fflib_AppBindingType enumValue : fflib_AppBindingType.values())
|
||||
{
|
||||
bindingTypeByStrings.put(String.valueOf(enumValue).toUpperCase(), enumValue);
|
||||
}
|
||||
|
||||
if (bindingTypeByStrings.containsKey(binding.Type__c.toUpperCase()) == false)
|
||||
throw new DeveloperException(
|
||||
String.format(
|
||||
'Unable to identify binding type {0} referenced by binding {1}',
|
||||
new List<String>{ binding.Type__c, binding.DeveloperName}
|
||||
)
|
||||
);
|
||||
|
||||
return bindingTypeByStrings.get(binding.Type__c.toUpperCase());
|
||||
}
|
||||
|
||||
private fflib_SharingMode getSharingModeFromString(String sharingMode)
|
||||
{
|
||||
switch on sharingMode.toUpperCase()
|
||||
{
|
||||
when 'WITH SHARING'
|
||||
{
|
||||
return fflib_SharingMode.WithSharing;
|
||||
}
|
||||
when 'WITHOUT SHARING'
|
||||
{
|
||||
return fflib_SharingMode.WithoutSharing;
|
||||
}
|
||||
when 'INHERITED SHARING'
|
||||
{
|
||||
return fflib_SharingMode.WithoutSharing;
|
||||
}
|
||||
when 'NONE'
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Type getSystemType(fflib_AppBinding__mdt binding, Schema.SObjectField sObjectField)
|
||||
{
|
||||
String systemTypeName = String.valueOf(binding.get(sObjectField));
|
||||
if (null == systemTypeName) return null;
|
||||
|
||||
Type systemType = System.Type.forName(systemTypeName);
|
||||
if (null == systemType)
|
||||
throw new DeveloperException(
|
||||
String.format(
|
||||
'Unable to find {0} referenced by binding {1} for {2}',
|
||||
new List<String>{ systemTypeName, binding.DeveloperName, sObjectField.getDescribe().getName()}
|
||||
)
|
||||
);
|
||||
return systemType;
|
||||
}
|
||||
|
||||
public class DeveloperException extends Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* File Name: fflib_AppBindingModule
|
||||
* Description: An application module is responsible for loading the application bindings
|
||||
*
|
||||
* @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_AppBindingModule
|
||||
implements fflib_IAppBindingModule
|
||||
{
|
||||
protected List<fflib_IAppBinding> bindings;
|
||||
|
||||
public fflib_AppBindingModule(){ }
|
||||
|
||||
public fflib_AppBindingModule(List<fflib_IAppBinding> bindings)
|
||||
{
|
||||
this.bindings = bindings;
|
||||
}
|
||||
|
||||
public virtual void addBinding(fflib_IAppBinding binding)
|
||||
{
|
||||
if (null == this.bindings) this.bindings = new List<fflib_IAppBinding>();
|
||||
|
||||
this.bindings.add(binding);
|
||||
}
|
||||
|
||||
public virtual void addBindings(List<fflib_IAppBinding> bindings)
|
||||
{
|
||||
if (null == this.bindings)
|
||||
{
|
||||
this.bindings = bindings;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.bindings.addAll(bindings);
|
||||
}
|
||||
}
|
||||
|
||||
public List<fflib_IAppBinding> getBindings()
|
||||
{
|
||||
return this.bindings;
|
||||
}
|
||||
|
||||
public virtual void init()
|
||||
{
|
||||
if (null == this.bindings) this.bindings = new List<fflib_IAppBinding>();
|
||||
}
|
||||
}
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
/**
|
||||
* File Name: fflib_AppBindingResolver
|
||||
* Description: Resolver for returning the requested binding(s)
|
||||
*
|
||||
* @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_AppBindingResolver
|
||||
implements fflib_IAppBindingResolver
|
||||
{
|
||||
// allow for dependency injection inside the resolver
|
||||
protected InternalBindings internalBindings
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == internalBindings)
|
||||
{
|
||||
internalBindings = new InternalBindings();
|
||||
}
|
||||
return internalBindings;
|
||||
}
|
||||
private set;
|
||||
}
|
||||
|
||||
protected fflib_IAppBinding bindingToResolve
|
||||
{
|
||||
get
|
||||
{
|
||||
if (bindingToResolve == null)
|
||||
{
|
||||
bindingToResolve = internalBindings.newAppBinding();
|
||||
}
|
||||
return bindingToResolve;
|
||||
}
|
||||
private set;
|
||||
}
|
||||
|
||||
protected fflib_IAppBindings bindings;
|
||||
private List<fflib_IAppBindingModule> modules;
|
||||
|
||||
public static fflib_IAppBindingResolver newInstance()
|
||||
{
|
||||
return new fflib_AppBindingResolver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructors
|
||||
*/
|
||||
public fflib_AppBindingResolver()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Providing routes to the AppBindingResolver constructor provides dependency injection inside the resolver
|
||||
*
|
||||
* @param routes The routes
|
||||
*/
|
||||
public fflib_AppBindingResolver(fflib_IAppBindingRouter routes)
|
||||
{
|
||||
this(routes.getRoutes());
|
||||
}
|
||||
|
||||
public fflib_AppBindingResolver(Map<System.Type, System.Type> internalBindings)
|
||||
{
|
||||
this.internalBindings = new InternalBindings(internalBindings);
|
||||
}
|
||||
|
||||
public fflib_IAppBindingResolver addModule(fflib_IAppBindingModule bindingModule)
|
||||
{
|
||||
if (null == this.modules) this.modules = new List<fflib_IAppBindingModule>();
|
||||
|
||||
this.modules.add(bindingModule);
|
||||
return this;
|
||||
}
|
||||
|
||||
public fflib_IAppBindingResolver byObject(Object bindingObject)
|
||||
{
|
||||
this.bindingToResolve.setBindingObject(bindingObject);
|
||||
return this;
|
||||
}
|
||||
|
||||
public fflib_IAppBindingResolver bySequence(Integer sequence)
|
||||
{
|
||||
this.bindingToResolve.setSequence(sequence);
|
||||
return this;
|
||||
}
|
||||
|
||||
public fflib_IAppBindingResolver byType(fflib_AppBindingType bindingType)
|
||||
{
|
||||
this.bindingToResolve.setBindingType(bindingType);
|
||||
return this;
|
||||
}
|
||||
|
||||
public fflib_IAppBindingResolver byInterfaceType(Type interfaceType)
|
||||
{
|
||||
this.bindingToResolve.setInterfaceType(interfaceType);
|
||||
return this;
|
||||
}
|
||||
|
||||
public fflib_IAppBindingResolver bySharingMode(fflib_SharingMode sharingMode)
|
||||
{
|
||||
this.bindingToResolve.setSharingMode(sharingMode);
|
||||
return this;
|
||||
}
|
||||
|
||||
public fflib_IAppBindingResolver byNamespacePrefix(String namespacePrefix)
|
||||
{
|
||||
this.bindingToResolve.setNamespacePrefix(namespacePrefix);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles lazy loading of modules, if no custom module is configured (via addModule) the default module is returned
|
||||
*
|
||||
* @return Returns the configured modules
|
||||
*/
|
||||
public List<fflib_IAppBindingModule> getModules()
|
||||
{
|
||||
if (null == this.modules)
|
||||
{
|
||||
// Lazy load the default Binding module is none other is set.
|
||||
modules = new List<fflib_IAppBindingModule>
|
||||
{
|
||||
internalBindings.newAppBindingModule()
|
||||
};
|
||||
}
|
||||
return modules;
|
||||
}
|
||||
|
||||
public List<fflib_IAppBinding> resolve()
|
||||
{
|
||||
if (!hasBindingsLoaded()) loadBindings();
|
||||
|
||||
fflib_IAppBindings resolvedBindings =
|
||||
this.bindings
|
||||
.selectByNamespacePrefix(bindingToResolve.getNamespacePrefix())
|
||||
.selectByType(bindingToResolve.getBindingType())
|
||||
.selectByInterfaceType(bindingToResolve.getInterfaceType())
|
||||
.selectByObject(bindingToResolve.getBindingObject())
|
||||
.selectBySharingMode(bindingToResolve.getSharingMode())
|
||||
.selectBySequence(bindingToResolve.getSequence());
|
||||
|
||||
this.bindingToResolve = internalBindings.newAppBinding();
|
||||
return resolvedBindings.getBindings();
|
||||
}
|
||||
|
||||
|
||||
protected Boolean hasBindingsLoaded()
|
||||
{
|
||||
return (this.bindings != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a domain to store the bindings,
|
||||
* retrieves the bindings from the modules
|
||||
* and stores the bindings in this.bindings
|
||||
*/
|
||||
protected virtual void loadBindings()
|
||||
{
|
||||
this.bindings = internalBindings.newAppBindings();
|
||||
List<fflib_IAppBindingModule> modules = getModules();
|
||||
List<fflib_IAppBinding> appBindings = loadModules(modules);
|
||||
this.bindings.addBindings(
|
||||
appBindings
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises all the modules and retrieves their binding.
|
||||
* Any child modules in all nested will also be initialised and processed
|
||||
*
|
||||
* @param modules The modules to load their binding
|
||||
*
|
||||
* @return Returns the bindings configured in the given modules
|
||||
*/
|
||||
protected virtual List<fflib_IAppBinding> loadModules(List<fflib_IAppBindingModule> modules)
|
||||
{
|
||||
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
|
||||
for (fflib_IAppBindingModule module : getModules())
|
||||
{
|
||||
module.init();
|
||||
List<fflib_IAppBinding> bindings = module.getBindings();
|
||||
List<fflib_IAppBindingModule> subModules = getModulesFromBindings(bindings);
|
||||
|
||||
if (subModules.isEmpty() == false)
|
||||
{
|
||||
result.addAll(
|
||||
loadModules(subModules)
|
||||
);
|
||||
}
|
||||
result.addAll(bindings);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the bindings of the type module from the given list and returns their instance
|
||||
*
|
||||
* @param bindings The bindings to filter
|
||||
*
|
||||
* @return Returns the instances of Module bindings
|
||||
*/
|
||||
private List<fflib_IAppBindingModule> getModulesFromBindings(List<fflib_IAppBinding> bindings)
|
||||
{
|
||||
List<fflib_IAppBindingModule> result = new List<fflib_IAppBindingModule>();
|
||||
for (fflib_IAppBinding binding : bindings)
|
||||
{
|
||||
if (binding.getBindingType() != fflib_AppBindingType.Module) continue;
|
||||
|
||||
Object instance = binding.newImplInstance();
|
||||
if (!(instance instanceof fflib_IAppBindingModule))
|
||||
throw new DeveloperException(
|
||||
'Binding module should be an instance of fflib_IAppBindingModule, instead found: '
|
||||
+ binding.getImplementationType().getName()
|
||||
);
|
||||
|
||||
result.add(
|
||||
(fflib_IAppBindingModule) instance
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public class InternalBindings
|
||||
{
|
||||
private Map<System.Type, System.Type> bindings;
|
||||
|
||||
public InternalBindings()
|
||||
{
|
||||
}
|
||||
|
||||
public InternalBindings(Map<System.Type, System.Type> internalBindings)
|
||||
{
|
||||
this.bindings = internalBindings;
|
||||
}
|
||||
|
||||
public fflib_IAppBinding newAppBinding()
|
||||
{
|
||||
System.Type interfaceType = fflib_IAppBinding.class;
|
||||
if (hasInternalBinding(interfaceType))
|
||||
{
|
||||
Object instance = getInternalBinding(interfaceType);
|
||||
if (!(instance instanceof fflib_IAppBinding))
|
||||
throw new DeveloperException('Invalid internal binding for fflib_IAppBinding');
|
||||
|
||||
return (fflib_IAppBinding) instance;
|
||||
}
|
||||
|
||||
return new fflib_AppBinding();
|
||||
}
|
||||
|
||||
public fflib_IAppBindings newAppBindings()
|
||||
{
|
||||
System.Type interfaceType = fflib_IAppBindings.class;
|
||||
if (hasInternalBinding(interfaceType))
|
||||
{
|
||||
Object instance = getInternalBinding(interfaceType);
|
||||
if (!(instance instanceof fflib_IAppBinding))
|
||||
throw new DeveloperException('Invalid internal binding for fflib_IAppBindings');
|
||||
|
||||
return (fflib_IAppBindings) instance;
|
||||
}
|
||||
|
||||
return new fflib_AppBindings();
|
||||
}
|
||||
|
||||
private Boolean hasInternalBinding(System.Type interfaceType)
|
||||
{
|
||||
return this.bindings != null && this.bindings.containsKey(interfaceType);
|
||||
}
|
||||
|
||||
private Object getInternalBinding(System.Type interfaceType)
|
||||
{
|
||||
return this.bindings.get(interfaceType).newInstance();
|
||||
}
|
||||
|
||||
private fflib_IAppBindingModule newAppBindingModule()
|
||||
{
|
||||
System.Type interfaceType = fflib_IAppBindingModule.class;
|
||||
if (hasInternalBinding(interfaceType))
|
||||
{
|
||||
Object instance = getInternalBinding(interfaceType);
|
||||
if (!(instance instanceof fflib_IAppBindingModule))
|
||||
throw new DeveloperException('Invalid internal binding for fflib_IAppBindingModule');
|
||||
|
||||
return (fflib_IAppBindingModule) instance;
|
||||
}
|
||||
|
||||
return new fflib_AppBindingMetaDataModule();
|
||||
}
|
||||
}
|
||||
|
||||
public class DeveloperException extends Exception {}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* File Name: fflib_AppBindingType
|
||||
* Description: Enum for Binding Types
|
||||
*
|
||||
* @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 enum fflib_AppBindingType
|
||||
{
|
||||
Domain, Service, Selector, Controller, Module, Misc
|
||||
}
|
||||
+5
@@ -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,178 @@
|
||||
/**
|
||||
* File Name: fflib_AppBindings
|
||||
* Description: Domain class for fflib_AppBinding objects
|
||||
*
|
||||
* @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_AppBindings
|
||||
implements fflib_IAppBindings
|
||||
{
|
||||
protected List<fflib_IAppBinding> bindings;
|
||||
|
||||
public fflib_AppBindings() { }
|
||||
|
||||
public fflib_AppBindings(List<fflib_IAppBinding> bindings)
|
||||
{
|
||||
this.bindings = bindings;
|
||||
}
|
||||
|
||||
public void addBinding(fflib_IAppBinding binding)
|
||||
{
|
||||
if (null == this.bindings)
|
||||
{
|
||||
this.bindings = new List<fflib_IAppBinding>{ binding };
|
||||
}
|
||||
{
|
||||
this.bindings.add(binding);
|
||||
}
|
||||
}
|
||||
|
||||
public void addBindings(List<fflib_IAppBinding> bindings)
|
||||
{
|
||||
if (null == this.bindings)
|
||||
{
|
||||
this.bindings = bindings;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.bindings.addAll(bindings);
|
||||
}
|
||||
}
|
||||
|
||||
public fflib_IAppBindings selectByObject(Object bindingObject)
|
||||
{
|
||||
if (null == bindingObject) return this;
|
||||
|
||||
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
|
||||
for (fflib_IAppBinding binding : bindings)
|
||||
{
|
||||
if (binding.getBindingObject() != bindingObject) continue;
|
||||
|
||||
result.add(binding);
|
||||
}
|
||||
return new fflib_AppBindings(result);
|
||||
}
|
||||
|
||||
public fflib_IAppBindings selectBySequence(Decimal sequence)
|
||||
{
|
||||
bindings.sort();
|
||||
|
||||
if (null == sequence) return this;
|
||||
|
||||
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
|
||||
for (fflib_IAppBinding binding : bindings)
|
||||
{
|
||||
if (binding.getSequence() != sequence) continue;
|
||||
|
||||
result.add(binding);
|
||||
}
|
||||
return new fflib_AppBindings(result);
|
||||
}
|
||||
|
||||
public fflib_IAppBindings selectByType(fflib_AppBindingType bindingType)
|
||||
{
|
||||
if (null == bindingType) return this;
|
||||
|
||||
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
|
||||
for (fflib_IAppBinding binding : bindings)
|
||||
{
|
||||
if (binding.getBindingType() != bindingType) continue;
|
||||
|
||||
result.add(binding);
|
||||
}
|
||||
return new fflib_AppBindings(result);
|
||||
}
|
||||
|
||||
public fflib_IAppBindings selectByInterfaceType(Type interfaceType)
|
||||
{
|
||||
if (null == interfaceType) return this;
|
||||
|
||||
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
|
||||
for (fflib_IAppBinding binding : bindings)
|
||||
{
|
||||
if (binding.getInterfaceType() != interfaceType) continue;
|
||||
|
||||
result.add(binding);
|
||||
}
|
||||
return new fflib_AppBindings(result);
|
||||
}
|
||||
|
||||
public fflib_IAppBindings selectBySharingMode(fflib_SharingMode sharingMode)
|
||||
{
|
||||
if (null == sharingMode) return this;
|
||||
|
||||
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
|
||||
for (fflib_IAppBinding binding : bindings)
|
||||
{
|
||||
if (binding.getSharingMode() != sharingMode) continue;
|
||||
|
||||
result.add(binding);
|
||||
}
|
||||
return new fflib_AppBindings(result);
|
||||
}
|
||||
|
||||
public fflib_IAppBindings selectByNamespacePrefix(String namespacePrefix)
|
||||
{
|
||||
if (null == namespacePrefix) return this;
|
||||
|
||||
List<fflib_IAppBinding> result = new List<fflib_IAppBinding>();
|
||||
for (fflib_IAppBinding binding : bindings)
|
||||
{
|
||||
if (binding.getNamespacePrefix() != namespacePrefix) continue;
|
||||
|
||||
result.add(binding);
|
||||
}
|
||||
return new fflib_AppBindings(result);
|
||||
}
|
||||
|
||||
public List<fflib_IAppBinding> getBindings()
|
||||
{
|
||||
return this.bindings;
|
||||
}
|
||||
|
||||
public List<System.Type> getImplementations()
|
||||
{
|
||||
List<System.Type> result = new List<System.Type>();
|
||||
for (fflib_IAppBinding binding : bindings)
|
||||
{
|
||||
result.add(
|
||||
binding.getImplementationType()
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<Object> getObjects()
|
||||
{
|
||||
return getBindings();
|
||||
}
|
||||
|
||||
public Object getType()
|
||||
{
|
||||
return fflib_IAppBinding.class;
|
||||
}
|
||||
}
|
||||
+5
@@ -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>
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* File Name: fflib_AppBindingsSelector
|
||||
* Description: Selector for fflib_AppBinding__mdt records
|
||||
*
|
||||
* @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 without sharing class fflib_AppBindingsSelector extends fflib_SObjectSelector
|
||||
{
|
||||
// Used for mocking
|
||||
@TestVisible
|
||||
private static System.Type SELECTOR_IMPL_TYPE = fflib_AppBindingsSelector.class;
|
||||
|
||||
public List<Schema.SObjectField> getSObjectFieldList()
|
||||
{
|
||||
return new List<Schema.SObjectField>
|
||||
{
|
||||
fflib_AppBinding__mdt.Id,
|
||||
fflib_AppBinding__mdt.BindingObject__c,
|
||||
fflib_AppBinding__mdt.BindingObjectAlternate__c,
|
||||
fflib_AppBinding__mdt.BindingSequence__c,
|
||||
fflib_AppBinding__mdt.DeveloperName,
|
||||
fflib_AppBinding__mdt.NamespacePrefix,
|
||||
fflib_AppBinding__mdt.ImplementationType__c,
|
||||
fflib_AppBinding__mdt.InterfaceType__c,
|
||||
fflib_AppBinding__mdt.SharingMode__c,
|
||||
fflib_AppBinding__mdt.Type__c
|
||||
};
|
||||
}
|
||||
|
||||
public static fflib_AppBindingsSelector newInstance()
|
||||
{
|
||||
return (fflib_AppBindingsSelector) SELECTOR_IMPL_TYPE.newInstance();
|
||||
}
|
||||
|
||||
public Schema.SObjectType getSObjectType()
|
||||
{
|
||||
return fflib_AppBinding__mdt.SObjectType;
|
||||
}
|
||||
|
||||
public virtual List<fflib_AppBinding__mdt> selectAll()
|
||||
{
|
||||
/**
|
||||
Todo - Waiting to uncomment the following section
|
||||
until fflib-apex-common fixes the getFieldPath issue
|
||||
Currently failing on the BindingObject__r field,
|
||||
thinking its not a relationship field
|
||||
|
||||
Error on line 119, column 1: fflib_QueryFactory.NonReferenceFieldException:
|
||||
fflib_AppBinding__mdt.BindingObject__r is not a lookup or master-detail
|
||||
field but is used in a cross-object query field.
|
||||
|
||||
return (List<fflib_AppBinding__mdt>) Database.query(
|
||||
newQueryFactory()
|
||||
.selectField('BindingObject__r.QualifiedApiName')
|
||||
.toSOQL());
|
||||
*/
|
||||
|
||||
return (List<fflib_AppBinding__mdt>) Database.query(
|
||||
String.format(
|
||||
'SELECT {0} FROM {1}',
|
||||
new List<String>
|
||||
{
|
||||
getFieldListString() + ', BindingObject__r.QualifiedApiName',
|
||||
getSObjectType().getDescribe().getName()
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
+5
@@ -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>
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* File Name: fflib_DynamicAppFactory
|
||||
* Description: Abstract class with common functionality for Dynamic Bindings
|
||||
*
|
||||
* @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 abstract class fflib_DynamicAppFactory
|
||||
{
|
||||
protected fflib_SharingMode sharingMode;
|
||||
protected fflib_IAppBindingResolver resolver;
|
||||
protected Map<System.Type, System.Type> routes;
|
||||
|
||||
protected Map<Object, Object> mockImplByObjectType = new Map<Object, Object>();
|
||||
|
||||
protected void setMock(Object objectType, Object mock)
|
||||
{
|
||||
this.mockImplByObjectType.put(
|
||||
objectType,
|
||||
mock
|
||||
);
|
||||
}
|
||||
|
||||
protected Object getMock(Object objectType)
|
||||
{
|
||||
return this.mockImplByObjectType.get(objectType);
|
||||
}
|
||||
|
||||
protected Boolean hasMock(Object objectType)
|
||||
{
|
||||
return this.mockImplByObjectType.containsKey(objectType);
|
||||
}
|
||||
}
|
||||
+5
@@ -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>
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* File Name: fflib_DynamicDomainFactory
|
||||
* 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_DynamicDomainFactory
|
||||
extends fflib_DynamicAppFactory
|
||||
implements fflib_IDomainFactory
|
||||
{
|
||||
public static final fflib_AppBindingType DOMAIN = fflib_AppBindingType.Domain;
|
||||
|
||||
protected Map<Object, fflib_IDomain> mockDomainByObjectType = new Map<Object, fflib_IDomain>();
|
||||
protected fflib_ISelectorFactory selectorFactory;
|
||||
|
||||
|
||||
public fflib_DynamicDomainFactory(fflib_IAppBindingResolver resolver, fflib_ISelectorFactory selectorFactory)
|
||||
{
|
||||
this.resolver = resolver;
|
||||
this.selectorFactory = selectorFactory;
|
||||
}
|
||||
|
||||
public fflib_IDomain newInstance(Set<Id> recordIds)
|
||||
{
|
||||
return newInstance(this.selectorFactory.selectById(recordIds));
|
||||
}
|
||||
|
||||
public fflib_IDomain newInstance(Set<Id> recordIds, SObjectType sObjectType)
|
||||
{
|
||||
return newInstance(this.selectorFactory.selectById(recordIds, sObjectType));
|
||||
}
|
||||
|
||||
public fflib_IDomain newInstance(List<SObject> records)
|
||||
{
|
||||
SObjectType sObjectType = records.getSObjectType();
|
||||
|
||||
if (sObjectType == null)
|
||||
throw new DeveloperException('Could not determine the SObjectType of the provided records');
|
||||
|
||||
return newInstance(
|
||||
(List<Object>) records,
|
||||
(Object) sObjectType
|
||||
);
|
||||
}
|
||||
|
||||
public fflib_IDomain newInstance(List<Object> objects, Object objectType)
|
||||
{
|
||||
if (hasMock(objectType)) return (fflib_IDomain) getMock(objectType);
|
||||
|
||||
List<fflib_IAppBinding> bindings = resolver.byObject(objectType)
|
||||
.byType(DOMAIN)
|
||||
.resolve();
|
||||
|
||||
if (bindings.isEmpty())
|
||||
throw new DeveloperException('Unable to find domain binding ' + objectType);
|
||||
|
||||
System.Type domainImplementationType = bindings.get(0).getImplementationType();
|
||||
|
||||
Object instance = domainImplementationType.newInstance();
|
||||
|
||||
if (!(instance instanceof fflib_IDomainConstructor))
|
||||
throw new DeveloperException(
|
||||
String.format(
|
||||
'Domain implementation {0} should be an instance of fflib_IDomainConstructor',
|
||||
new List<String> { domainImplementationType.getName() }
|
||||
)
|
||||
);
|
||||
|
||||
return ((fflib_IDomainConstructor) domainImplementationType.newInstance())
|
||||
.construct(objects);
|
||||
}
|
||||
|
||||
public fflib_IDomain newInstance(List<SObject> records, SObjectType domainSObjectType)
|
||||
{
|
||||
return newInstance((List<Object>) records, (Object) domainSObjectType);
|
||||
}
|
||||
|
||||
public void setMock(fflib_ISObjectDomain mockDomain)
|
||||
{
|
||||
super.setMock(mockDomain.getType(), mockDomain);
|
||||
}
|
||||
|
||||
public void setMock(Schema.SObjectType sObjectType, fflib_ISObjectDomain mockDomain)
|
||||
{
|
||||
super.setMock(sObjectType, mockDomain);
|
||||
}
|
||||
|
||||
public void setMock(fflib_IDomain mockDomain)
|
||||
{
|
||||
super.setMock(mockDomain.getType(), mockDomain);
|
||||
}
|
||||
|
||||
public void setMock(Object domainType, fflib_IDomain mockDomain)
|
||||
{
|
||||
super.setMock(domainType, mockDomain);
|
||||
}
|
||||
|
||||
public class DeveloperException extends Exception {}
|
||||
}
|
||||
+5
@@ -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>
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* File Name: fflib_DynamicSelectorFactory
|
||||
* 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_DynamicSelectorFactory
|
||||
extends fflib_DynamicAppFactory
|
||||
implements fflib_ISelectorFactory
|
||||
{
|
||||
public static final fflib_AppBindingType SELECTOR_BINDING_TYPE = fflib_AppBindingType.Selector;
|
||||
|
||||
protected Map<Object, Object> mockSelectorImplByObjectType = new Map<Object, Object>();
|
||||
|
||||
public fflib_DynamicSelectorFactory(fflib_IAppBindingResolver resolver)
|
||||
{
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
public fflib_ISObjectSelector newInstance(SObjectType sObjectType)
|
||||
{
|
||||
if (hasMock(sObjectType)) return (fflib_ISObjectSelector) getMock(sObjectType);
|
||||
|
||||
List<fflib_IAppBinding> bindings = resolver
|
||||
.byType(SELECTOR_BINDING_TYPE)
|
||||
.byObject(sObjectType)
|
||||
.bySharingMode(sharingMode)
|
||||
.resolve();
|
||||
|
||||
if (bindings.isEmpty())
|
||||
throw new DeveloperException(
|
||||
String.format(
|
||||
'Unable to find selector binding {0} with sharing more {0}',
|
||||
new List<String>
|
||||
{
|
||||
sObjectType.getDescribe().getName(),
|
||||
sharingMode.name()
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
return (fflib_ISObjectSelector) bindings.get(0).newImplInstance();
|
||||
}
|
||||
|
||||
public List<SObject> selectById(Set<Id> recordIds)
|
||||
{
|
||||
if (null == recordIds || recordIds.size() == 0)
|
||||
throw new fflib_Application.DeveloperException('Invalid record Id\'s set');
|
||||
|
||||
return selectById(recordIds, new List<Id>(recordIds)[0].getSObjectType());
|
||||
}
|
||||
|
||||
public List<SObject> selectById(Set<Id> recordIds, SObjectType sObjectType)
|
||||
{
|
||||
if (null == recordIds || recordIds.size() == 0)
|
||||
throw new fflib_Application.DeveloperException('Invalid record Id\'s set');
|
||||
|
||||
return newInstance(sObjectType)
|
||||
.selectSObjectsById(recordIds);
|
||||
}
|
||||
|
||||
public List<SObject> selectByRelationship(List<SObject> relatedRecords, SObjectField relationshipField)
|
||||
{
|
||||
Set<Id> relatedIds =
|
||||
new RelatedRecordsDomain(relatedRecords)
|
||||
.getRelatedIds(relationshipField);
|
||||
|
||||
if (relatedIds.isEmpty()) return new List<SObject>();
|
||||
|
||||
return selectById(relatedIds);
|
||||
}
|
||||
|
||||
public void replaceWith(SObjectType sObjectType, Type replacementImplType)
|
||||
{
|
||||
resolver.byType(fflib_AppBindingType.Selector)
|
||||
.byObject(sObjectType)
|
||||
.bySharingMode(this.sharingMode)
|
||||
.resolve()
|
||||
.get(0)
|
||||
.setImplementationType(replacementImplType);
|
||||
}
|
||||
|
||||
public void setMock(fflib_ISObjectSelector selectorInstance)
|
||||
{
|
||||
setMock(selectorInstance.sObjectType(), selectorInstance);
|
||||
}
|
||||
|
||||
public void setMock(SObjectType sObjectType, fflib_ISObjectSelector selectorInstance)
|
||||
{
|
||||
super.setMock(sObjectType, selectorInstance);
|
||||
}
|
||||
|
||||
public fflib_DynamicSelectorFactory setSharingMode(fflib_SharingMode sharingMode)
|
||||
{
|
||||
this.sharingMode = sharingMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
private class RelatedRecordsDomain extends SObjects
|
||||
{
|
||||
public RelatedRecordsDomain(List<SObject> records)
|
||||
{
|
||||
super(records);
|
||||
}
|
||||
|
||||
public Set<Id> getRelatedIds(Schema.SObjectField relationshipField)
|
||||
{
|
||||
return getIdFieldValues(relationshipField).getIds();
|
||||
}
|
||||
}
|
||||
|
||||
public class DeveloperException extends Exception {}
|
||||
}
|
||||
+5
@@ -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>
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* File Name: fflib_DynamicServiceFactory
|
||||
* Description: Service Factory to return service class instances in a dynamic way
|
||||
*
|
||||
* @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_DynamicServiceFactory
|
||||
extends fflib_DynamicAppFactory
|
||||
implements fflib_IServiceFactory
|
||||
{
|
||||
public static final fflib_AppBindingType SERVICE_BINDING_TYPE = fflib_AppBindingType.Service;
|
||||
|
||||
protected Map<System.Type, Object> mockServiceImplByObjectType = new Map<System.Type, Object>();
|
||||
|
||||
public fflib_DynamicServiceFactory(fflib_IAppBindingResolver resolver)
|
||||
{
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
public Object newInstance(Type serviceInterfaceType)
|
||||
{
|
||||
if (hasMock(serviceInterfaceType)) return getMock(serviceInterfaceType);
|
||||
|
||||
List<fflib_IAppBinding> bindings = resolver
|
||||
.byType(SERVICE_BINDING_TYPE)
|
||||
.byInterfaceType(serviceInterfaceType)
|
||||
.bySharingMode(sharingMode)
|
||||
.resolve();
|
||||
|
||||
if (bindings.isEmpty())
|
||||
throw new DeveloperException(
|
||||
String.format(
|
||||
'Unable to find service binding {0} with sharing more {0}',
|
||||
new List<String>
|
||||
{
|
||||
serviceInterfaceType.getName(),
|
||||
sharingMode.name()
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
return bindings.get(0).newImplInstance();
|
||||
}
|
||||
|
||||
public void replaceWith(Type serviceInterfaceType, Type replacementImplType)
|
||||
{
|
||||
resolver.byType(SERVICE_BINDING_TYPE)
|
||||
.byInterfaceType(serviceInterfaceType)
|
||||
.bySharingMode(sharingMode)
|
||||
.resolve()
|
||||
.get(0) // TODO - validate that there are any resolved bindings
|
||||
.setImplementationType(replacementImplType);
|
||||
}
|
||||
|
||||
public void setMock(Type serviceInterfaceType, Object serviceImpl)
|
||||
{
|
||||
super.setMock(serviceInterfaceType, serviceImpl);
|
||||
}
|
||||
|
||||
public fflib_DynamicServiceFactory setSharingMode(fflib_SharingMode sharingMode)
|
||||
{
|
||||
this.sharingMode = sharingMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public class DeveloperException extends Exception {}
|
||||
}
|
||||
+5
@@ -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,34 @@
|
||||
/**
|
||||
* File Name: fflib_SharingMode
|
||||
* Description: Enum with the Application Binding Sharing Modes
|
||||
|
||||
* @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 enum fflib_SharingMode
|
||||
{
|
||||
WithSharing, WithoutSharing, InheritedSharing, None
|
||||
}
|
||||
+5
@@ -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>
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* File Name: fflib_IAppBinding
|
||||
* Description: Interface for Application Binding Data Object
|
||||
*
|
||||
* @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_IAppBinding
|
||||
{
|
||||
Object getBindingObject();
|
||||
fflib_AppBindingType getBindingType();
|
||||
System.Type getImplementationType();
|
||||
System.Type getInterfaceType();
|
||||
String getNamespacePrefix();
|
||||
Decimal getSequence();
|
||||
fflib_SharingMode getSharingMode();
|
||||
|
||||
Object newImplInstance();
|
||||
|
||||
fflib_IAppBinding setBindingObject(Object bindingObject);
|
||||
fflib_IAppBinding setBindingType(fflib_AppBindingType bindingType);
|
||||
fflib_IAppBinding setNamespacePrefix(String namespacePrefix);
|
||||
fflib_IAppBinding setImplementationType(System.Type implementationType);
|
||||
fflib_IAppBinding setInterfaceType(System.Type interfaceType);
|
||||
fflib_IAppBinding setSequence(Decimal sequence);
|
||||
fflib_IAppBinding setSharingMode(fflib_SharingMode sharingMode);
|
||||
}
|
||||
+5
@@ -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>
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* File Name: fflib_IAppBindingModule
|
||||
* Description: Interface for the Application Module
|
||||
*
|
||||
* @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_IAppBindingModule
|
||||
{
|
||||
void init();
|
||||
void addBinding(fflib_IAppBinding binding);
|
||||
void addBindings(List<fflib_IAppBinding> bindings);
|
||||
List<fflib_IAppBinding> getBindings();
|
||||
}
|
||||
+5
@@ -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>
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* File Name: fflib_IAppBindingResolver
|
||||
* 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 interface fflib_IAppBindingResolver
|
||||
{
|
||||
fflib_IAppBindingResolver addModule(fflib_IAppBindingModule bindingModule);
|
||||
fflib_IAppBindingResolver byObject(Object bindingObject);
|
||||
fflib_IAppBindingResolver bySequence(Integer sequence);
|
||||
fflib_IAppBindingResolver byType(fflib_AppBindingType bindingType);
|
||||
fflib_IAppBindingResolver byInterfaceType(System.Type interfaceType);
|
||||
fflib_IAppBindingResolver bySharingMode(fflib_SharingMode sharingMode);
|
||||
fflib_IAppBindingResolver byNamespacePrefix(String namespacePrefix);
|
||||
List<fflib_IAppBinding> resolve();
|
||||
}
|
||||
+5
@@ -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>
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* File Name: fflib_IAppBindingRouter
|
||||
* 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 interface fflib_IAppBindingRouter
|
||||
{
|
||||
Map<System.Type, System.Type> getRoutes();
|
||||
}
|
||||
+5
@@ -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>
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* File Name: fflib_IAppBindings
|
||||
* Description: Domain class interface signatures for fflib_AppBindings
|
||||
*
|
||||
* @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_IAppBindings
|
||||
extends fflib_IDomain
|
||||
{
|
||||
void addBinding(fflib_IAppBinding binding);
|
||||
void addBindings(List<fflib_IAppBinding> bindings);
|
||||
|
||||
fflib_IAppBindings selectByObject(Object bindingObject);
|
||||
fflib_IAppBindings selectBySequence(Decimal sequence);
|
||||
fflib_IAppBindings selectByType(fflib_AppBindingType bindingType);
|
||||
fflib_IAppBindings selectByInterfaceType(System.Type interfaceType);
|
||||
fflib_IAppBindings selectBySharingMode(fflib_SharingMode sharingMode);
|
||||
fflib_IAppBindings selectByNamespacePrefix(String namespacePrefix);
|
||||
|
||||
List<fflib_IAppBinding> getBindings();
|
||||
List<System.Type> getImplementations();
|
||||
}
|
||||
+5
@@ -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>
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Layout xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<layoutSections>
|
||||
<customLabel>false</customLabel>
|
||||
<detailHeading>false</detailHeading>
|
||||
<editHeading>true</editHeading>
|
||||
<label>Information</label>
|
||||
<layoutColumns>
|
||||
<layoutItems>
|
||||
<behavior>Required</behavior>
|
||||
<field>MasterLabel</field>
|
||||
</layoutItems>
|
||||
<layoutItems>
|
||||
<behavior>Required</behavior>
|
||||
<field>DeveloperName</field>
|
||||
</layoutItems>
|
||||
<layoutItems>
|
||||
<behavior>Required</behavior>
|
||||
<field>Type__c</field>
|
||||
</layoutItems>
|
||||
</layoutColumns>
|
||||
<layoutColumns>
|
||||
<layoutItems>
|
||||
<behavior>Edit</behavior>
|
||||
<field>IsProtected</field>
|
||||
</layoutItems>
|
||||
<layoutItems>
|
||||
<behavior>Required</behavior>
|
||||
<field>NamespacePrefix</field>
|
||||
</layoutItems>
|
||||
</layoutColumns>
|
||||
<style>TwoColumnsTopToBottom</style>
|
||||
</layoutSections>
|
||||
<layoutSections>
|
||||
<customLabel>true</customLabel>
|
||||
<detailHeading>true</detailHeading>
|
||||
<editHeading>true</editHeading>
|
||||
<label>Binding</label>
|
||||
<layoutColumns>
|
||||
<layoutItems>
|
||||
<behavior>Edit</behavior>
|
||||
<field>BindingObject__c</field>
|
||||
</layoutItems>
|
||||
<layoutItems>
|
||||
<behavior>Edit</behavior>
|
||||
<field>BindingObjectAlternate__c</field>
|
||||
</layoutItems>
|
||||
<layoutItems>
|
||||
<behavior>Edit</behavior>
|
||||
<field>BindingSequence__c</field>
|
||||
</layoutItems>
|
||||
</layoutColumns>
|
||||
<layoutColumns>
|
||||
<layoutItems>
|
||||
<behavior>Edit</behavior>
|
||||
<field>InterfaceType__c</field>
|
||||
</layoutItems>
|
||||
<layoutItems>
|
||||
<behavior>Required</behavior>
|
||||
<field>ImplementationType__c</field>
|
||||
</layoutItems>
|
||||
<layoutItems>
|
||||
<behavior>Required</behavior>
|
||||
<field>SharingMode__c</field>
|
||||
</layoutItems>
|
||||
</layoutColumns>
|
||||
<style>TwoColumnsLeftToRight</style>
|
||||
</layoutSections>
|
||||
<layoutSections>
|
||||
<customLabel>false</customLabel>
|
||||
<detailHeading>false</detailHeading>
|
||||
<editHeading>true</editHeading>
|
||||
<label>System Information</label>
|
||||
<layoutColumns>
|
||||
<layoutItems>
|
||||
<behavior>Readonly</behavior>
|
||||
<field>CreatedById</field>
|
||||
</layoutItems>
|
||||
</layoutColumns>
|
||||
<layoutColumns>
|
||||
<layoutItems>
|
||||
<behavior>Readonly</behavior>
|
||||
<field>LastModifiedById</field>
|
||||
</layoutItems>
|
||||
</layoutColumns>
|
||||
<style>TwoColumnsTopToBottom</style>
|
||||
</layoutSections>
|
||||
<layoutSections>
|
||||
<customLabel>true</customLabel>
|
||||
<detailHeading>true</detailHeading>
|
||||
<editHeading>false</editHeading>
|
||||
<label>Custom Links</label>
|
||||
<layoutColumns/>
|
||||
<layoutColumns/>
|
||||
<layoutColumns/>
|
||||
<style>CustomLinks</style>
|
||||
</layoutSections>
|
||||
<showEmailCheckbox>false</showEmailCheckbox>
|
||||
<showHighlightsPanel>false</showHighlightsPanel>
|
||||
<showInteractionLogPanel>false</showInteractionLogPanel>
|
||||
<showRunAssignmentRulesCheckbox>false</showRunAssignmentRulesCheckbox>
|
||||
<showSubmitAndAttachButton>false</showSubmitAndAttachButton>
|
||||
<summaryLayout>
|
||||
<masterLabel>00h55000002F8hB</masterLabel>
|
||||
<sizeX>4</sizeX>
|
||||
<sizeY>0</sizeY>
|
||||
<summaryLayoutStyle>Default</summaryLayoutStyle>
|
||||
</summaryLayout>
|
||||
</Layout>
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<label>Application Binding</label>
|
||||
<pluralLabel>Application Bindings</pluralLabel>
|
||||
<visibility>Public</visibility>
|
||||
</CustomObject>
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<fullName>BindingObjectAlternate__c</fullName>
|
||||
<description>Use this field to specify the SObject API name to bind to when the "Binding Object" field does not list that particular SObject. Only specify the "Binding Object" field or this one; not both.</description>
|
||||
<externalId>false</externalId>
|
||||
<fieldManageability>SubscriberControlled</fieldManageability>
|
||||
<inlineHelpText>Use this field to specify the SObject API name to bind to when the "Binding Object" field does not list that particular SObject. Only specify the "Binding Object" field or this one; not both.</inlineHelpText>
|
||||
<label>Binding Object Alternate</label>
|
||||
<length>255</length>
|
||||
<required>false</required>
|
||||
<type>Text</type>
|
||||
<unique>false</unique>
|
||||
</CustomField>
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<fullName>BindingObject__c</fullName>
|
||||
<externalId>false</externalId>
|
||||
<fieldManageability>SubscriberControlled</fieldManageability>
|
||||
<label>Binding Object</label>
|
||||
<referenceTo>EntityDefinition</referenceTo>
|
||||
<relationshipLabel>Bindings</relationshipLabel>
|
||||
<relationshipName>Bindings</relationshipName>
|
||||
<required>false</required>
|
||||
<type>MetadataRelationship</type>
|
||||
<unique>false</unique>
|
||||
</CustomField>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<fullName>BindingSequence__c</fullName>
|
||||
<externalId>false</externalId>
|
||||
<fieldManageability>SubscriberControlled</fieldManageability>
|
||||
<label>Binding Sequence</label>
|
||||
<precision>18</precision>
|
||||
<required>false</required>
|
||||
<scale>0</scale>
|
||||
<type>Number</type>
|
||||
<unique>false</unique>
|
||||
</CustomField>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<fullName>ImplementationType__c</fullName>
|
||||
<externalId>false</externalId>
|
||||
<fieldManageability>SubscriberControlled</fieldManageability>
|
||||
<label>Implementation Type</label>
|
||||
<length>255</length>
|
||||
<required>true</required>
|
||||
<type>Text</type>
|
||||
<unique>false</unique>
|
||||
</CustomField>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<fullName>InterfaceType__c</fullName>
|
||||
<externalId>false</externalId>
|
||||
<fieldManageability>SubscriberControlled</fieldManageability>
|
||||
<label>Interface Type</label>
|
||||
<length>255</length>
|
||||
<required>false</required>
|
||||
<type>Text</type>
|
||||
<unique>false</unique>
|
||||
</CustomField>
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<fullName>SharingMode__c</fullName>
|
||||
<defaultValue>"With Sharing"</defaultValue>
|
||||
<externalId>false</externalId>
|
||||
<fieldManageability>DeveloperControlled</fieldManageability>
|
||||
<label>Sharing mode</label>
|
||||
<required>true</required>
|
||||
<type>Picklist</type>
|
||||
<valueSet>
|
||||
<restricted>true</restricted>
|
||||
<valueSetDefinition>
|
||||
<sorted>false</sorted>
|
||||
<value>
|
||||
<fullName>With Sharing</fullName>
|
||||
<default>true</default>
|
||||
<label>With Sharing</label>
|
||||
</value>
|
||||
<value>
|
||||
<fullName>Without Sharing</fullName>
|
||||
<default>false</default>
|
||||
<label>Without Sharing</label>
|
||||
</value>
|
||||
<value>
|
||||
<fullName>Inherited Sharing</fullName>
|
||||
<default>false</default>
|
||||
<label>Inherited Sharing</label>
|
||||
</value>
|
||||
<value>
|
||||
<fullName>None</fullName>
|
||||
<default>false</default>
|
||||
<label>None</label>
|
||||
</value>
|
||||
</valueSetDefinition>
|
||||
</valueSet>
|
||||
</CustomField>
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<fullName>Type__c</fullName>
|
||||
<externalId>false</externalId>
|
||||
<fieldManageability>DeveloperControlled</fieldManageability>
|
||||
<inlineHelpText>Type of binding or Logical layers of functionality</inlineHelpText>
|
||||
<label>Binding Type</label>
|
||||
<required>true</required>
|
||||
<type>Picklist</type>
|
||||
<valueSet>
|
||||
<restricted>true</restricted>
|
||||
<valueSetDefinition>
|
||||
<sorted>false</sorted>
|
||||
<value>
|
||||
<fullName>Domain</fullName>
|
||||
<default>true</default>
|
||||
<label>Domain</label>
|
||||
</value>
|
||||
<value>
|
||||
<fullName>Service</fullName>
|
||||
<default>false</default>
|
||||
<label>Service</label>
|
||||
</value>
|
||||
<value>
|
||||
<fullName>Selector</fullName>
|
||||
<default>false</default>
|
||||
<label>Selector</label>
|
||||
</value>
|
||||
<value>
|
||||
<fullName>Controller</fullName>
|
||||
<default>false</default>
|
||||
<label>Controller</label>
|
||||
</value>
|
||||
<value>
|
||||
<fullName>Module</fullName>
|
||||
<default>false</default>
|
||||
<label>Module</label>
|
||||
</value>
|
||||
<value>
|
||||
<fullName>EventListener</fullName>
|
||||
<default>false</default>
|
||||
<label>Event Listener</label>
|
||||
</value>
|
||||
<value>
|
||||
<fullName>Miscellaneous</fullName>
|
||||
<default>false</default>
|
||||
<label>Miscellaneous</label>
|
||||
</value>
|
||||
</valueSetDefinition>
|
||||
</valueSet>
|
||||
</CustomField>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ListView xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<fullName>All</fullName>
|
||||
<columns>MasterLabel</columns>
|
||||
<columns>BindingObject__c</columns>
|
||||
<columns>BindingObjectAlternate__c</columns>
|
||||
<columns>BindingSequence__c</columns>
|
||||
<columns>InterfaceType__c</columns>
|
||||
<columns>ImplementationType__c</columns>
|
||||
<filterScope>Everything</filterScope>
|
||||
<label>All</label>
|
||||
</ListView>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ValidationRule xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<fullName>BindObj_Or_BindObjAlt</fullName>
|
||||
<active>true</active>
|
||||
<description>This validation rule ensures that only the "Binding Object" or the "Binding Object Alternate" field is specified and not both.</description>
|
||||
<errorConditionFormula>NOT( ISBLANK( BindingObject__c ) ) && NOT( ISBLANK( BindingObjectAlternate__c ) )</errorConditionFormula>
|
||||
<errorMessage>Only specify the "Binding Object" field or the "Binding Object Alternate" field; not both.</errorMessage>
|
||||
</ValidationRule>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ValidationRule xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<fullName>Require_Interface_Type_For_Services</fullName>
|
||||
<active>true</active>
|
||||
<description>An Interface Type is required for Service class Bindings</description>
|
||||
<errorConditionFormula>AND(ISPICKVAL(Type__c,"Service"), ISBLANK( InterfaceType__c ) )</errorConditionFormula>
|
||||
<errorDisplayField>ImplementationType__c</errorDisplayField>
|
||||
<errorMessage>An Interface Type is required for Service class Bindings</errorMessage>
|
||||
</ValidationRule>
|
||||
+2
-2
@@ -42,7 +42,7 @@ public interface fflib_IDomainFactory
|
||||
**/
|
||||
fflib_IDomain newInstance(Set<Id> recordIds);
|
||||
|
||||
fflib_IDomain newInstance(Set<Id> recordIds, Schema.SObjectType objectType);
|
||||
fflib_IDomain newInstance(Set<Id> recordIds, Schema.SObjectType sObjectType);
|
||||
|
||||
/**
|
||||
* Dynamically constructs an instance of the Domain class for the given records
|
||||
@@ -95,5 +95,5 @@ public interface fflib_IDomainFactory
|
||||
* 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);
|
||||
void setMock(Object domainType, fflib_IDomain mockDomain);
|
||||
}
|
||||
+5
@@ -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>
|
||||
+5
@@ -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>
|
||||
+5
@@ -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>
|
||||
+5
@@ -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>
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* File Name: fflib_DynamicDomainFactoryTest
|
||||
* 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.
|
||||
*/
|
||||
@IsTest(IsParallel=true)
|
||||
public class fflib_DynamicDomainFactoryTest
|
||||
{
|
||||
private static final fflib_IAppBindingResolver bindingResolver =
|
||||
new fflib_AppBindingResolver();
|
||||
|
||||
|
||||
private static final fflib_IDomainFactory Domain =
|
||||
new fflib_DynamicDomainFactory(
|
||||
bindingResolver,
|
||||
fflib_DynamicSelectorFactoryTest.Selector);
|
||||
private static final SObjectType ACCOUNT_OBJECT_TYPE = Schema.Account.SObjectType;
|
||||
|
||||
@IsTest
|
||||
static void itShouldReturnDomain()
|
||||
{
|
||||
// Mock the App Bindings selector
|
||||
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = AppBindingsSelectorMock.class;
|
||||
final List<Account> records = generateAccountRecords();
|
||||
|
||||
System.Test.startTest();
|
||||
Object instance = Domain.newInstance(records);
|
||||
System.Test.stopTest();
|
||||
|
||||
System.assert(instance instanceof fflib_SObjects);
|
||||
}
|
||||
|
||||
@IsTest
|
||||
static void itShouldReturnDomainById()
|
||||
{
|
||||
// Mock the App Bindings selector
|
||||
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = AppBindingsSelectorMock.class;
|
||||
|
||||
final List<Account> records = generateAccountRecords();
|
||||
final Set<Id> ids = new fflib_SObjects(records).getRecordIds();
|
||||
|
||||
fflib_ApexMocks mocks = new fflib_ApexMocks();
|
||||
fflib_ISObjectSelector selectorMock = (fflib_ISObjectSelector) mocks.mock(fflib_ISObjectSelector.class);
|
||||
mocks.startStubbing();
|
||||
mocks.when(selectorMock.selectSObjectsById(ids)).thenReturn(records);
|
||||
mocks.stopStubbing();
|
||||
|
||||
fflib_DynamicSelectorFactoryTest.Selector.setMock(ACCOUNT_OBJECT_TYPE, selectorMock);
|
||||
|
||||
System.Test.startTest();
|
||||
Object instance = Domain.newInstance(ids);
|
||||
System.Test.stopTest();
|
||||
|
||||
System.assert(instance instanceof fflib_SObjects);
|
||||
System.assertEquals(records, ((fflib_SObjects) instance).getRecords());
|
||||
}
|
||||
|
||||
@IsTest
|
||||
static void itShouldReturnTheMockDomain()
|
||||
{
|
||||
// Mock the App Bindings selector
|
||||
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = AppBindingsSelectorMock.class;
|
||||
|
||||
final List<Account> records = generateAccountRecords();
|
||||
final Set<Id> ids = new fflib_SObjects(records).getRecordIds();
|
||||
|
||||
fflib_ApexMocks mocks = new fflib_ApexMocks();
|
||||
fflib_SObjects domainMock = (fflib_SObjects) mocks.mock(fflib_SObjects.class);
|
||||
|
||||
mocks.startStubbing();
|
||||
mocks.when(domainMock.getType()).thenReturn(ACCOUNT_OBJECT_TYPE);
|
||||
mocks.when(domainMock.getRecords()).thenReturn(new List<Account>());
|
||||
mocks.stopStubbing();
|
||||
|
||||
System.Test.startTest();
|
||||
fflib_SObjects instanceA = (fflib_SObjects) Domain.newInstance(records);
|
||||
Domain.setMock(domainMock);
|
||||
fflib_SObjects instanceB = (fflib_SObjects) Domain.newInstance(records, ACCOUNT_OBJECT_TYPE);
|
||||
System.Test.stopTest();
|
||||
|
||||
System.assertEquals(records, instanceA.getRecords());
|
||||
System.assert(instanceB.getRecords().isEmpty());
|
||||
}
|
||||
|
||||
|
||||
private static List<Account> generateAccountRecords()
|
||||
{
|
||||
List<Account> records = new List<Account>
|
||||
{
|
||||
new Account(Id = fflib_IDGenerator.generate(ACCOUNT_OBJECT_TYPE)),
|
||||
new Account(Id = fflib_IDGenerator.generate(ACCOUNT_OBJECT_TYPE)),
|
||||
new Account(Id = fflib_IDGenerator.generate(ACCOUNT_OBJECT_TYPE))
|
||||
};
|
||||
return records;
|
||||
}
|
||||
|
||||
|
||||
public class MyDomainConstructor implements fflib_IDomainConstructor
|
||||
{
|
||||
public fflib_IDomain construct(List<Object> objects)
|
||||
{
|
||||
return new fflib_SObjects((List<SObject>) objects);
|
||||
}
|
||||
}
|
||||
|
||||
private class AppBindingsSelectorMock extends fflib_AppBindingsSelector
|
||||
{
|
||||
public override List<fflib_AppBinding__mdt> selectAll()
|
||||
{
|
||||
return new List<fflib_AppBinding__mdt>
|
||||
{
|
||||
new fflib_AppBinding__mdt(
|
||||
Type__c = 'Domain',
|
||||
BindingObject__c = '',
|
||||
BindingObjectAlternate__c = ACCOUNT_OBJECT_TYPE.getDescribe().getName(),
|
||||
ImplementationType__c = MyDomainConstructor.class.getName(),
|
||||
SharingMode__c = 'None'
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -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>
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* File Name: fflib_DynamicSelectorFactoryTest
|
||||
* 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.
|
||||
*/
|
||||
@IsTest(IsParallel=true)
|
||||
public class fflib_DynamicSelectorFactoryTest
|
||||
{
|
||||
|
||||
private static fflib_IAppBindingResolver bindingResolver =
|
||||
new fflib_AppBindingResolver();
|
||||
|
||||
@TestVisible
|
||||
private static final fflib_ISelectorFactory Selector =
|
||||
new fflib_DynamicSelectorFactory(bindingResolver)
|
||||
.setSharingMode(fflib_SharingMode.WithSharing);
|
||||
|
||||
private static final Type MY_SELECTOR_TYPE = fflib_DynamicSelectorFactoryTest.MySelector.class;
|
||||
|
||||
@IsTest
|
||||
static void itShouldReturnTheSelectorByBindingObject()
|
||||
{
|
||||
// Mock the App Bindings selector
|
||||
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = AppBindingsSelectorMock.class;
|
||||
|
||||
System.Test.startTest();
|
||||
Object instance = Selector.newInstance(Schema.Account.SObjectType);
|
||||
System.Test.stopTest();
|
||||
|
||||
System.assert(instance instanceof fflib_DynamicSelectorFactoryTest.MySelector);
|
||||
}
|
||||
|
||||
@IsTest
|
||||
static void itShouldReturnTheAlternativeSelector()
|
||||
{
|
||||
// Mock the App Bindings selector
|
||||
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = AppBindingsSelectorMock.class;
|
||||
|
||||
System.Test.startTest();
|
||||
Object instanceA = Selector.newInstance(Schema.Account.SObjectType);
|
||||
Selector.replaceWith(Schema.Account.SObjectType, MyMockSelector.class);
|
||||
Object instanceB = Selector.newInstance(Schema.Account.SObjectType);
|
||||
System.Test.stopTest();
|
||||
|
||||
System.assert(instanceA instanceof fflib_DynamicSelectorFactoryTest.MySelector);
|
||||
System.assert(instanceB instanceof fflib_DynamicSelectorFactoryTest.MyMockSelector);
|
||||
}
|
||||
|
||||
@IsTest
|
||||
static void itShouldReturnTheRecordsById()
|
||||
{
|
||||
Id id = fflib_IDGenerator.generate(Schema.Account.SObjectType);
|
||||
Set<Id> ids = new Set<Id>{ id };
|
||||
final List<Account> records = new List<Account>{ new Account(Name='Test') };
|
||||
|
||||
fflib_ApexMocks mocks = new fflib_ApexMocks();
|
||||
fflib_ISObjectSelector selectorMock = (fflib_ISObjectSelector) mocks.mock(fflib_ISObjectSelector.class);
|
||||
mocks.startStubbing();
|
||||
mocks.when(selectorMock.selectSObjectsById(ids)).thenReturn(records);
|
||||
mocks.stopStubbing();
|
||||
|
||||
Selector.setMock(Schema.Account.SObjectType, selectorMock);
|
||||
|
||||
System.Test.startTest();
|
||||
List<SObject> result = Selector.selectById(ids);
|
||||
System.Test.stopTest();
|
||||
|
||||
System.assert(result == records);
|
||||
((fflib_ISObjectSelector) mocks.verify(selectorMock)).selectSObjectsById(ids);
|
||||
}
|
||||
|
||||
@IsTest
|
||||
static void itShouldReturnTheRecordsByRelatedId()
|
||||
{
|
||||
Id id = fflib_IDGenerator.generate(Schema.Account.SObjectType);
|
||||
Set<Id> ids = new Set<Id>{ id };
|
||||
final List<Account> accounts = new List<Account>{ new Account(Id = id, Name='Test') };
|
||||
final List<Contact> contacts = new List<Contact> { new Contact(AccountId = id)};
|
||||
|
||||
fflib_ApexMocks mocks = new fflib_ApexMocks();
|
||||
fflib_ISObjectSelector selectorMock = (fflib_ISObjectSelector) mocks.mock(fflib_ISObjectSelector.class);
|
||||
mocks.startStubbing();
|
||||
mocks.when(selectorMock.sObjectType()).thenReturn(Schema.Account.SObjectType);
|
||||
mocks.when(selectorMock.selectSObjectsById(ids)).thenReturn(accounts);
|
||||
mocks.stopStubbing();
|
||||
|
||||
Selector.setMock(selectorMock);
|
||||
|
||||
System.Test.startTest();
|
||||
List<SObject> result = Selector.selectByRelationship(contacts, Schema.Contact.AccountId);
|
||||
System.Test.stopTest();
|
||||
|
||||
System.assert(result == accounts);
|
||||
((fflib_ISObjectSelector) mocks.verify(selectorMock)).selectSObjectsById(ids);
|
||||
}
|
||||
|
||||
public interface IMySelector extends fflib_ISObjectSelector {}
|
||||
|
||||
private abstract class MySelectorAbstract extends fflib_SObjectSelector implements IMySelector
|
||||
{
|
||||
public List<Schema.SObjectField> getSObjectFieldList()
|
||||
{
|
||||
return new List<Schema.SObjectField>{ Account.Id, Account.Name };
|
||||
}
|
||||
|
||||
public SObjectType getSObjectType()
|
||||
{
|
||||
return Schema.Account.SObjectType;
|
||||
}
|
||||
}
|
||||
|
||||
public class MySelector extends MySelectorAbstract {}
|
||||
public class MyMockSelector extends MySelectorAbstract {}
|
||||
|
||||
private class AppBindingsSelectorMock extends fflib_AppBindingsSelector
|
||||
{
|
||||
public override List<fflib_AppBinding__mdt> selectAll()
|
||||
{
|
||||
return new List<fflib_AppBinding__mdt>
|
||||
{
|
||||
new fflib_AppBinding__mdt(
|
||||
Type__c = 'Selector',
|
||||
BindingObject__c = '',
|
||||
BindingObjectAlternate__c = Schema.Account.SObjectType.getDescribe().getName(),
|
||||
ImplementationType__c = MY_SELECTOR_TYPE.getName(),
|
||||
SharingMode__c = 'With Sharing'
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -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>
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* File Name: fflib_DynamicServiceFactoryTest
|
||||
* 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.
|
||||
*/
|
||||
@IsTest(IsParallel=true)
|
||||
public class fflib_DynamicServiceFactoryTest
|
||||
{
|
||||
private static final Type MY_SERVICE_INTERFACE_TYPE = fflib_DynamicServiceFactoryTest.IMyService.class;
|
||||
private static final Type MY_SERVICE_TYPE = fflib_DynamicServiceFactoryTest.MyService.class;
|
||||
private static final Type MY_ALT_SERVICE_TYPE = fflib_DynamicServiceFactoryTest.MyALtService.class;
|
||||
|
||||
@IsTest
|
||||
static void itShouldReturnTheCorrectInstance()
|
||||
{
|
||||
fflib_AppBindingModule module = new fflib_AppBindingModule();
|
||||
module.addBinding(createBindingForMyService());
|
||||
bindingResolver.addModule(module);
|
||||
|
||||
System.Test.startTest();
|
||||
Object instance = Service.newInstance(MY_SERVICE_TYPE);
|
||||
System.Test.stopTest();
|
||||
|
||||
System.assert(instance instanceof fflib_DynamicServiceFactoryTest.MyService);
|
||||
}
|
||||
|
||||
@IsTest
|
||||
static void itShouldReturnTheAlternativeInstance()
|
||||
{
|
||||
fflib_AppBindingModule module = new fflib_AppBindingModule();
|
||||
module.addBinding(createBindingForMyService());
|
||||
bindingResolver.addModule(module);
|
||||
Service.replaceWith(MyService.class, MyAltService.class);
|
||||
|
||||
System.Test.startTest();
|
||||
Object instance = Service.newInstance(MY_SERVICE_TYPE);
|
||||
System.Test.stopTest();
|
||||
|
||||
System.assert(instance instanceof fflib_DynamicServiceFactoryTest.MyAltService);
|
||||
}
|
||||
|
||||
@IsTest
|
||||
static void itShouldReturnTheMockInstance()
|
||||
{
|
||||
fflib_AppBindingModule module = new fflib_AppBindingModule();
|
||||
module.addBinding(createBindingForMyService());
|
||||
bindingResolver.addModule(module);
|
||||
IMyService mock = new MyAltService();
|
||||
Service.setMock(MyService.class, mock);
|
||||
|
||||
System.Test.startTest();
|
||||
Object instance = Service.newInstance(MY_SERVICE_TYPE);
|
||||
System.Test.stopTest();
|
||||
|
||||
System.assert(instance instanceof fflib_DynamicServiceFactoryTest.MyAltService);
|
||||
}
|
||||
|
||||
@IsTest
|
||||
static void itShouldReturnTheFirstBindingInstance()
|
||||
{
|
||||
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = AppBindingsSelectorMock.class;
|
||||
|
||||
System.Test.startTest();
|
||||
Object instance = Service.newInstance(MY_SERVICE_INTERFACE_TYPE);
|
||||
System.Test.stopTest();
|
||||
|
||||
System.assert(instance instanceof fflib_DynamicServiceFactoryTest.MyService);
|
||||
}
|
||||
|
||||
@IsTest
|
||||
static void itShouldReturnTheSecondBindingInstance()
|
||||
{
|
||||
fflib_AppBindingsSelector.SELECTOR_IMPL_TYPE = reverseAppBindingsSelectorMock.class;
|
||||
|
||||
System.Test.startTest();
|
||||
Object instance = Service.newInstance(MY_SERVICE_INTERFACE_TYPE);
|
||||
System.Test.stopTest();
|
||||
|
||||
System.assert(instance instanceof fflib_DynamicServiceFactoryTest.MyAltService);
|
||||
}
|
||||
|
||||
|
||||
private static fflib_AppBinding createBindingForMyService()
|
||||
{
|
||||
fflib_AppBinding result = new fflib_AppBinding();
|
||||
|
||||
result.setBindingType(fflib_AppBindingType.Service);
|
||||
result.setInterfaceType(MY_SERVICE_TYPE);
|
||||
result.setImplementationType(MY_SERVICE_TYPE);
|
||||
result.setSharingMode(fflib_SharingMode.WithSharing);
|
||||
result.setSequence(2);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static fflib_AppBinding createBindingForMyAltService()
|
||||
{
|
||||
fflib_AppBinding result = createBindingForMyService();
|
||||
result.setImplementationType(MyAltService.class);
|
||||
result.setSequence(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static fflib_IAppBindingResolver bindingResolver =
|
||||
new fflib_AppBindingResolver();
|
||||
|
||||
private static final fflib_IServiceFactory Service =
|
||||
new fflib_DynamicServiceFactory(bindingResolver)
|
||||
.setSharingMode(fflib_SharingMode.WithSharing);
|
||||
|
||||
public interface IMyService {}
|
||||
|
||||
public class MyService implements IMyService { }
|
||||
|
||||
public class MyAltService implements IMyService { }
|
||||
|
||||
private class AppBindingsSelectorMock extends fflib_AppBindingsSelector
|
||||
{
|
||||
public override List<fflib_AppBinding__mdt> selectAll()
|
||||
{
|
||||
return new List<fflib_AppBinding__mdt>
|
||||
{
|
||||
new fflib_AppBinding__mdt(
|
||||
Type__c = 'Service',
|
||||
InterfaceType__c = MY_SERVICE_INTERFACE_TYPE.getName(),
|
||||
ImplementationType__c = MY_SERVICE_TYPE.getName(),
|
||||
SharingMode__c = 'With Sharing',
|
||||
BindingSequence__c = 1
|
||||
),
|
||||
new fflib_AppBinding__mdt(
|
||||
Type__c = 'Service',
|
||||
InterfaceType__c = MY_SERVICE_INTERFACE_TYPE.getName(),
|
||||
ImplementationType__c = MY_ALT_SERVICE_TYPE.getName(),
|
||||
SharingMode__c = 'With Sharing',
|
||||
BindingSequence__c = 2
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class reverseAppBindingsSelectorMock extends fflib_AppBindingsSelector
|
||||
{
|
||||
public override List<fflib_AppBinding__mdt> selectAll()
|
||||
{
|
||||
return new List<fflib_AppBinding__mdt>
|
||||
{
|
||||
new fflib_AppBinding__mdt(
|
||||
Type__c = 'Service',
|
||||
InterfaceType__c = MY_SERVICE_INTERFACE_TYPE.getName(),
|
||||
ImplementationType__c = MY_SERVICE_TYPE.getName(),
|
||||
SharingMode__c = 'With Sharing',
|
||||
BindingSequence__c = 2
|
||||
),
|
||||
new fflib_AppBinding__mdt(
|
||||
Type__c = 'Service',
|
||||
InterfaceType__c = MY_SERVICE_INTERFACE_TYPE.getName(),
|
||||
ImplementationType__c = MY_ALT_SERVICE_TYPE.getName(),
|
||||
SharingMode__c = 'With Sharing',
|
||||
BindingSequence__c = 1
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -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>
|
||||
Reference in New Issue
Block a user