Andy in the Cloud

From BBC Basic to Force.com and beyond…


4 Comments

Introducing the Flow Factory

Flow is a great technology for providing a means for non-coders to build functionality. More so than any other point and click facility on the platform, even Process Builder. Why? Because it offers a rich set of Elements (operations) that contain conditional branching, loop and storage of variables. Along with the ability to read or update any object (API accessible) you like. Its almost like a programming language….

Ironically, like Apex, it is missing one increasingly asked for feature… being able to call another Flow that is not known at the time your writing your calling code. Such as one configured via the amazing Custom Metadata… Basically a kind of Apex reflection for Flow. Often the workaround for this type of problem is to use a factory pattern.

As i highlighted in this prior blog on calling Flow from Apex, the platform does not yet provide this capability to change this please up vote this idea. Well at least not in Apex, as there exists a REST API for this. Meanwhile though back in the land of Apex, it occurred to me when building the LittleBits Connector last year. As workaround i could generate a factory class that would workaround this.

I have created Flow Toolbelt library (GitHub repo here) and package (if you want to install that way) which takes last years solution and lifts it into its own smaller package. The Flow Factory tab discovers the Flows configured in your org and generates the required factory Apex class. If you add or remove flows you need to repeat the process.

FlowFactory.png

Once this has been Deployed you can use code like the following. Passing in the name of your Flow. Note this is a WIP version of the library and needs more error handling, so be sure to pass in a valid Flow name and also at least an empty params Map.

Flow.Interview flow =
  flowtb.FlowFactory.newInstance('TestA', new Map<String, Object>());
flow.start();
System.debug(flow.getVariableValue('Var'));

I think this concept can be extended to allow Flow to run from other Apex entry points, such as the recently added Sandbox Apex callback. Allowing you to run Flow when your Sandbox spins up. Let me know your thoughts, if this is something useful or not.

 

 


Leave a comment

Working with Apex Mocks Matchers and Unit Of Work

The Apex Mocks framework gained a new feature recently, namely Matchers. This new feature means that we can start verifying what records and their fields values are being passed to a mocked Unit Of Work more reliably and with a greater level of detail.

Since the Unit Of Work deals primarily with SObject types this does present some challenges to the default behaviour of Apex Mocks. Stephen Willcock‘s excellent blog points out the reasons behind this with some great examples. In addition prior to the matchers functionality, you could not verify your interest in a specific field value of a record, passed to registerDirty for example.

So first consider the following test code that does not use matchers.

	@IsTest
	private static void callingApplyDiscountShouldCalcDiscountAndRegisterDirty()
	{
		// Create mocks
		fflib_ApexMocks mocks = new fflib_ApexMocks();
		fflib_ISObjectUnitOfWork uowMock = new fflib_SObjectMocks.SObjectUnitOfWork(mocks);

		// Given
		Opportunity opp = new Opportunity(
			Id = fflib_IDGenerator.generate(Opportunity.SObjectType),
			Name = 'Test Opportunity',
			StageName = 'Open',
			Amount = 1000,
			CloseDate = System.today());
		Application.UnitOfWork.setMock(new List<Opportunity> { opp };);

		// When
		IOpportunities opps =
			Opportunities.newInstance(testOppsList);
		opps.applyDiscount(10, uowMock);

		// Then
		((fflib_ISObjectUnitOfWork)
			mocks.verify(uowMock, 1)).registerDirty(
				new Opportunity(
					Id = opp.Id,
					Name = 'Test Opportunity',
					StageName = 'Open',
					Amount = 900,
					CloseDate = System.today()));
	}

On the face of it, it looks like it should correctly verify that an updated Opportunity record with 10% removed from the Amount was passed to the Unit Of Work. But this fails with an assert claiming the method was not called. The main reason for this is its a new instance and this is not what the mock recorded. Changing it to verify with the test record instance works, but this only verifies the test record was passed, the Amount could be anything.

		// Then
		((fflib_ISObjectUnitOfWork)
			mocks.verify(uowMock, 1)).registerDirty(opp);

The solution is to use the new Matchers functionality for SObject’s. This time we can verify that a record was passed to the registerDirty method, that it was the one we expected by its Id and critically the correct Amount was set.

		// Then
		((fflib_ISObjectUnitOfWork)
			mocks.verify(uowMock, 1)).registerDirty(
				fflib_Match.sObjectWith(
					new Map<SObjectField, Object>{
						Opportunity.Id => opp.Id,
						Opportunity.Amount => 900} ));

