Code Monkey home page Code Monkey logo

fflib-apex-common's Introduction

FFLib Apex Common

Push Source and Run Apex Tests

Dependencies: Must deploy ApexMocks before deploying this library

Deploy to Salesforce

Updates

  • December 2022, IMPORTANT CHANGE - Support for native Apex User Mode was added to the library (see discussion). For new projects, the old enforceCRUD and enforceFLS flags on fflib_SObjectSelector should be considered deprecated and the constructors that take dataAccess arguments should be used instead. Additionally, the introduction of fflib_SObjectUnitOfWork.UserModeDML provides an IDML implementation that supports USER_MODE or SYSTEM_MODE. fflib_SObjectUnitOfWork.SimpleDML (the default IDML implementation) should be considered deprecated. There are measurable performance benefits to using SYSTEM_MODE and USER_MODE (Apex CPU usage reduction). Additionally, the use of explicit USER_MODE and SYSTEM_MODE overrides the with sharing and without sharing class declaration and makes the expected behavior of DML and SOQL easier to understand.
  • April 2020, IMPORTANT CHANGE, the directory format of this project repo was converted to Salesforce DX Source Format. While the GIT commit history was maintained, it is not visible on GitHub. If you need to see the history, either clone the repo and execute git log --follow from the command line or refer to this tag of the codebase prior to conversion.
  • September 2014, IMPORTANT CHANGE, changes applied to support Dreamforce 2014 advanced presentation, library now provides Application factories for major layers and support for ApexMocks. More details to follow! As a result ApexMocks must be deployed to the org before deploying this library. The sample application here has also been updated to demonstrate the new features!
  • July 2014, IMPORTANT CHANGE, prior 23rd July 2014, both the fflib_SObjectDomain.onValidate() and fflib_SObjectDomain.onValidate(Map<Id, SObject> existingRecords) methods where called during an on after update trigger event. From this point on the onValidate() method will only be called during on after insert. If you still require the orignal behaviour add the line Configuration.enableOldOnUpdateValidateBehaviour(); into your constructor.
  • June 2014, New classes providing utilities to support security and dynamic queries, in addition to improvements to existing Apex Enterprise Pattern base classes. Read more here.

This Library

Is derived from the Dreamforce 2012 presentation on Apex Enterprise Patterns and progresses the patterns further with a more general ongoing home for them. It also adds some form of namespace qualification from the previous version. So that classes are grouped together more easily in the IDE's and packages. Below you can find comprehensive articles and videos on the use of these patterns. There is also a working sample application illustrating the patterns here.

Alt text

Application Enterprise Patterns on Force.com

Design patterns are an invaluable tool for developers and architects looking to build enterprise solutions. Here are presented some tried and tested enterprise application engineering patterns that have been used in other platforms and languages. We will discuss and illustrate how patterns such as Data Mapper, Service Layer, Unit of Work and of course Model View Controller can be applied to Force.com. Applying these patterns can help manage governed resources (such as DML) better, encourage better separation-of-concerns in your logic and enforce Force.com coding best practices.

Documentation

Related Webinars

Related Book

Other Related Blogs

fflib-apex-common's People

Contributors

1903daniel avatar afawcett avatar afawcettffdc avatar agarciaffdc avatar autobat avatar benedwards44 avatar capeterson avatar chivalry avatar christiancoleman avatar claychipps avatar daveerickson avatar daveespo avatar dbtavernerffdc avatar dfrudd avatar dfruddffdc avatar dhuckins avatar foxysolutions avatar imjohnmdaniel avatar jondavis9898 avatar jonnypower avatar liquidjbilling avatar maythesforcebewithyou avatar peterlin888 avatar squattingdog avatar sskular-wonderlab avatar stohn777 avatar tahsinz avatar tmowbrey avatar wimvelzeboer avatar yurybond avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fflib-apex-common's Issues

Concrete subsclass of fflib_SObjectSelector generating "Attempt to de-reference a null object" when instantiated using the "includeFieldSets" constructor.

I've created the following concrete implmentation of fflib_SObjectSelector:

global with sharing class Selector_CustomObject1 extends fflib_SObjectSelector {

    global Selector_CustomObject1() {
        super();
    }

    global Selector_CustomObject1(Boolean includeFieldSetFields) {
        super(includeFieldSetFields);
    }

    global List<Schema.SObjectField> getSObjectFieldList() {
        return new List<Schema.SObjectField> {
            CustomObject1__c.Id,
            CustomObject1__c.Name,
            CustomObject1__c.CreatedDate,
            CustomObject1__c.LastModifiedDate,
            CustomObject1__c.CustomText1__c,
            CustomObject1__c.CustomDateTime1__c,
            CustomObject1__c.CustomEmail1__c,
            CustomObject1__c.CustomPhone1__c
        };
    }

    global Schema.SObjectType getSObjectType() {
        return CustomObject1__c.SObjectType;
    }

    global List<CustomObject1__c> selectById(Set<Id> idSet) {
        return (List<CustomObject1__c>) super.selectSObjectsById(idSet);
    }

    global CustomObject1__c selectById(Id objId) {
        List<CustomObject1__c> co1List = selectById(new Set<Id>{ objId });
        return co1List.get(0);
    }
}