There is also methods fflib_Match.sObjectWithName and fflib_Match.sObjectWithId as kind of short hands if you just want to check these specific fields. The Matcher framework is hugely powerful, with many more useful matchers. So i encourage you to take a deeper look David Frudd‘s excellent blog post here to learn more.

If you want to know more about how Apex Mocks integrates with the Apex Enterprise Patterns as shown in the example above, refer to this two part series here.


11 Comments

Declarative Rollup Tool Summer Release!

Over the course of the last couple of weeks, i have been focusing my community time on release v2.4 of the DLRS tool. Specifically focusing on some much requested features driven by the community in the the Chatter group.

So lets get stuck in…

Rollup Scheduler Improvements

The ability to run a full (or partial with criteria) recalculate of a rollup on a daily schedule has been in the tool for a few releases now. However up until now the only option was to run it at 2am everyday. It is now possible to change this with this new UI, its a bit raw and basic, but for now it should at least give some more flexibility.

RollupSchedule.png

Support for Merging Accounts, Contacts and Leads

The platform has some special handling for merging Accounts, Contacts and Leads. Especially when it comes to when Apex Triggers are invoked. Basically if your parent object is one of these objects, prior versions of the tool had no awareness of this operation, so rollups would not recalculate. If you are using Realtime or Schedule calculation modes on your rollups. Since the platform does not fire Apex Triggers for child records reparented as a result of a merge.

With this release there are two things you can do to fix this. First when you click the Manage Child Trigger button, you get a new checkbox option to control deployment of an additional Apex Trigger on the parent object. If your upgrading you will need to click Remove then Deploy again, to see this.

ParentTrigger.png

IMPORTANT NOTE: If you don’t feel merge operations are an issue for your use cases you can deselect this option and cut down on the number of triggers deployed. Also if it is only the rollup child object that supports merging, there is no need to deploy any additional triggers and the tool does not show the above checkbox option.

Secondly you need to setup the RollupJob as an Apex Scheduled job (under Setup > Apex Classes), even if you don’t have any Schedule Mode rollups. This is due to the fact that due to a platform restriction, the tool cannot recalculate rollups realtime during a merge operation. So it can only record that they need to be recalculated. It does this via the tools scheduled mode infrastructure, by automatically adding records to the Lookup Rollup Summary Schedule Items object. Note that you don’t need to change your rollups from Realtime to Scheduled mode for this to work, only schedule the job.

Support for Archived / Deleted Records via the All Rows Setting

Salesforce archives Tasks and Events after a while. If you have rollups over these child objects you can enable the Aggregate All Rows checkbox. This will ensure your rollups remain accurate even if some records have been archived. Note this also will apply to records in the recycle bin. For upgrades (if your not using the Manage Lookup Rollup Summaries tab), you will need to add this field to your layout to see it.

AllRows.png

Row Limit for Concatenate and Last Rollup Operations

If your using the Last or Concatenate operations, you can define a limit as to how many child records are actually considered when calculating the rollup. This is useful if your using Concatenate into a fix length field for example. When upgrading you need to add the new Row Limit field to your layout if your not using the swanky new Manage Lookup Rollup Summaries tab.

RowLimit.png

Improved House Keeping for Scheduled Mode

If your are using rollups with their Calculation Mode set to Scheduled. The tool records parent rollup records to be later recalculated by the RollupJob Apex Scheduled job. In past releases if through merge or other operation the parent record was deleted before the next scheduled run. Then records would sit in limbo in the Lookup Rollup Summary Schedule Items object, being processed and erroring over and over. These will now be cleared out and there is no upgrade actions you need to take for this.

Summary

Thanks for everyones support for this tool, i hope these changes help you go further with clicks not code! Though as reminder please keep in mind the best practices and restrictions listed in the README. If you have any questions you can either post comments on this blog or use the Chatter Group. The Chatter Group is a great place to get your query seen by a broader group of people who are also diligently supporting the tool as well!

You can find releases of the tool here.


2 Comments

Lightning Out: Components on Any Platform

This blog is my first video blog! Since Salesforce does not record the Developer Theatre sessions at the Salesforce World Tour events i thought i would do a re-run at home of my session last week and publish it here. As you know i have a love for all things API’s, and while I typically focus in this blog on backend API’s, there is one i’ve been keen to explore for a while…

The Lightning Out API, as any good API should, brings great promise and reality i’m pleased to say, to further integrating and extending the power of the platform and generally simplifying our users lives. In this case boldly going where no Lightning Component has gone before….

You can access the slides and thus the links within via this Slideshare upload.


6 Comments

Introduction to the Platform Action API

shutterstock_159003926.jpg

Actions are Salesforce’s general term for tasks users can perform either through buttons throughout various UI’s on desktop, mobile, tablet etc or in fact via non-UI processes such those built via via Process Builder or Automation Flows.

Actions are about “getting things done” in Salesforce. They encapsulate a piece of logic that allows a user to perform some work, such as sending email. When an action runs, it saves changes in your organization by updating the database. More here.

Over the years we’ve had many terms and ways to define these. Custom Button and Custom Link are perhaps the most obvious ones, which i’ve covered here in the past. Quick Actions (previously Publisher Actions) and more recently we’ve had Action Link‘s, which i covered in a past blog. Then of course the Standard Buttons, Edit, Delete, Follow, Submit for Approval etc provided by the platform. Such actions appear in various places Record layouts, List Views, Related Lists, Chatter and more recently Flexi Pages (aka Lighting Pages).

You might wonder then, if you had the task as developer to build your own UI or tool that wanted to expose some or all of the above actions, it would be quite a challenge to find them all. Indeed in some cases you may have had to resort to URL hacking to invoke some of them. Well worry not no longer, Salesforce’s clever architects now have you covered! Enter a new virtual SObject known as PlatformAction! Before we get onto what exactly virtual means, lets review some Actions and some SOQL queries…

Consider this Account Record detail page in the Classic (or Aloha) UI

PlatformActionAccount.png

Note down your record ID and use it in a query like the one below…

SELECT DeviceFormat, Label, Type, Section,
       ActionTarget, ActionTargetType, ActionListContext
  FROM PlatformAction
  WHERE ActionListContext = 'Record' AND
        SourceEntity = '001B000000D2V0n' AND
        Section = 'Page' AND
        DeviceFormat = 'Aloha'

In Developer Console you should see something like this…

PlatformActionQueryResults1.png

Pretty cool huh!? Check out the ActionTarget field, for the Standard Button records, thats the URL you can place on your UI’s to invoke that action, simple as that! Better still this is a supported way to get it, no more URL hacking! Now lets add a couple of Custom Buttons and re-run the query…

PlatformActionAcount2.png

We now see CustomButton records appear…

PlatformActionQueryResults2.png

This next query reveals actions shown on a List View. I did note Custom List View buttons that require record selection did not appear however. I suspect this is due to them requiring more than a simple HTTP GET URL to invoke.

SELECT DeviceFormat, Label, Type, Section,
       ActionTarget, ActionTargetType, ActionListContext
  FROM PlatformAction
  WHERE ActionListContext = 'ListView' AND
        SourceEntity = 'Account' AND
        Section = 'Page' AND
        DeviceFormat = 'Aloha'

Other observations..

  • Prior to Summer’16 (out in preview as i write this), Apex SOQL was not supported, only REST API SOQL. This is due to a limitation with the internally applied LIMIT keyword. This has now been resolved in Summer’16, so Apex SOQL now works!
  • SourceEntity can also be given an SObject API name, e.g. SourceEntity = ‘Account’, the result here are object level buttons, like New or those you add to the MRU page.
  • DeviceFormat field value matters, if you leave it off, it defaults to Phone. Thus some actions will be missing from those in Desktop (Lightning Experience) or Aloha (Classic). I eventually found Custom Buttons using Visualforce pages that didn’t have the Lightning Supported checkbox set didn’t appear when querying with the Phone device type for example.
  • User context matters, actions returned are user and configuration sensitive, meaning the record itself, record type and associated layout all contribute to the actions returned. Custom Buttons for example need to be on the relevant layout.
  • Label and Icon information, there are also fields that allow you to render appropriate labels and icons for the actions.
  • Related List actions, you can also retrieve actions shown on related lists, search for RelatedList in the help topic here.
  • Describe actions? You will notice some actions have an ActionTargetType of Describe? These are invoked via an API, something i will cover in later blog.

So lets discuss the “virtual SObject” bit!?!

Your probably wondering what a virtual SObject is?

Well my best guess is its an SObject that is not backed by physical data in the Salesforce database. If you check the documentation you’ll see fields just like any other object and it supports SOQL (with some limitations). My thinking is the records for this object are dynamically generated on demand by doing all the heavy lifting internally to scan all the various historic places where actions have been defined.