I instantiate this class as follows, and invoke one of the selectById methods, I get the following error:

DEBUG LOG
34.0 APEX_CODE,FINE;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;SYSTEM,DEBUG;VALIDATION,INFO;VISUALFORCE,INFO;WORKFLOW,INFO
Execute Anonymous: Selector_CustomObject1 co1Selector = new Selector_CustomObject1(true);
Execute Anonymous: List<CustomObject1__c> co1List = co1Selector.selectById(new Set<Id>{ 'a001500000g6oJs' });
09:45:14.127 (127018125)|EXECUTION_STARTED
.
.
.
09:45:14.153 (153195558)|SYSTEM_MODE_EXIT|false
09:45:14.153 (153431018)|FATAL_ERROR|System.NullPointerException: Attempt to de-reference a null object

Class.TomPackage.fflib_SObjectSelector.configureQueryFactory: line 369, column 1
Class.TomPackage.fflib_SObjectSelector.newQueryFactory: line 293, column 1
Class.TomPackage.fflib_SObjectSelector.newQueryFactory: line 275, column 1
Class.TomPackage.fflib_SObjectSelector.buildQuerySObjectById: line 341, column 1
Class.TomPackage.fflib_SObjectSelector.selectSObjectsById: line 224, column 1
Class.TomPackage.Selector_CustomObject1.selectById: line 29, column 1
AnonymousBlock: line 2, column 1
AnonymousBlock: line 2, column 1

The strange thing is this does NOT happen in all of my Salesforce orgs. It's happening in a DE org of mine on NA22. I am going to add protection against a null list being returned by the fflib_SObjectSelector.getSObjectFieldSetList() method on line 369.

Enterprise Patterns 'Light'

Firstly - thanks for sharing the patterns!

This post was prompted by a brief exchange with Andrew after this tweet :

Great call with @LaceySnr this morning, talking about Apex Enterprise Patterns โ€œLightโ€ and consulting project usage! @SalesforceDevs

โ€” Andrew Fawcett (@andyinthecloud) March 6, 2015
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

At the time I was trying to decide whether to use the patterns in my upcoming project but was concerned about the complexity. Hence, my interest in a โ€˜Lightโ€™ versionโ€ฆ

Weโ€™ve been on Salesforce for about 18 months and our implementation, although not particularly large, covers quite a lot of the platform with two-way integrations to our website on the frontend and our legacy ERP on the backend, scheduled & batch Apex plus the usual VF controllers and triggers etc. At this stage I'm starting to feel the maintenance pain and therefore very receptive to the โ€˜separation of concernsโ€™ approach.

Iโ€™m the business owner and spend only a small part of my time as a โ€˜developerโ€™, going months (if all is running well) without touching the codeโ€ฆ but weโ€™re about to embark on another phase of implementation involving FinancialForce Accounts & HCM and then re-implementing whatโ€™s left of the ERP in Salesforce.

In short I want maximum separation of concerns to help with maintainability but with minimum complexity!

I've seen this post from Matt Lacey but Iโ€™m not confident enough to go pulling the framework apart and I have a feeling that Iโ€™m going to find some of the more advanced parts, eg mocks, useful once I get into it, so my approach to 'Light' so far is to just pick what seem like the more straightforward and approachable parts and start there. Something like this :

  • Application class that just implements Unit of Work
  • Service classes - Iโ€™d already started collecting related methods into classes so this involves the adoption of a more formal and disciplined approach to this, and Unit of Work is helpful here
  • Selector classes - pretty straightforward to implement and address an issue that Iโ€™ve already experienced trouble with (consistency of fields returned via SOQL)
  • Domain class - this one seems less obvious but plan to try it out next time I need to code a trigger
  • Avoid most of the interfaces/factories/mocks ie the 'advanced' stuff, at least for the time being

I plan to try this with new code or when any of the existing code has to be reworked.

Iโ€™d be interested to hear how others have approached getting started and working with the patterns.

EnforcingTriggerCRUDSecurity=true is not backwards compatible for triggers

The default instantiation of Configuration in the Domain class is as follows:

public Configuration()
{
    EnforcingTriggerCRUDSecurity = true; // Default is true for backwards compatability
    ...
}

Contrary to the what the comment say, the default behaviour of Salesforce triggers is to run in system context without enforcing CRUD security. For example, the following trigger will create an invoice record even if the running user does not have the permission to do so:

trigger AccountsTrigger on Account (after insert) {
    insert new Invoice__c(Description__c = 'trigger created');
}

In effect, the after-event handler methods of the Domain class (handleAfterInsert(), handleAfterUpdate(), etc.) imposes a different behaviour than SFDC's default.

if(Configuration.EnforcingTriggerCRUDSecurity && !SObjectDescribe.isUpdateable())                       
    throw new DomainException('Permission to udpate an ' + SObjectDescribe.getName() + ' denied.');

UOW and cyclic dependencies

The UOW pattern currently doesn't support cyclic dependencies as stated in:
http://andyinthecloud.com/2013/06/09/managing-your-dml-and-transactions-with-a-unit-of-work/

Note: If you have some cyclic dependencies in your schema, you will have to either use two separate unit of work instances or simply handle this directly using DML.