Thank you Salesforce architects, this is now my #1 coolest Salesforce API!

Whats next?

  • For starters, no more URL hacking of those standard pages, no excuses now!
  • Helper class or Visualforce and/or Lighting component for actions?
  • Explore the Force.com Actions Developer Guide


2 Comments

Disabling Trigger Events in Apex Enterprise Patterns

Iautobat.jpeg‘m proud to host my first guest bloggerChris Mail or Autobat as he is known on GitHub. Take it away Chris….

How to put the safety on…

Being an architect in a professional services organisation is a funny game. Each project is either a shiny new Salesforce instance without a fingerprint on it or an unknown vault of code and configuration that we must navigate through.

I have been using the fflib pattern now for some time, and more of our teams are adopting it for our programs of work. My latest addition is something that an architect might wonder why we need; the ability to turn off triggers via a simple interface on all domains.

In an ever growing complex environment, perhaps multiple projects over time delivering iterative enhancements I was noticing a common piece of code being developed within the Domain layer. It looked something along the lines of this:

public override void onAfterInsert()
{
    // if this is set we are already in a loop and want to exit!
    if(bProhibitAfterInsertTrigger)
    {
        return;
    }
    // down here we do something, maybe insert an Account!
}

While small and inconspicuous it allowed our code base to become inconsistent as there was no control over the exposure of these controlling flags and worse, we were repeating ourselves in every domain!

The solution was simple, a fluent style API within fflib_SObjectDomain. Any code can now simply set the control flags for any domain class:

fflib_SObjectDomain.getTriggerEvent(YourDomain.class).disableAll(); // dont fire anything
fflib_SObjectDomain.getTriggerEvent(YourDomain.class).disableAllBefore();
fflib_SObjectDomain.getTriggerEvent(YourDomain.class).disableAllAfter();

fflib_SObjectDomain.getTriggerEvent(YourDomain.class).disableBeforeInsert();
fflib_SObjectDomain.getTriggerEvent(YourDomain.class).disableBeforeUpdate();
fflib_SObjectDomain.getTriggerEvent(YourDomain.class).disableBeforeDelete();

fflib_SObjectDomain.getTriggerEvent(YourDomain.class).disableAfterInsert();
fflib_SObjectDomain.getTriggerEvent(YourDomain.class).disableAfterUpdate();
fflib_SObjectDomain.getTriggerEvent(YourDomain.class).disableAfterDelete();
fflib_SObjectDomain.getTriggerEvent(YourDomain.class).disableAfterUndelete();

To enable, just call the inverse e.g. .enableAfterInsert(); etc.

While not every code base will need to use these flags, they allow you to control quickly and easily your trigger execution with a single line of code that all your development team can reuse and follow.


10 Comments

GitHub Salesforce Deploy Tool Lightning Edition

A recent discussion on Twitter around sharing Salesforce configuration between admins has motivated me to revisit this tool. Before getting into anything major (watch this space). I decided to get back into the tools code by addressing a few outstanding maintenance tasks, enhancements and bug fixes, as well as treating it to a face lift!

LightningGitHubSFDeploy.png

As some of you may have noticed the tool has now adopted the Salesforce Lightning Design System look and feel. This new version is not just cosmetic, its also addressed some key enhancements and bug fixes…

LightningGitHubSFDeploy2.png

In keeping with the Lightning principles, this release makes the Deploy to Salesforce button (example shown below), even easier to place in your repository README files with less configuration required. The button will now automatically detect the GitHub repository. Which is useful if you Fork a repository into your own account or rename it, you no longer need to change the README file. The button code is now also smaller.

LightningGitHubSFDeployButton.png

IMPORTANT NOTE: This only works if your placing the button code in a GitHub README file. If your planning on using the button on a blog, article or wiki etc tick Use Specified Owner and Repository checkbox to have the specified repository details encoded into the button code as before.

This release has now also addressed issues preventing use with repositories that have Reports or Lightning Components in them. So you can now use the tool to deploy your favourite open source Lightning Components!

Finally if you have any private repositories, an improvement around the error handling in this area has also been made. Thanks to some great code contributions from Moti Korets and  Nathan Kramer for the whole GitHub private repository support! Thanks guys!

 

 

Follow

Get every new post delivered to your Inbox.

Join 430 other followers