If this could be handled generically in the UOW logic it could be very useful in certain situations. I also agree with Tom Gagne that it may be best to re-factor your data model to avoid this situation altogether, but if it's needed having UOW handle it would be ideal.

creating dependency on fflib-apex-common

A colleague pointed me to this github. My question may look silly.

I would like to use this library in my development of the code. However, I find that it is shared as source-library and not as 'binary' of salesforce. The deployment to SF org creates unmanaged classes.

Could I know what is the recommended way of using the fflib-apex-common and fflib-apex-mocks in our development? I would like to refrain from including it as source-code library as much as possible.
This is because we need to create various packages, which can have dependencies between them. if these packages are using fflib_*, we would have code-duplicates.

also qualifying our packages to specific version of fflib-* is not possible with source-library.

Do you think converting the fflib-* as package will work?

Regards,
Amit

Querying from domain class

Hi,

I am suggest how to write query for below scenario.

In Controller:
bookstoreCont.bookapply(new list<Bookstore__c> { bookstoreIns });

In Domain
public static void bookapply(list<Bookstore__c> bookstoreInsPraram)
{
list<Bookstore__c> bookStroeList=new list<Bookstore__c>();
//This is the place where i am facing problem.
bookStroeList=[select id,Name from Bookstore__c where Email__c=:bookstoreInsPraram.Email__c];
}

Because I can't query directly by using the list variable . so i need to convert to single instance and then I need to use in the where condition to query the record. Is there any other way to achieve this without creating one more variable.

Thanks,

Improve ability to customize functionality

Coming from a non-SFDC background, the fflib framework and enterprise patterns that it promotes are a breath of fresh air. However, the ability to customize the implementation is difficult because a large number of classes/methods/etc. are not marked virtual. The solution for this is:

  1. Modify the fflib classes directly - Downside is this impacts upgrade pathing
  2. Create custom classes that encapsulate the fflib classes and use the custom classes as this - Downside is that fflib classes are still directly available for use and requires "more" code

Would like to see the library use more liberal use of virtual, protected, etc.

Where to place logic, Domain vs Service?

Started this post to gather feedback on some content i'm writing to help with the common question of 'Where to place my logic, Domain or Service'

Business Logic in the Domain class vs Service class?
Sometimes it can feel less than obvious where to place code. Lets go back to the Separation of Concerns principle and think about what the Service and Domain layers are concerned with.

screen shot 2016-02-26 at 18 56 18

fflib_QueryFactory subqueries produce incorrect soql

I tried to create a query that also fetches related child records but I was unable as the syntax of building such subqueries doesn't produce correct SOQL. Even test methods from the library did work.

Account acct = new Account();
acct.Name = 'testchildqueriesacct';
insert acct;
Contact cont = new Contact();
cont.FirstName = 'test';
cont.LastName = 'test';
cont.AccountId = acct.Id;
insert cont;

String soql = new fflib_QueryFactory(Account.SObjectType)
    .selectField('Name')
    .subselectQuery(Contact.SObjectType)
    .selectField('FirstName')
    .toSoql();

System.debug(soql);
List<Account> accounts = Database.query(soql);

Prints out this incorrect soql

SELECT FirstName FROM Contacts

and throws this exception:

System.QueryException: sObject type 'Contacts' is not supported. If you are attempting to use a
custom object, be sure to append the '__c' after the entity name. Please reference your WSDL or the > describe call for the appropriate names.

Poor performance of QueryFactory (most notably QueryField)

Sorry, it's going to be long. Brace yourself.

This is just a different version of what we reported in #79

We have the following frustration:

  • If we try to debug Apex code (printf-style debugging; not the new Apex Interactive Debugger) with a level of FINEST, the log file fills up with a bajillion of these and overflows the 2MB log limit:
13:57:03.185 (1185547282)|METHOD_ENTRY|[EXTERNAL]|01p36000001tRgR|fflib_QueryFactory.QueryField.equals(Object)
13:57:03.185 (1185753260)|METHOD_EXIT|[EXTERNAL]|01p36000001tRgR|fflib_QueryFactory.QueryField.equals(Object)
  • If we set a Trace Filter for fflib_QueryFactory to try to silence it (by setting Apex debug level to ERROR, not NONE .. due to the Known Issue mentioned in #79), we see these in the log instead:
13:59:44.970 (18970258739)|PUSH_TRACE_FLAGS|[EXTERNAL]|01p36000001tRgR|QueryField|APEX_CODE,ERROR;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;SYSTEM,DEBUG;VALIDATION,INFO;VISUALFORCE,INFO;WORKFLOW,INFO
13:59:44.970 (18970382445)|POP_TRACE_FLAGS|[EXTERNAL]|01p36000001tRgR|QueryField|APEX_CODE,ERROR;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;SYSTEM,DEBUG;VALIDATION,INFO;VISUALFORCE,INFO;WORKFLOW,INFO

Accompanying the log file overflowing, we often reach the Apex CPU Time Limit: "Apex CPU time limit exceeded. An unexpected error has occurred. Your development organization has been notified."

Our Selectors have some methods that retrieve really wide records with lots of parent/grandparent fields included in the related field list .. sometimes a hundred fields wide.

We found a couple particularly painful hot spots in the code -- both are related to fflib_QueryFactory.QueryField.

First, the use of a Set in QueryFactory to hold the fields has the 'surprising' performance behavior outlined in #79. From our perspective, this is a pre-optimization to try to keep a unique set of fields. The implementions of QueryField.hashCode and equals() are expensive and hashCode() is not consistently used by the platform. We think that a List can be used and deduped at the last minute before generating the SOQL string

Second, the loop in toSoql() to generate the list of fields in the SELECT clause uses string concatenation in Apex vs String.join. This has terrible performance characteristics. We thought that we could pass in the Set<QueryField> into String.join since it takes an iterable, but apparently String.join doesn't call the overridden toString() implemented on QueryField. So we're stuck there.

We did some quick hacking and slashing and totally removed QueryField from QueryFactory and replaced it with a List<String>. There are some corner cases there, but the code compiles and generates largely correct SOQL.

So, onto the questions:

  • Are we in the minority of Enterprise Pattern users and hitting problems that no one else is seeing? Or are there workarounds that we're not thinking of for snuffing out fflib debug output before it causes a performance impact or overflows the log? Anyone over at ffdev want to share the secret sauce? :-)
  • We don't see the real world benefit of keeping a Set of QueryFields in order to protect against dupes; it feels like if you're passing duplicate fields into QueryFactory, you're doing something wrong. To support backwards compat, we can shim this behavior and dedupe, but for the new implementations, they shouldn't depend on this behavior (just like they shouldn't depend on the sorting of the selected fields -- like what was fixed in #99)
  • I don't think the issue outlined in #79 is ever going to be fixed by the platform team so QueryField is a lurker that will burn developer after developer. Can we eradicate QueryField?

We're glad to dive in and submit a pull request .. but before we dot all the I's and cross the T's, we wanted to make sure we weren't running totally off the rails .. and that we weren't going to be rejected at the door

How does the trigger pattern handle downstream trigger events?

After reading Andrew's book and blog articles I'm ready to dive in, but still trying to wrap my head around everything.
Up until now, I've been following the trigger pattern that Dan Appleman talks about in his Advanced Apex Programming book. A feature of his pattern is the ability to control how downstream trigger events, caused by DML in the initial trigger, are handled. (Advanced Apex Programming pgs 126-132) As I plan to update my code to use enterprise patterns, I'm not sure how to implement that same behavior.

Can you explain the program flow in the fflib_SObjectDomain.triggerHandler method. Specifically, what is it doing with TriggerStateByClass and how should we be using TriggerStateEnabled? How do we manage the downstream trigger events?

Adding work to UOW breaks factory pattern

Using the UnitOfWorkFactory to obtain a fflib_ISObjectUnitOfWork, unable to registerWork as the registerWork/registerEmail are implemented on fflib_UnitOfWork but not exposed via fflib_ISObjectUnitOfWork. The ability to process "post-DML but pre-commit" operations is incredible useful, would be able to keep consistent use of other patterns if these methods were added to the interface fflib_ISObjectUnitOfWork.

Add helper methods to fflib_SObjectDomain for changed fields

A common need in triggers is to identify whether a field or set of fields has been changed. I like the model that is used in the TriggerX framework to pass in a list of Strings or a list of sObjectFields. I'd also add a way to pass in a field set to see if any fields in the field set have changed.

Domain Event Pattern - can and should it be done?

In Domain Driven Design a single pattern is drawing a lot of attention to itself - Domain Events and Event Queues.

enter image description here
(slide via http://de.slideshare.net/andysal/never-mind-the-bollocks-heres-the-domain-driven-design)

Domain Events models non-technical events as their own entity and allow code that needs to react to those event to subscribe to such events. A kind of Pub/Sub, Observer pattern to decouple code.

I'm a strong believer in applying Enterprise Pattern to the Apex space especially if they are adapted to the special characteristics of the Force.com platform. I see a great use case in using libraries like the awesome FinancialForce Apex Common.

So my questions to the expert out there are:

  1. Does it make sense to port something like this to the Salesforce.com world?
  2. Have you done it and with which experience?
  3. How would one implement the Event queue? Using Async Queuable jobs? Streaming API?

Create Domain Class from non-concrete list of SObjects

Currently a concrete list of SObjects is required in order to create an instance of an fflib_SObjectDomain class. The reason for this is that the constructor of fflib_SObjectDomain calls getSObjectType() on the list specified in the constructor arguments and this call will return null if the List is not of a concrete type (e.g. Opportunity, Account, etc.).

Use Case: In an approach similar to what fflib UOW does, I have a need to keep a Map of SObjects by type and then iterate the map, constructing a domain class and invoking methods on it (methods are exposed via common interface). Currently, my only solution is to keep a static map of concrete Lists to SObjectTypes which can be cloned and used within an execution context. This carries with it additional maintenance/support overhead in managing an "Application" class as well as the perf cost incurred cloning large maps (we have 100+ domain classes). An alternate solution would be to add a constructor to fflib_SObjectDomain allowing the SObjectType to be supplied instead of inferred from the List supplied.

Unfortunately, there is no way to create an List of a specific SObjectType at runtime. Given the goal of SObjectDomain classes and ability to use them outside of a trigger context (which supplies concrete lists in Trigger Maps), adding the constructor seems to make sense and provide a mechanism to do.

Interested in any feedback and especially for those more familiar with the entire fflib package, if not having a concrete list of "Records" could present any downstream impacts.

InvalidFIeldException UserRecordAccess on a Custom Object

I need to select a custom object with UserRecordAccess as a foreign key, but I can't get it from Salesforce SObjectDescribe and SObjectFIeldDescribe, I don't know why... if I can write a select into [] and get that relationship data, why can't I get it from describe? Whatever... I want to use the QueryFactory but I'm getting the InvalidFieldException caused by the problem that I told above through the method fflib_QueryFactory.getFieldToken(String fieldName). I don't want to write a "hard-coded select" that is the only solution that I found until now. Can someone help me?

As a developer, I'd love advanced WHERE conditions in QueryFactory, so that I can build faceted search pages

Hey Andy,

I'm all about this library, and QueryFactory is a really great class. In the docs, you mention that someday you'd like to expand the WHERE clause to be more useful, and I wanted to +1 that idea wholeheartedly. I'm working on a project that does some complicated faceted search things (if a checkbox is selected, then add this specific clause to the WHERE, if the checkbox is not selected, do not add any condition), and being able to build that query more descriptively would help future maintenance of the code.

Are there other use cases that you want to handle in queryfactory WHERE clauses? I'd love to try and come up with a patch.

Performance optimization - build mapByType Maps as needed

Currently during UOW construction, new/dirty/delete/relationship maps are seeded with the types passed in. Using the Application concept, this typically means all types supported by the domain layer. However, when building a unit of work, in most cases, few very SObjects are modified. During the commit phase, the entire map is inspected looking for operations which in most cases are empty for any given type.

To improve performance and reduce memory footprint, suggestion would be to remove the seeding of the maps from the constructor and add the key in registerDirty/New/Deleted methods. The approach would be something along the lines of :

  1. Get SObject name
  2. Find List Index from m_sObjectTypes (could change m_sObjectTypes to a Map<String, Integer> and build in construction setting Integer to index order - or add another member variable that is the Map of typename to order).
  3. Check the appropriate map (map key would become an Integer)
  4. If key not found check if type is a supported type (via m_sObjectTypes). If supported, add the key to the map, else throw UOWException
  5. add record to map

Then, in commit, use the keyset to create a sorted list and iterate over it.

In our application, we have over 100 custom objects so a performance optimization such as this would make a significant impact as it would avoid iterating keys that are empty and also decrease the memory footprint required.

Base Class CRUD Security Checking Not Configurable

In the domain base class SObjectDomain, currently code is structured such that all trigger paths must go through a security check. While this is optimal for most use cases, I have come across a specific use case in which this is limiting. Today, we have a site set up for customers to come and buy small parts for our product. We do not have a need to authenticate these users and so are not using a customer portal. As expected this site uses the Guest User License which restricts the ability to edit or delete standard object records. As our store runs through utilization of standard objects, while the customer is adding items to the cart and proceeding through checkout we have triggers that need to fire on update to set up their purchase profile correctly.

Changing that security methods such that they would be easily modified outside the base class to allow for specific exceptions would be a great help.

Unable to deploy into org

When I upgrade my fflib in my current org using the Deploy button (which normally worked) it fails with the following output:

Deployment Started
Status: Queued 
Status: InProgress 
Status: InProgress 
Status: InProgress 
Status: InProgress 
Status: Completed 
Deployment Complete
Failures:
classes/fflib_ApplicationTest.cls(84,41):Dependent class is invalid and needs recompilation:
UP2GO_2S1.fflib_SObjectMocks: line 189, column 4: Method does not exist or incorrect signature: [fflib_ApexMocks].mockVoidMethod(fflib_SObjectMocks.SObjectUnitOfWork, String, List)
classes/fflib_SObjectMocks.cls(189,4):Method does not exist or incorrect signature: [fflib_ApexMocks].mockVoidMethod(fflib_SObjectMocks.SObjectUnitOfWork, String, List)

Order of DML Operation

Currently there is no way (that I can tell) for someone to control the order of the DML operations in fflib_SObjectUnitOfWork. I've found myself in a situation in which I would like to complete all my updates first and then complete the inserts and/or deletes. Any thoughts on resolving this? Should it be resolved?

Unable to deploy: no "System Administrator" or "Read Only" profiles

I get the following message when I try to deploy on my production environment. It's weird because I was able to deploy the same package on my sandbox.

From what I can understand, the "unit test user" is not able to create new user for test.

Can somebody help me ? I really need to be able to install the package on my prod environment.

Thx

Deployment CompleteTest failure, method: fflib_SecurityUtilsTest.readonly_field_access -- System.QueryException: List has no rows for assignment to SObject stack Class.fflib_SecurityUtilsTest.setupTestUser: line 38, column 1
Class.fflib_SecurityUtilsTest.readonly_field_access: line 56, column 1

Test failure, method: fflib_SecurityUtilsTest.readonly_objectAndField_access -- System.QueryException: List has no rows for assignment to SObject stack Class.fflib_SecurityUtilsTest.setupTestUser: line 38, column 1
Class.fflib_SecurityUtilsTest.readonly_objectAndField_access: line 153, column 1

Test failure, method: fflib_SecurityUtilsTest.readonly_object_access -- System.QueryException: List has no rows for assignment to SObject stack Class.fflib_SecurityUtilsTest.setupTestUser: line 38, column 1
Class.fflib_SecurityUtilsTest.readonly_object_access: line 99, column 1

Test failure, method: fflib_SecurityUtilsTest.sysadmin_objectAndField_access -- System.QueryException: List has no rows for assignment to SObject stack Class.fflib_SecurityUtilsTest.setupTestUser: line 38, column 1
Class.fflib_SecurityUtilsTest.sysadmin_objectAndField_access: line 238, column 1

Deployment to Salesforce fails due to missing class

When I try deploying the latest code into a Developer Edition org of mine, deployment is failing with the following error:

Deployment Started
Status: Queued
Status: InProgress
Status: InProgress
Status: InProgress
Status: InProgress
Status: InProgress
Status: Completed
Deployment Complete
Failures:
classes/fflib_SObjectMocks.cls(36,11):Invalid type: fflib_ApexMocks

It looks like the new fflib_SObjectsMocks class is referencing fflib_ApexMocks, but that class is missing from the repo, and package.xml.

System.CalloutException: You have already created Savepoints. You cannot make callout after creating a Savepoint

I'm currently working on implementing this library for our organization and am struggling with an issue in unit tests

System.CalloutException: You have already created Savepoints.   You cannot make callout after creating a Savepoint

What I did was extend the fflib_SobjectUnitOfWork class using a custom class with an additional "Work" item inner-class SendSMSWork which calls my SMS integration class. This follows the same pattern as the registerEmail pattern already in the parent class. When I originally tried this in the UI all works absolutely fine and my SMS is sent. However in my Unit tests I'm having issues with the above error.

I'm wondering if anyone else has solved this issue and what would be the advised way within the context of this library?

I'm hoping I can mock out my SMS Service which would allow these tests to pass.

Failed deployment to salesforce

Getting following error while deploying to salesforce. Can you please advice if i'm missing something.

Deployment Started
Status: Queued
Status: InProgress
Status: Completed
Deployment Complete
Failures:
classes/fflib_SObjectMocks.cls(36,11):Invalid type: fflib_ApexMocks

Thanks,
Karthik Kornalies

addQueryFactorySubselect deprecated method for sObject (Related)

Since subselectQuery(SObjectType related) method is deprecated in fflib_QueryFactory, are there any changes in the works for addQueryFactorySubselect method in fflib_SObjectSelector class?

I am assuming there should be method overload with passing relationship name instead of related sObject from selector.

Provide dependency injection for SecurityUtils for testing and alternative security implementations other than fflib_SecurityUtils

This enhancement resulted from discussion in #56.

Currently the SecurityUtils class is used for various FLS & CRUD checks. The static methods in this class are used in various places in the library (e.g. fflib_QueryFactory) where these checks need to occur. In the case where a custom security solution is required, performing these checks is still necessary but there is no way to override how the check is performed. Custom security can be implemented in other ways but this potentially leads to redundant checks and also a confusing design because checks are done in different places.

Suggestion would be something along the lines of the following:

  1. Create a new interface fflib_ISecurity. To begin with, the methods on this interface can mirror the static methods on fflib_SecurityUtils
  2. Inject an instance of fflib_ISecurity in to the places where it is needed (e.g. fflib_QueryFactory) and have the QF use the injected instance rather than the concrete static methods.
  3. SObjectDomain could also receive an instance of fflib_ISecurity and its permission checking could be updated to defer to the class instead of directly checking describe.

Making a change as described above would yield the following benefits:

  1. All "security" logic would be in one place and anywhere in the library where security checks were required could defer to the security class injected.
  2. Allows for custom security implementations while still providing base level security functionality
  3. Improve testability

Cyclic Triggers

I'm working on a very large implementation using the platform and we have a number of cases where the business logic requires some APEX rollups and processing of related tables.

My usual method is to use a singleton to control if a trigger has run previously and have it gracefully return and thus stop any cyclic triggers from running away from each other or causing unwanted handlers to run and take up resources that just aren't needed.

As this code is now being repeated in a number of different Domain classes i was thinking of enhancing the fflib_SObjectDomain such that we have process controls within each handle[event] method.

So a few questions before I start:

  1. Do you see this as a valid enhancement for the branch
  2. if yes, how flexible do we want it?

Is it a straight, this has run before don't run it again per event per object, or,
You can set how many times an objects trigger handler will run e.g. unbounded, once, twice etc?

Feedback is welcomed,

Chris

Design issue

Thanks for your reply.

I have created an App in fallowing design pattern.
1.Controller
2. Service class
3. Domain Class.

The problem I am facing here is for example I want to create an Contact record by using VF page. So I have created an single instance in controller. But as per your Design I need to pass list of instance to Service and Domain class. If I didn't pass in that way I will get an salesforce security issue.So, how do I resolve this.

Looking Forward for your reply.

Test Data Class

I use this library in many different orgs and as such I find that there are quite a few different instances where field requirements are put in place. Whenever I newly install this package or have to update it, I have to remember to manually update every place an account, contact, and activity are used rather than just updating a test data class.

Any thoughts on whether is makes sense or not to work on adding this functionality?

Test failures in environment with Financial Force packages installed

When deploying into a fresh developer edition, all tests pass and everything is hunky dory.

When deploying into an environment which has the followingFinancial Force packages installed (and no other Apex), SObjectSelectorTests fail.

  • FinancialForce Expansion Pack (ffxp)
  • FinancialForce QuickStart (ffqs)
  • FinancialForce ClickLink (ffirule)
  • FinancialForce Accounting (c2g)
  • FinancialForce Reporting (ffr)
  • FinancialForce Accounting Accounts Payable Extension (ffap)
  • Basic SCM Reports
  • FinancialForce Central (ffc)
  • FinancialForce Journal Extension (ffgl)
  • FinancialForce Cash Entry Extension (ffcash)
  • FinancialForce VAT Reporting (ffvat)
  • FinancialForce OneTouch (ffbext)
  • SCM (SCMC)
  • Declarative Lookup Rollup Summaries Tool (dlrs)
  • FinancialForce Enquires
  • FinancialForce Consulting Tools (ffct)

Test Failures

Class
fflib_SObjectSelectorTest
Method Name
testDefaultConfig
Pass/Fail
Fail
Error Message
System.AssertException: Assertion Failed: Expected: AccountNumber,AnnualRevenue,Id,Name, Actual: Name,AnnualRevenue,AccountNumber,Id
Stack Trace
Class.fflib_SObjectSelectorTest.testDefaultConfig: line 185, column 1

Class
fflib_SObjectSelectorTest
Method Name
testGetFieldListString
Pass/Fail
Fail
Error Message
System.AssertException: Assertion Failed: Expected: myprefix.AccountNumber,myprefix.AnnualRevenue,myprefix.Id,myprefix.Name, Actual: myprefix.AccountNumber,myprefix.Name,myprefix.Id,myprefix.AnnualRevenue
Stack Trace
Class.fflib_SObjectSelectorTest.testGetFieldListString: line 46, column 1

Is this class also helpful for caching DescribeFieldResults - and how?

Even if there are no describe limits in Apex anymore I realized that repeated getDescribe() is really expensive time-wise. I therefore planned to use this class to get some caching just to find out that there it only seems to care about DescribeSObject scenarios.

Is this intentional or do I get something wrong?

Can't use fflib_SObjectSelector classes at post-install time

We've integrated a number of fflib classes into one of our managed packages. We are making extensive use of fflib_SObjectSelector within our application. We also utilize the capability where you can invoke an Apex class upon completion of package installation into subscriber orgs. We're trying to construct an instance of one of our custom SObjectSelector classes and use it to run queries at post-install time. What we're finding is that at post-install time, we're getting the following error:

There was a problem creating the Fee records
Entity is not api accessible
Stack trace:
Class.PatronTicket.fflib_SObjectSelector: line 35, column 1
Class.PatronTicket.SObjectSelector.<init>: line 15, column 1
Class.PatronTicket.Selector_FeeSlot.<init>: line 37, column 1
Class.PatronTicket.Service_Fee.createFeeSlotObjects: line 205, column 1
Class.PatronTicket.Service_Fee.configureUnitFeeSlot: line 373, column 1
Class.PatronTicket.PostInstallOperations.migrateFeesFromPTicketSettings: line 91, column 1
Class.PatronTicket.PostInstallOperations.doPostInstallOperations: line 33, column 1
Class.PatronTicket.PostInstallOperations.onInstall: line 12, column 1
Line number: 35

This can be traced back to the following static initialization code in fflib_SObjectSelector:

    /**
     * This overrides the Multi Currency handling, preventing it from injecting the CurrencyIsoCode fie ld for certain System objects that don't ever support it
     **/
    private static Set<String> STANDARD_WITHOUT_CURRENCYISO = new Set<String> { AsyncApexJob.SObjectType.getDescribe().getName()
                                                                                , ApexClass.SObjectType.getDescribe().getName()
                                                                                , Attachment.SObjectType.getDescribe().getName()
                                                                                , RecordType.SObjectType.getDescribe().getName() };

This same code executes just fine from application context, as well as unit test context. I suspect this is one of those quirky issues that only occurs when your code executes in the context of the post-install user. Has anyone else experienced this?

Upgrading to latest

This is more of a question than an issue...

If I use the 'Deploy to Salesforce' button, does that bring in the latest versions of all files in the fflib/src folder? Specifically, I have previously deployed to a sandbox, if I deploy again to the sandbox will I have the latest version at that point?

fflib_QueryFactory().selectFieldSet() fails with when FieldSet queries namespaced fields

I have a valid FieldSet that contains field of a managed Custom Object and some fields of a related objects

When I run this code in unmanaged namespace-less org

new fflib_QueryFactory(CustomObject__c.SObjectType)
            .selectFieldSet(SObjectType.CustomObject__c.Fieldsets.MyFieldSet)

it perfectly works. When try the same in a managed org with namespace (make Cusom Object and the related Object part of this namespace) it fails with:

caused by: UP2GO_2F.fflib_QueryFactory.InvalidFieldException: Invalid field 'NAMESPACE__Field__c' for object 'NAMESPACE__CustomObject__c'

Class.NAMESPACE.fflib_QueryFactory.getFieldToken: line 95, column 1
Class.NAMESPACE.fflib_QueryFactory.selectFieldSet: line 276, column 1
Class.NAMESPACE.fflib_QueryFactory.selectFieldSet: line 262, column 1
Class.NAMESPACE.MasterPartSelectCtrlExt: line 94, column 1

Diagnostics Support

Hello All,

I would like to start a discussion on adding support for diagnostics. I've been working through "Advanced Apex Programming" by Dan Appleman and came across his ideas on diagnostics and thought it would be a great addition to the library. I would be happy to start the work on getting this piece integrated if others thought it would be beneficial.

Thoughts?

Inconsistent performance when constructing QueryFactory

We have an ongoing Case with Tier 3 (I'll spare the rant) regarding a performance problem that we're seeing when constructing a new fflib_QueryFactory

Here's a sample Selector:

public with sharing class TicketOrdersSelector extends fflib_SObjectSelector {
  public TicketOrdersSelector() {
    super();
  }

  public TicketOrdersSelector(Boolean includeFieldSetFields) {
    super(includeFieldSetFields);
  }

  List<Schema.SObjectField> getSObjectFieldList() {
    return new List<Schema.SObjectField> {
      TicketOrder__c.Account__c,
      TicketOrder__c.AmountDue__c,
/* <snip ... about 60 additional fields/> */
      TicketOrder__c.UserAgent__c
    };
  }

  Schema.SObjectType getSObjectType() {
    return TicketOrder__c.SObjectType;
  }

  public List<TicketOrder__c> selectById(Set<Id> idSet) {
    return (List<TicketOrder__c>) selectSObjectsById(idSet);
  }
}

We're seeing that calling newQueryFactory() on an instance of TicketOrdersSelector is taking 200-300ms.

We boiled down the problem to the use of a Set to back the list of QueryFields in QueryFactory. QueryField implements hashCode() and equals() but upon instrumenting those two methods, we found that hashCode() wasn't always called but equals() was -- up to N times -- basically behaving more like a List than a Set from a performance perspective. Concretely, this meant that equals() was being called (N^2)/2 times -- a real drag if you have 50+ fields in your Selector

Further debugging showed that the behavior was affected by the logging level. Setting Apex Code to FINEST would result in the N^2 behavior while setting it to DEBUG wouldn't. But this wasn't how we had our DEs configured -- they usually had DEBUG set as the default level.

Further investigation lead to the log override we were setting on fflib_QueryFactory to set all log levels to NONE (so that we didn't pollute all of our logs with METHOD_ENTRY/METHOD_EXIT). It seems like setting the overrides for the class caused it to revert back to the N^2 behavior. Without the log override, it was performant (though noisy).

The words from Tier 3 thus far are:

This is Working as Designed (WAD). The difference comes from underlying Map representations. We have two representations for Map.

One keeps the objects in a Map in the interpreter (apex) native representation. And in this case, if the put() method (or add() ) is called to it, uniqueness of keys are determined by using both of hashCode() and equals(). (A value returned by the hashCode() method is used to determine a bucket, and the equals() method is used to identify objects in the same bucket.)

Once a Map is marshaled, the other representation is used.In this representation, in the put() method call, we traverse all objects in a Map and linearly check uniqueness of keys using the equals() method if a user defined key is used.That's why you don't see the hashCode() method being called but see the equals() method calls in our testcase. (The Map/set object is marshaled when trying to generate a debug message for local variable assignments.)

However, the latter representation does not violate the Map contract. Any method call defined in the Map class works as per doc.

This obviously disregards the fact that we're not generating debug messages for QueryFactory -- we've explicitly disabled it. Yet it still behaves as though it's set to FINEST even when the entry point log level is DEBUG.

The reason I'm opening this ticket is to ask: has anyone else figured out how to make QueryFactory performant in all situations? Developer orgs shouldn't behave differently than production deployed packaged code.

fflib_SObjectSelectorTest.testGetFieldListString Fails

I've just started working with the library and I thought I'd quickly run all tests to get an idea of where I was at with coverage, but unfortunately one of the packaged test failed!

Here are the details:

Apex Test Result Detail

Time Started
20/06/2014 16:12
Class
fflib_SObjectSelectorTest
Method Name
testGetFieldListString
Pass/Fail
Fail
Error Message
System.AssertException: Assertion Failed: Expected: myprefix.Name,myprefix.AccountNumber,myprefix.Id,myprefix.AnnualRevenue, Actual: myprefix.Name,myprefix.Id,myprefix.AccountNumber,myprefix.AnnualRevenue
Stack Trace
Class.fflib_SObjectSelectorTest.testGetFieldListString: line 43, column 1

addOrdering is not defining the sort order

When I add
addOrdering(Account.LastModifiedDate, fflib_QueryFactory.SortOrder.DESCENDING). into newQueryFactory(), the records are returned sorted by name (aka default sort).
When I use [SELECT Id, Name FROM Account ORDER BY LastModifiedDate DESC] in the Selector, it gets sorted correctly.
Also when I override getOrderBy with
public override String getOrderBy() {return 'LastModifiedDate DESC';} the records get sorted accordingly and it looks like any addOrdering commands sorting is performed before this 'final' sorting.

P.S. I was able to have addOrdering taken into the consideration when I was using in getOrderBy the field that has all null or same values, so the sort order done by addOrdering is not get resorted.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.