Thursday, September 15, 2016

Force.com Migration Tool - Deploy like a Pro with Change Sets, Workbench & the Metadata API

Introduction


When I started working with the salesforce platform a couple of years back, one of the things I noticed was how painful deployments were. Back then I didn't understand why. But I have come to understand that long painful deployments have more to do with improper planning and release management than with the platform itself. Good tools for deployment certainly do exist, so the problem is not with technology. In this article we will look at one such tool that is very efficient, easy and less error prone. This method will work for the needs of most organisation out there using salesforce. This is the Metadata API way.

What is the Metadata API?


In order to answer this question, we need to understand what metadata is. Metadata can be described as data that describes data. This means it is not the data itself, but everything you can create from Setup. In Salesforce Setup is the UI entry point for doing customisations. On the Salesforce platform Metadata is represented as XML Files.

The Metadata API gives us the ability to manage these customisations. Two prominent tools built on the Metadata API are;

  • the popular eclipse based development tool Force.com IDE and 
  • the Force.com Migration toll which we will be taking a look at here. 

For more information on the Metadata API look at the documentation - Understanding Metadata API

Force.com Migration Tool


This tool is used to move metadata from one Salesforce org or to another. This means moving the metadata XML files from one or to another. Two of it's prominent methods let you download or retrieve the XML files from the source Org onto your local file system and then upload or deploy them to the destination org.

Prerequisite


Please look Prerequisites for Using the Force.com Migration Tool at for prerequisites you need in order to use the Force.com Migration Tool.  Here is a brief summary of what you need.


  1. You need to have Java version 1.7.x or later installed. You can download Java here.
  2. You need to have ant install since the Force.com is based on ant. For those running mac this two minute video Install ant on Mac OSX shows you how to install mac on you machine.
  3. You need to get developer orgs. Ideally you should use an old Developer Org with configuration you can move to another org and a new Developer Org as the target org.


So let us look at how this works in practice.

How it works


1.) Download the Force.com Migration toolkit


You can download the Force.com Migration Tool here. Another way to reach this link will be from you Developer Org by going to Setup -> Develop -> Tools. Here click on "Force.com Tools and Toolkits" and in the next page click on the "Force.com Migration Tool".

Here you will also find a nice video from Jeff Douglas, that explains how to do this. You can also watch the video if you prefer. In this blog I will show you a step by step process of how I normally do it.

There may be two versions to download from, the preview version for the upcoming release and the version from the previous release. If you intend to deploy to Production please choose the version on which Production is running. For example if your Production Org is not yet upgraded to the next release, then use the version for the previous release. After download

2.) Create a directory for your project


After you extract the zip file you can open it in your editor for ease of use. I use Sublime Text and the Mavensmate plugin, so for me it is as easy as dragging the whole folder and dropping it on sublime text. Your files should look like this;



The important files here are;

  • ant-salesforce.jar which are the ant tasks
  • build.properties in the sample project
  • build.xml in the sample project
We will look at the build files in detail in a minute. So I want to deploy some configuration from my Trailhead developer org to a new dev org. So I will create a deployment folder for the Trailhead deployment. My project looks like this;



Remove holds two files, a barebones package.xml file and a destructiveChanges.xml files which specifies components we want to delete in the target or destination org.

Retrieve holds the package.xml file which will determine which components should be retrieved from the source org.

3.) Configure your build.properties file


build.properties is a configuration file where you can configure your credentials for the source org and the destination org. Your build.properties file could look like this;


 # build.properties  
 #  
 # Specify the login credentials for the desired Salesforce organization  
 sf.username_source = <Insert your Salesforce username here>  
 sf.password_source = <Insert your Salesforce password here>  
 sf.username_dest = <Insert your Salesforce username here>  
 sf.password_dest = <Insert your Salesforce password here>  
 #sf.sessionId = <Insert your Salesforce session id here. Use this or username/password above. Cannot use both>  
 #sf.pkgName = <Insert comma separated package names to be retrieved>  
 #sf.zipFile = <Insert path of the zipfile to be retrieved>  
 #sf.metadataType = <Insert metadata type name for which listMetadata or bulkRetrieve operations are to be performed>  
 # Use 'https://login.salesforce.com' for production or developer edition (the default if not specified).  
 # Use 'https://test.salesforce.com for sandbox.  
 sf.serverurl = https://login.salesforce.com  
 sf.maxPoll = 20  
 # If your network requires an HTTP proxy, see http://ant.apache.org/manual/proxy.html for configuration.  
 #  


Don't forget that your password is a combination of your password and your security token. The next step is to

4.) Configure your build.xml file

The build.xml file is the most important file because it defines exactly what and how the files are to be moved from one org to another. e.g should we run test when deploying, should we validate or check before deploying, where on the local file system should the retrieve metadata be stored etc. Initially I always strip this file to the minimal amount of task that I need done and then add targets gradually as I progress through my deployments. For example, we will not need to run all test to deploy from one developer org to another. But if I were deploying say to a UAT (User Acceptance Test) Sandbox, it will be an excellent Idea to run all test and I will therefore need the appropriate task. I always keep my sample project around and update my build.xm file from there when I need to.

The reduced version of my build xml hast only three targets, retrieve, deploy and remove and looks like this;


 <project name="Sample usage of Salesforce Ant tasks" default="test" basedir="." xmlns:sf="antlib:com.salesforce">  
   <property file="build.properties"/>  
   <property environment="env"/>  
   <!-- Setting default value for username, password and session id properties to empty string   
      so unset values are treated as empty. Without this, ant expressions such as ${sf.username}  
      will be treated literally.  
   -->  
   <condition property="sf.username_source" value=""> <not> <isset property="sf.username_source"/> </not> </condition>  
   <condition property="sf.password_source" value=""> <not> <isset property="sf.password_source"/> </not> </condition>  
   <condition property="sf.username_dest" value=""> <not> <isset property="sf.username_dest"/> </not> </condition>  
   <condition property="sf.password_dest" value=""> <not> <isset property="sf.password_dest"/> </not> </condition>  
   <condition property="sf.sessionId" value=""> <not> <isset property="sf.sessionId"/> </not> </condition>  
   <taskdef resource="com/salesforce/antlib.xml" uri="antlib:com.salesforce">  
     <classpath>  
       <pathelement location="../ant-salesforce.jar" />           
     </classpath>  
   </taskdef>  
   <!-- Retrieve an unpackaged set of metadata from your org -->  
   <!-- The file unpackaged/package.xml lists what is to be retrieved -->  
   <target name="retrieve">  
    <mkdir dir="retrievedComponents"/>  
    <!-- Retrieve the contents into another directory -->  
    <sf:retrieve username="${sf.username_source}" password="${sf.password_source}" sessionId="${sf.sessionId}" serverurl="${sf.serverurl}" maxPoll="${sf.maxPoll}" retrieveTarget="retrievedComponents" unpackaged="retrieve/package.xml"/>  
   </target>  
   <!-- Deploy the unpackaged set of metadata retrieved with retrieveUnpackaged and run tests in this organization's namespace only-->  
   <target name="deploy">  
    <sf:deploy username="${sf.username_dest}" password="${sf.password_dest}" sessionId="${sf.sessionId}" serverurl="${sf.serverurl}" maxPoll="${sf.maxPoll}" deployRoot="retrievedComponents" rollbackOnError="true"/>  
   </target>  
   <!-- Shows removing code; only succeeds if done after deployCode -->  
   <target name="remove">  
    <sf:deploy username="${sf.username_dest}" password="${sf.password_dest}" sessionId="${sf.sessionId}" serverurl="${sf.serverurl}" maxPoll="${sf.maxPoll}" deployRoot="remove"/>  
   </target>  
 </project>  


The build.xml file is pretty straight forward. Let's briefly look at it's 3 target definitions;

retrieve


Retrieve sets the credentials of the source org. It also creates a directory called retrievedComponents and sets it as the retrieve target. The metadata from the source org will be retrieved and stored in this directory. We then tell the tool to use the package.xml file in the retrieve folder to determine what components to retrieve from the source org.

deploy


Deploy sets the credentials of the destination or target org. It then sets the attribute "deployRoot" to the directory "retrievedComponents" created in retrieve. Everything in this directory will be deployed to the target Org.

remove


Remove works in a slightly different way. Like the others we begin by setting the credentials of the target Org. Then we simply pass in the name of the directory that holds the destructiveChanges.xml file. This file specifies the components we want to delete. Notice that remove also has a package.xml file. This file does not define any metadata components but is required. If you run remove without it, you will get "Error: No package.xml found". More about remove and destructiveChanges.xm later.

We are now done with the setup of the migration tool. Let's look at how to prepare our package.xml file. So our next step is to

5.) Build package.xml


Change Sets


I normally use change sets to create my package.xml and I will show you how. For those who are completely new to Salesforce, change sets are used to deploy metadata from the Salesforce UI / setup from one org to another related org e.g. from a sandbox to a production org or another sandbox created from the same production instance.

Since we use change sets to deploy only between related orgs, change sets are not available in the developer org since this is a stand alone org that is not related to any other org. So, for this article we will build our change set manually.

But for the sake of completeness and for the benefit of those on a real org, I will outline the whole process here.

Create a change set by going to Setup -> Outbound Change Sets. Click on "New" and enter a name and description for your change set. The change set detail page should look like this after you save;



The  Change Set Components section lets you add the metadata components you will like to push from one org to another. Next we will use Workbench to extract the package.xml file.

Workbench


Workbench works with and supports most of the APIs on the Force.com platform. For more on the capabilities of workbench go to Workbench Documentation. It is a very handy tool that you will come to love in time if you take a serious look at it.

As a next step navigate to workbench . It is best to log in to the source org and then open this url on a separate tab on the same browser. This is the org that has the change set you want to retrieve. Choose the right environment; production or sandbox, agree to the terms and then log in.



Once logged in go to migration -> retrieve, then supply the name of you change set. Do not forget to check the Single Package option since we want to retrieve a directory with a single file in it - the package.xml file.




Then click on retrieve to start retrieving from the source org



When retrieve completes use the Download ZIP File link to download the retrieved file. The extracted file will have a single file - package.xml



Now that we have the package.xml file, let's move to the real deployment and


6.) Deploy to Target Org


I manually built my package.xml and it looks like this;



when building your package.xml file, use Metadata Types to see what Metadata can retrieved and deployed, if you can retrieve them by using a wildcard (*) and the entities and settings you can generally configure.

Open up your terminal and start the deployment process.

=> navigate to your deployment directory. For me it is by typing the following command,

          cd Desktop/salesforce_ant_37.0/Trailhead

=> view the contents of the build.xml file. In this way you will know that everything is set up correctly and you are ready to rock & roll. Use the command

          ant -p build.xml

=> next retrieve the components to be deployed

         ant retrieve




The tool first runs mkdir which creates the local directory retrievedComponents where the retrieve entities or components will be stored locally. Compare the contents of retrievedComponents with the entities and components defined in the package.xml, they match one to one.

=> finally deploy your changes by executing the deploy target

        ant deploy



You can now log into your target org and verify that all components were successfully deployed. And now you are done. Wasn't that straight forward? But wait a minute, what if you what to delete components? Null problemos ( by the way that is supposed to be spanish :-) )

Deleting Metadata Components


destructiveChanges.xml


One of the caveats of using Change Sets to deploy is that you cannot use them to remove components from the target org. You will have to delete them manually.

The Force.com Migration gives us a way to delete components from an Org using the destructiveChanges manifest. This file is set up exactly as our package.xml file and tells the tool what components to remove. The only difference is that you cannot use wildcards in the destructiveChanges.xml file, which makes total sense. The last thing you want is a careless developer who copies the CustomObject entity with a wildcard, puts it in a destructiveChanges.xml file and runs the remove target and KABOOM - all objects gone, just like that. This will probably cost you more than just your job. My destructiveChanges.xml Package looks like this;





You also need to add a package.xml file to the same folder in which the destructiveChanges.xml reside. In this case this is just a barebones package.xml file with no contents to deploy. It is however important because it specifies the API version that will be used for the deployment













Now you can delete the required components by running the remove target in the build.xml file

       ant remove




Look at your target org to confirm that your components were really deleted.

And now we are really done. Oh wait a moment ...


destructiveChangesPre.xml and destructiveChangesPost.xml


For the purpose of completeness let me briefly mention these two files. The Force.com Migration tool takes it a notch further and gives us the ability to control when deletion of components happen, i.e. either pre or post deployment. What this means is, we can deploy and delete in a single target. In this case the package.xml file will specify the components we want to deploy, the destructiveChangesPre.xml will specify the components to delete before deployment and the destructiveChangesPost.xml will then specify the components to delete after deployment.

So why would you want to do something like this? I bet you have seen this nasty little fellow before;


In such a situation, you could deploy some code that modifies the Apex class that uses the custom field you want to delete and then run the destructiveChangesPost.xml to perform the deletion. You will probably come along more use cases as you progress along your salesforce way.

And now we are really done. Oh wait a moment ... (I know this is getting really old :-) )


Limitations


Some of the metadata that can be created through Setup on the Salesforce Org isn't available on the Metadata API. So we cannot retrieve and deloy them using the Force.com Migration Tool, meaning we will have to make changes to these components manually. Please see the list here Unsupported Metadata Types - Metadata API Developer Guide. The list is pretty long.

Now we are really really done :-)

Conclusion


In this post we looked at how to set up and use the ANT based Force.com Migration Tool for deployments. When I started using the platform, I felt intimidated by the mention of this tool until I decided to take a closer look at it one day. Today it is my tool of choice. The purpose of this article was to demystify this tool and show you how straight forward and easy it is to use it. I hope I achieved this goal.

Please leave comments and feedback. I really do appreciate your questions and critique. Happy learning



Monday, September 12, 2016

Testing the Standard Controller

Introduction


Testing Standard Controllers is quite easy and straight forward and in this post I will show you how. For more information about Standard Controllers please read Visualforce Controllers - stay standard & extend? or go wild

Let's begin by looking at the Apex class and Visualforce we want to write a test for.

Apex Class - FinancialStatementControllerExt.cls


 public with sharing class FinancialStatementControllerExt {  
   public Financial_Statement__c financialStatement { get; set; }  
   public ApexPages.StandardController stdController { get; set; }  
   public FinancialStatementControllerExt(ApexPages.StandardController stdController){  
     this.financialStatement = (Financial_Statement__c)stdController.getRecord();  
     this.stdController = stdController;  
   }  
   public PageReference saveFinancialStatement(){  
     try {  
       if(this.financialStatement.Account__c == null)  
         this.financialStatement.Account__c = this.getDefaultAccountId();  
       insert this.financialStatement;  
       return new PageReference('/' + this.financialStatement.Id);  
     } catch(Exception e) {  
       ApexPages.addMessage(new ApexPages.Message(  
         ApexPages.Severity.Error,   
         'An error occurred while inserted a new financial statement record. Please contact your admin!')  
       );  
     }  
     return null;  
   }  
   public PageReference cancelOperation(){  
     return this.stdController.cancel();  
   }  
   private Id getDefaultAccountId(){  
     try {  
       return [SELECT Id FROM Account WHERE Name = 'Default Account' LIMIT 1].Id;  
     } catch (Exception e){  
       ApexPages.addMessage(new ApexPages.Message(  
         ApexPages.Severity.Error,   
         'An error occurred retrieving the default Account. Please contact your admin!')  
       );  
     }  
     return null;  
   }  
 }  


Visualforce - FinancialStatement.page



 <apex:page standardController="Financial_Statement__c"   
      extensions="FinancialStatementControllerExt" showHeader="true" sidebar="true">  
      <apex:form>  
           <apex:sectionHeader title="Create Financial Statement"   
                subtitle="New Financial Statement" rendered="{!Financial_Statement__c.Id == null}" />  
           <apex:sectionHeader title="Update Financial Statement"   
                subtitle="{!Financial_Statement__c.Name}" rendered="{!Financial_Statement__c.Id != null}" />  
           <apex:pageBlock title="Financial Statement">  
                <apex:pageBlockButtons location="top">  
                     <apex:commandButton value="Save" action="{!saveFinancialStatement}" />  
                     <apex:commandButton value="Cancel" action="{!cancelOperation}" />  
                </apex:pageBlockButtons>  
                <apex:pageBlockSection title="Enter a new Financial Statement">  
                     <apex:inputField value="{!Financial_Statement__c.Name}" />  
                     <apex:inputField value="{!Financial_Statement__c.Account__c}" />  
                </apex:pageBlockSection>  
           </apex:pageBlock>  
      </apex:form>  
 </apex:page>  


Test Class - FinancialStatementControllerExtTest.cls


So looking at the Visualforce and  Controller Extension above, what would you expect your test class to have?

  • The extension uses a Standard Controller for "Financial_Statement__c", so we will have to create that Standard Controller in the Test as well.
  • The extension makes use of a default account, so we need to create a default account
  • This also means we need to create at least two test cases, one for when a user enters an account and one for when the extension uses the default account
  • There are two try/catch blocks in the extension, one for the DML insert of a new financial statement and one for retrieving the default account. This means we have to write at least 2 negative test cases
  • There is a cancel operation going on in the controller as well. This means we need a test case for this operation too
  • And since we are testing a Visualforce page, we will need to reference this page in our test code
So I think that should be it. I haven't covered all these test cases in my test class. I have left out the negative test case for the insert of the financial statement and I haven't tested the cancel operation. Also the second positive test case where a user supplies the account to use for the financial statement is not covered. So 3 test methods are not written. This will be a nice exercise for you. Remember practice makes perfect. Currently the class has a coverage of 73%. I challenge you to raise it to 100% and add your additional test use cases to the comment.

So my test class looks like this;


 @isTest(SeeAllData=false)  
 private class FinancialStatementControllerExtTest {  
      private static User testUser;  
      private static Account defaultAcct;  
      private static Financial_Statement__c financialStatement;  
      private static ApexPages.StandardController stdController;  
      static {  
           testUser = TestDataFactory.createActiveUser();   
           /* Insert an account with the name 'Default Account' */  
           TestDataFactory.setFieldNameValuePairs('Name', 'Default Account');  
           defaultAcct = (Account)TestDataFactory.createSObject('Account');  
           //insert defaultAcct;  
           TestDataFactory.resetFieldNameValuePairs();  
           /* Create a financial statement and it's standard controller. Do not insert it yet */  
           financialStatement = new Financial_Statement__c();  
           stdController = new ApexPages.StandardController(financialStatement);  
      }  
      /* Inserting with no account, should create the Financial Statement with a default account */  
      @isTest static void test_insertWithNoAccount() {  
           insert defaultAcct;  
           FinancialStatementControllerExt fsControllerExt;  
           PageReference pageRef;  
           PageReference returnPage;  
           Test.startTest();  
                System.runAs(testUser){  
                     pageRef = Page.FinancialStatement;  
                     Test.setCurrentPage(pageRef);  
                     fsControllerExt = new FinancialStatementControllerExt(stdController);  
                     returnPage = fsControllerExt.saveFinancialStatement();  
                }  
           Test.stopTest();  
           Financial_Statement__c insertedFinancialStatement = [  
                SELECT Id, Name, Account__c   
                FROM Financial_Statement__c   
                WHERE Id = :fsControllerExt.financialStatement.Id LIMIT 1  
           ];  
           System.assertNotEquals(null, returnPage, 'Pagereference is null, therefore Financial Statement was not created');  
           System.assertEquals('/' + insertedFinancialStatement.Id, returnPage.getUrl(),   
                'Pagereference return url is wrong, therefore Financial Statement was not created');  
           System.assertEquals(defaultAcct.Id, insertedFinancialStatement.Account__c,   
                'The default Acct was not attached to the inserted financial statement');  
      }  
      @isTest static void test_insertNegativeTestCase() {  
           FinancialStatementControllerExt fsControllerExt;  
           PageReference pageRef;  
           PageReference returnPage;  
           Boolean errorOccurred = false;  
           Test.startTest();  
                System.runAs(testUser){  
                     pageRef = Page.FinancialStatement;  
                     Test.setCurrentPage(pageRef);  
                     fsControllerExt = new FinancialStatementControllerExt(stdController);  
                     returnPage = fsControllerExt.saveFinancialStatement();  
                }  
           Test.stopTest();  
           List<ApexPages.Message> msgs = ApexPages.getMessages();  
           for(ApexPages.Message msg : msgs){  
                if(msg.getDetail().contains('An error occurred retrieving the default Account. Please contact your admin!'))  
                errorOccurred = true;  
           }  
           Financial_Statement__c insertedFinancialStatement = [  
                SELECT Id, Name, Account__c   
                FROM Financial_Statement__c   
                WHERE Id = :fsControllerExt.financialStatement.Id LIMIT 1  
           ];  
           System.assert(errorOccurred,   
                'Due to the missing default account, an exception should have be caught and handled. This is not the case!');  
           System.assertEquals(null, insertedFinancialStatement.Account__c,   
                'The Account__c should be null because no default account was created');  
      }  
 }  


Notice that I use a TestDataFactory to create my test data. How to create such a test data factory, is a topic for an entire blog that I will tackle in the future.

First create the test data that you need, which in this case is a test user, a default account, a financial statement and a Standard Controller for the financial statement. The default account and financial statements are not inserted yet. The financial statement will be inserted as part of the test.

The first test case test_insertWithNoAccount begins by inserting the default account so that it is available to the controller extension when creating the account. This first step is missing from the negative test case and causes the exception in the getDefaultAccountId() in the controller exception to be thrown

For both test cases, we set the current page to FinancialStatement which is the page we are testing. We then create an instance of the controller extension by calling it's constructor and passing it the Standard Controller for the financial statement record.

In the test_insertWithNoAccount test case, we call the saveFinancialStatement() method and then assert that the page will be properly redirected to the detail page of the newly created financial statement. We also assert that the default account was attached to the financial statement.

In the negative test case test_insertNegativeTestCase we assert that the Financial Statement was created with no account because a default account does not exist. We also assert that the right error message was added to the page.

Best Practices


  1. Always create test data for your test. Tests should not depend on the environment in which they run, period.
  2. Your test cases should be complete and independent of other test cases. Concretely the results on one test should not depend on the results of another test
  3. Write positive as well as negative test. Depending on how tricky your use case it, writing test classes to assert negative or unwanted behaviour can be challenging and many developers just comfortably skip them, BAD
  4. Use Test.start() and Test.stop() methods to run your test. Code between these two methods runs with governor limits reset. So you get a clearer picture of how your code is doing against those nasty little limits
  5. Always use System.runAs() to test your code within the context of a specific user. This is especially important for security and data access test as you can confirm that Users have access to the data they need and others don't have access to data they do not need
  6. This is the last and most important one and if you haven't been doing this and do not change immediately, you have no business writing Apex code. ASSERT expected behaviour. Very important. Assert the logic in your code and do not write test classes just to gain coverage. Way too often, I have seen controller test classes that have a single method which just calls all the methods in the controller without a single assert. If you keep doing this, one day the Lord of Apex might strike you down. NO  guys, on a serious note, make it a habit to assert your code. It might one day literally save your life by helping you catch some very nasty bugs that would otherwise be very costly

Conclusion


We have looked at the best way to test Standard controllers and have discussed aspects that will normally affect such test. We concluded by looking at best practices that I have also included in my code example. They apply to writing test code in general and not just test for Standard controllers. Please take these best practices to heart, own them and live them. Practice makes perfect. Also try to complete the test class above and raise it's coverage to 100%. Reach out if you need my assistance.

As usual it is always a pleasure to share my knowledge and I appreciate your feedback, questions and critique

Visualforce Controllers - stay standard & extend? or go wild

Introduction

More than once I have seen a lot of people use the wrong controller more than once. At the beginning of my Apex days, it wasn't quite clear what exactly controllers were and when I should use them. So this post is for all new to Apex & Visualforce and those who might have already been programming in Apex but still get confused when making the decision about what controller to use. So let's begin by briefly answering the question, what is a contoller?

What is a VF Controller?


Simply put a VF Controller is a class that contains a bunch of methods and properties used to control the data, navigation and actions that can be performed on a Visualforce or Standard detail record page. Example of data includes for example what fields of a particular record are retrieved and shown on the UI. An example of navigation could be a User clicking on a link of a related record which opens this record on a new page or tab. And finally an example of an action could be a user clicking on an edit button of a standard detail page. 

There are 2 types of controllers; Standard Controller and a Custom Controller. Both Controllers can be extended by what we called Controller Extensions.

Standard Controller


Every time we create a new custom object, Salesforce creates a corresponding class for that object. That class determines what we see when we look at records of that object from the standard salesforce UI, also called the record detail page. It also  determines what happens when we perform an action, say click on edit, delete, clone or even on the new button when looking at a list view for that particular object. But this is not limited to objects we create. Standard Salesforce objects also have standard controllers. As an example, look at the standard detail page of a contact;





The information displayed here and the actions which take place when the buttons are clicked is controlled by the Standard Controller for Contact. The Standard Controller is always the name of the object.

In order to access the Standard Controller in Apex, we have to create a Visualforce page. This leads us to the next question, when exactly should we use a Standard Controller?

When to use a Standard Controller


Use a standard controller when you need to override the standard buttons for an object. The standard buttons you can override include New, View, Edit, Delete, Clone and Accept. Overriding any of these buttons will make sure that a Visualforce page which uses the Standard Controller is called when the overriden button is clicked and not the Standard Salesforce page for that particular button. Note that you have to override these buttons individually. This makes the ability to override standard pages very powerful because you can implement different functionality on a different page for each button. I have seen this feature abused quite a lot and therefore a word of caution, don't do something just because you can. The standard buttons will be enough in most situations and if extra functionality is really required, please think about adding a Visualforce section onto the page layout for an object rather than immediate overriding the "View" button and rebuilding the whole page. An example of such a situation can be when you need to retrieve data from an external System and show it on the record detail. Here you will also need to use the Standard Controller of the object whose record detail page is to be extended with the Visualforce section.

Before we look at an example, let's talk about controller extensions.

Extensions


The Standard Controller is a brilliant concept and coupled together with other Salesforce features such as field dependencies, record types, page layouts etc. it is enough in most situations and no additional code is required. However there are times when the functionality of the Standard Controller needs to be extended. This is when we use an extension and then put the custom functionality in the extension. The extension is simply an Apex class. In this class, we have access to the standard controller and all it's methods. Very important to note, although there can only be a single controller on a page, many extensions can be attached to the page.

Now let us look at an example;


 <apex:page standardController="Financial_Statement__c"   
      extensions="FinancialStatementControllerExt" showHeader="true" sidebar="true">  
      <apex:form>  
           <apex:sectionHeader title="Create Financial Statement"   
                subtitle="New Financial Statement" rendered="{!Financial_Statement__c.Id == null}" />  
           <apex:sectionHeader title="Update Financial Statement"   
                subtitle="{!Financial_Statement__c.Name}" rendered="{!Financial_Statement__c.Id != null}" />  
           <apex:pageBlock title="Financial Statement">  
                <apex:pageBlockButtons location="top">  
                     <apex:commandButton value="Save" action="{!saveFinancialStatement}" />  
                     <apex:commandButton value="Cancel" action="{!cancelOperation}" />  
                </apex:pageBlockButtons>  
                <apex:pageBlockSection title="Enter a new Financial Statement">  
                     <apex:inputField value="{!Financial_Statement__c.Name}" />  
                     <apex:inputField value="{!Financial_Statement__c.Account__c}" />  
                </apex:pageBlockSection>  
           </apex:pageBlock>  
      </apex:form>  
 </apex:page>  


Looking at this page, it is clear that this is a page used to override one of the standard buttons for an object called "Financial_Statement__c" or create a visualforce page to be added to the record detail page for Financial_Statement__c records. This means whenever a user clicks on that button for a particular record, the record or at least it's Id will be passed to this page. Because we are using the Standard Controller, we have direct access to the fields on the record e.g. through the expression "{!Financial_Statement__c.Name}.

Also notice that the page definition tag has an "extensions" attribute. Notice the "s" in extensions. More than 1 extension can be added to a single page. The extension "FinancialStatementControllerExt"  is used to add more functionality. For instance the "Save" and "Cancel" buttons do not call the save and cancel actions which exists in the Standard Controller but the "saveFinancialStatement" and "cancelOperation" actions which exists in the controller extension.

 public with sharing class FinancialStatementControllerExt {  
   public Financial_Statement__c financialStatement { get; set; }  
   public ApexPages.StandardController stdController { get; set; }  
   public FinancialStatementControllerExt(ApexPages.StandardController stdController){  
     this.financialStatement = (Financial_Statement__c)stdController.getRecord();  
     this.stdController = stdController;  
   }  
   public PageReference saveFinancialStatement(){  
     try {  
       if(this.financialStatement.Account__c == null)  
         this.financialStatement.Account__c = this.getDefaultAccountId();  
       insert this.financialStatement;  
       return new PageReference('/' + this.financialStatement.Id);  
     } catch(Exception e) {  
       ApexPages.addMessage(new ApexPages.Message(  
         ApexPages.Severity.Error,   
         'An error occurred while inserted a new financial statement record. Please contact your admin!')  
       );  
     }  
     return null;  
   }  
   public PageReference cancelOperation(){  
     return this.stdController.cancel();  
   }  
   private Id getDefaultAccountId(){  
     try {  
       return [SELECT Id FROM Account WHERE Name = 'Default Account' LIMIT 1].Id;  
     } catch (Exception e){  
       ApexPages.addMessage(new ApexPages.Message(  
         ApexPages.Severity.Error,   
         'An error occurred retrieving the default Account. Please contact your admin!')  
       );  
     }  
     return null;  
   }  
 }  

Notice that the cancel button "cancelOperation()" calls the standard controller "cancel()" method.

We can get access to the current record in our controller extension by using the methods defined in the Standard Controller. To get access to the Standard Controller, we have to write a constructor which will be passed an instance of the Standard Controller when the extension is initialised. The Standard Controller method getRecord() returns the current record. It is very important to note that only fields already referenced on the Visualforce page will be available in the controller extension, in our example only "Name" and "Account__c". So what do we do if we want to use fields in the controller extension, that do not necessarily need to be visible on the UI? There are basically two ways to do this that I have come across;

  1. Use hidden components on the page and reference the additional fields in those components. The hidden component to used is the "<apex:hiddenInput value="{!Financial_Statement__c.SomeValue}" />" whose value attribute binds the referenced value to the controller extension such that it is retrieved and available in the controller extension when "getRecord()" method of the Standard Controller is called.
  2. The second method is another Standard Controller method, "addFields(fieldList)"

Add Fields - addFields()


We can use the Standard Controller method "addFields(fieldList)" to add fields that should be retrieved together with fields referenced on the page when "getRecord()" is called. For example, the constructor which retrieves the record data would like look like this;

   public FinancialStatementControllerExt(ApexPages.StandardController stdController){  
     stdController.addFields(new List<String>{'fieldName1__c', 'fieldName2__c'});  
     this.financialStatement = (Financial_Statement__c)stdController.getRecord();  
     this.stdController = stdController;  
   }  

Notice that "addFields(fieldList)" is called before getRecords(), logical right?

I personally do not like hidden fields because I dislike the idea that someone can view the source of my page and get his hands on information, I may not want to expose, so I generally prefer using "addFields(fieldList)". The problem with "addFields(fieldList)" method is that it is not testable. Take a look at this idea StandardController AddFields method should be testable on the ideaExchange to learn more. You can see that the idea was created 5 years ago meaning others have lived with it for this long and so will you. Doesn't seem to be a priority to Salesforce to fix this. So what do you do? You will have to workaround this by making sure that "addFields(fieldList)" does not run if you are in a text class. Our constructor now looks like this; 

   public FinancialStatementControllerExt(ApexPages.StandardController stdController){  
     if (!Test.isRunningTest())  
        stdController.addFields(new List<String>{'fieldName1__c', 'fieldName2__c'});  
     }  
     this.financialStatement = (Financial_Statement__c)stdController.getRecord();  
     this.stdController = stdController;  
   }  


Depending on what you are testing, you might have to carefully craft your test class to avoid errors and to achieve the required coverage for the controller extension.

Also note that controller extensions can also be used to extend custom controllers. All you need to do in your extension is to provide a constructor which takes the custom controller you are extending as a parameter. This is similar to the constructor in our example above which takes the Standard Controller it is extending as a parameter.

Now that we have looked at the Standard Controller and controller extensions, let's briefly talked about Custom Controllers

Custom Controllers


These are classes that are not attached to any specific object the way Standard Controllers are. They are more like extensions in that they implement custom functionality that is available to the Visualforce page that uses them. So when should we use custom controllers?

When to use a Custom Controller?


A custom controller is mostly used when we need to expose a piece of functionality using Visualforce Tabs, custom buttons, and links. To stay with out Financial Statement example, let us create a custom button and add it to the Account detail page. This button should open a Visualforce page that can be used to create a financial statement record directly from the account. Here is the custom controller code;


 public with sharing class FinancialStatementController {  
      public String accountId { get; set; }  
      private String accountName { get; set; }  
      public Financial_Statement__c financialStatement { get; set; }  
      public FinancialStatementController() {  
           this.accountId = ApexPages.currentPage().getParameters().get('id');  
           this.accountName = ApexPages.currentPage().getParameters().get('name');  
           this.financialStatement = new Financial_Statement__c();  
           if(String.isNotBlank(this.accountId))   
                this.financialStatement.Account__c = this.accountId;  
           if(String.isNotBlank(this.accountName))   
                this.financialStatement.Name = this.accountName + ' FS';  
      }  
      public PageReference save(){  
           try {  
                insert this.financialStatement;  
                return new PageReference('/' + this.accountId);  
           } catch(Exception e){  
                ApexPages.addMessage(new ApexPages.Message(  
                     ApexPages.Severity.Error,  
                     'An error occurred while creating the Financial Statement. Please contact your admin!'  
                     )  
                );  
           }  
           return null;  
      }  
      public PageReference cancel(){  
           PageReference acctPage = new PageReference('/' + this.accountId);  
           acctPage.setRedirect(true);  
           return acctPage;  
      }  
 }  

And the page looks like this;


 <apex:page controller="FinancialStatementController" showHeader="true" sidebar="true" tabStyle="Account">  
      <apex:form>  
           <apex:pageBlock title="Create a new Financial Statement">  
                <apex:pageBlockButtons location="top">  
                     <apex:commandButton value="Save" action="{!save}" />  
                     <apex:commandButton value="Cancel" action="{!cancel}" />  
                </apex:pageBlockButtons>  
                <apex:pageBlockSection title="Enter Financial Statement details for {!financialStatement.Name}">  
                     <apex:inputField value="{!financialStatement.Name}" />  
                     <apex:outputField value="{!financialStatement.Account__c}" />  
                </apex:pageBlockSection>  
           </apex:pageBlock>  
      </apex:form>  
 </apex:page>  


For those of you who are completely new to Salesforce, you can create a custom button on account by navigating Setup -> Customize -> Accounts -> Buttons, Links, and actions and then clicking on "New Button or Link" button. You can then enter the details as shown below




Notice that we use URL as the content source for our link. We then call our Visualforce page and pass it parameters. We could also select Visualforce directly as the content source and then select our Visualforce page. If we do it this way, we will have no way of getting the Account Id to which the created Financial Statement should be attached. That is why we choose a link here, because it is of upmost importance to pass at the least the account Id. In some situations that we do not need to pass parameters and do not want to expose data in a URL, choosing Visualforce as a data type will be the appropriate choice here.

Please don't forget to add the button to the page layout by navigating to Setup -> Customize -> Accounts -> Page Layouts and editing the page. Click "Buttons" on the left panel on the fixed header, then drag and drop the "Create Financial Statement" button from the right panel onto the "Custom Buttons" section at the top of the Account Detail info.

If you click on the "Create Financial Statement" button on the account detail the following Visualforce page opens up.



You will notice that although we came from an account detail, the Financial Statement Tab is automatically selected. Well not really automatically. This happens because we set the tabStyle attribute on the "apex:page" component to "Financial_Statement__c" when defining our Visualforce page

Also notice that the account is read-only and also a hyperlink. This is because we used a "apex:outputField" component for the "Account__c" field. Also notice that the name defaults to the account name concatenated with "FS". This is exactly as defined in the custom controller.

Security & Data Access - With Sharing / Without Sharing

It is important to note that all Apex code always executes in System mode meaning that sharing is not applied. Eventhough Visualforce always enforces sharing such that Users wouldn't see Data they are not entitled to see, they would still be able to create records they are not allowed to create. For this reason, it is important to use the keywords "with sharing" in controller and controller extensions to make sure that sharing is applied and the Apex code runs within the context of the current user.

To know more about the dos and don'ts and how to correctly apply "with" & "without" sharing please read my blodpost Apex Sharing - "with sharing" & "without sharing"

Conclusion


As a recap, we have learned about the Standard Controller, controller extensions and the Custom Controller.

We learned that each object in Salesforce, be it Standard or Custom has a Standard Controller which controls the look & feel and functionality of the standard detail pages. We also learned that we could modify or customise this functionality by using extensions. In this case we could use Standard Controllers together with extensions to override standard buttons such as New, View, Edit etc. and to create Visualforce pages that can be added as sections to the standard detail record page.

Extensions can also be used to extend the functionality of custom controllers.

We also learned that we can use custom controllers to build stand-alone functionality for custom Visualforce tabs, buttons & links. The functionality behind this tabs, buttons and links is limited only by your use case and imagination. We looked at an example of how to create a Visualforce button for accounts.

I hope that you have understood when and how to use the different controller types after reading this blogpost. If not ask a questions in the comments and I will get back to you soon. Also take a look at the additional links below. As always I appreciate your feedback and critique, so don't be shy to leave a comment. Thanks for reading and lots of fun with learning salesforce.

Additional Links


Sunday, September 11, 2016

Apex Sharing - "with sharing" & "without sharing"

Introduction


I have come across many developers who use "with sharing" and "without sharing" without actually knowing what it really means. So if you are new to Apex, it is good to start using it right, right from day one. And if you are a veteran who just writes "with sharing" in all classes you create without knowing why, please do read further.

System vs User mode


To understand what the keywords "with sharing" and "without sharing" really mean, it is important to understand the difference between Apex code execution in system mode as opposed to the user mode.

In System mode, Apex code is executed with all sharing ignored. This means queries will retrieve data for which the current / running user has no access. Also in the system mode, other security features such as FLS (Field Level Security) and object permissions are ignored meaning users will see fields in retrieved records which are supposed to be hidden e.g. customer social security numbers, sales rep performance scores etc.

In the user mode, all sharing rules that apply to the current user, be it from role hierarchy, OWD (Org Wide Defaults), Sharing rules, Manual Sharing are applied. Field Level Security and object access permissions are also respected.

System mode is always the default when running Apex code. That is why we need the "with sharing" and "without sharing" mechanism to control access to data when executing Apex code.

With Sharing


This is what the documentation says about with sharing:

     "The with sharing keyword allows you to specify that the sharing rules for the current user be taken into account for a class."

Do you see how it fails to say anything about object permissions and Field Level Security (FLS). My assumption will be that, "with sharing" really only affects sharing and not object permissions and FLS. But to be sure, let's find out for ourselves in the section below, so keep reading.

Does with sharing respect Field Level Security?


In this small experiment, I have created an Object called Financial_Statement__c. This object has a  lookup to the account object Account__c. I have also created a user and given him CRUD ( create, read, update & delete ) rights to the Financial_Statement__c object but no access to the Account__c field. His profile looks like this;



Next I have the following Visualforce page and Controller Extension that create the Financial Statement records;

 public with sharing class FinancialStatementControllerExt {  
   public Financial_Statement__c financialStatement { get; set; }  
   public ApexPages.StandardController stdController { get; set; }  
   public FinancialStatementControllerExt(ApexPages.StandardController stdController){  
     this.financialStatement = (Financial_Statement__c)stdController.getRecord();  
     this.stdController = stdController;  
   }  
   public PageReference saveFinancialStatement(){  
     try {  
       if(this.financialStatement.Account__c == null)  
         this.financialStatement.Account__c = this.getDefaultAccountId();  
       insert this.financialStatement;  
       return new PageReference('/' + this.financialStatement.Id);  
     } catch(Exception e) {  
       ApexPages.addMessage(new ApexPages.Message(  
         ApexPages.Severity.Error,   
         'An error occurred while inserted a new financial statement record. Please contact your admin!')  
       );  
     }  
     return null;  
   }  
   public PageReference cancelOperation(){  
     return this.stdController.cancel();  
   }  
   private Id getDefaultAccountId(){  
     try {  
       return [SELECT Id FROM Account WHERE Name = 'Default Account' LIMIT 1].Id;  
     } catch (Exception e){  
       ApexPages.addMessage(new ApexPages.Message(  
         ApexPages.Severity.Error,   
         'An error occurred retrieving the default Account. Please contact your admin!')  
       );  
     }  
     return null;  
   }  
 }  



 <apex:page standardController="Financial_Statement__c"   
      extensions="FinancialStatementControllerExt" showHeader="true" sidebar="true">  
      <apex:form>  
           <apex:sectionHeader title="Create Financial Statement"   
                subtitle="New Financial Statement" rendered="{!Financial_Statement__c.Id == null}" />  
           <apex:sectionHeader title="Update Financial Statement"   
                subtitle="{!Financial_Statement__c.Name}" rendered="{!Financial_Statement__c.Id != null}" />  
           <apex:pageBlock title="Financial Statement">  
                <apex:pageBlockButtons location="top">  
                     <apex:commandButton value="Save" action="{!saveFinancialStatement}" />  
                     <apex:commandButton value="Cancel" action="{!cancelOperation}" />  
                </apex:pageBlockButtons>  
                <apex:pageBlockSection title="Enter a new Financial Statement">  
                     <apex:inputField value="{!Financial_Statement__c.Name}" />  
                     <apex:inputField value="{!Financial_Statement__c.Account__c}" />  
                </apex:pageBlockSection>  
           </apex:pageBlock>  
      </apex:form>  
 </apex:page>  


And here are the results;








You will notice that the results are the same. If I declared the class with "with sharing" or without  "with sharing", the results are the same, the Default account is attached to the Financial Statement even though the test user has no access to this field i.e. his access is blocked by FLS. This is confirmed by looking at the UI. The test user does not see the input field for the account field. If he had FLS for this field, the UI would look like this;



This is because Visualforce always enforces Sharing and FLS even if the APEX Controller doesn't.

So with can safely assume that "with sharing" only controls sharing of records as established by the different sharing models we have on the platform namely; OWDs (Organization-wide Defaults ), Role Hierarchy, Sharing Rules and Manual Sharing.

With Sharing & Controller Extensions


The other day a colleague asked me if he should also use "with sharing" in a controller extension. The reason he asked this question is simple, logic in the standard controller will always execute in the "user context" meaning sharing, FLS and object permissions will be respected. So if this is the case, if we extend the standard controller using an extension, do we still need the "with sharing" keyword?

The answer is YES. This is what the documentation says;

      If a controller extension extends a standard controller, the logic from the standard controller doesn’t execute in system mode. Instead, it executes in user mode, in which the permissions, field-level security, and sharing rules of the current user apply.

Notice it says logic in the standard controller doesn't execute in system mode. For example if you call the save() method of the standard controller, it will execute in user mode. Whereas if we had our own save method in the extension such as saveFinancialStatement() in the example above, it will respect whatever context we have chosen for the extension to run in, user context if we have used "with sharing" or system context if we have left it out or explicitly defined "without sharing".

Without Sharing


Without sharing simple means that Apex code will run in system mode i.e. no sharing rules will be respected. But this is the default right? meaning if we do not declare a class with "with sharing" or "without sharing", it will run in system mode. So why should we even bother declaring a class with "without sharing"?
Simply because a class can inherit "with sharing" from another class that calls it. We might however want the class that is called to still execute in system mode despite being called by a class that has "with sharing" and is executing in user mode.

Sharing Setting in Triggers


I haven't found this documented anywhere but it has been my experience, that triggers always run in System mode i.e. it doesn't matter if you use the "with sharing" keyword in the Trigger handler class or not.

To test this, I have created an a Trigger on Account, that creates a Financial Statement record every time an account is inserted. A financial statement was created every time, even when the test user had "no Access" on his profile for the Financial_Statement__c object. Here is my code snippet;

 trigger AccountTrigger on Account (after insert) {  
      if(Trigger.isAfter){  
           AccountTriggerHandler.createFinancialStatement(Trigger.new);  
      }  
 }  


 public with sharing class AccountTriggerHandler {  
      public static void createFinancialStatement(List<Account> accounts){  
           List<Financial_Statement__c> financialStatements = new List<Financial_Statement__c>();  
           for(Account acct : accounts){  
                financialStatements.add(new Financial_Statement__c(Name = acct.Name + '_FS', Account__c = acct.Id));  
           }  
           if(!financialStatements.isEmpty()){  
                try {  
                     insert financialStatements;  
                } catch(Exception e){  
                     accounts[0].addError('An error occurred while attaching a Financial Statement to an Account');  
                }  
           }  
      }  
 }  

This blogpost A Common Myth : Triggers “always” play in GOD Mode (System Context) ! explains situations in which an Apex Trigger will not run in System mode. I haven't tried to reproduce it but may be you can take it upon yourself to do this.

Gotchas


We have already mention two gotchas above, but i will repeat them here for the sake of completenes

  1. As with the case of the Standard Controller and controller extension, if a class runs in user mode ( has with sharing ), all methods of this class will execute in user mode even if they are called from a class running in system mode
  2. The second gotcha has to do with the importance of "without sharing" as described above. If a class has "with sharing" and calls a method of class which is not declared with either "with" or "without" sharing, that method will execute in the context of the calling class, i.e user context
  3. Inner classes do not inherit the context of the outer class
  4. When classes extend or implement other classes they inherit their sharing setting

Conclusion


The keywords "with sharing" and "without sharing" are very important because of the security and Data Access implications they have. So when designing your code, do not fail to give careful thought to these keywords and make sure that they are aligned with the general security and data access strategy of the whole org.

As usual it is always a pleasure sharing my knowledge with you. I appreciate you feedback, questions and critique. So do not be shy to leave a comment Thanks for reading.

Friday, September 9, 2016

Salesforce Custom Metadata Types - Application Configuration Magic

Introduction


Metadata is data about data, .i.e. it is data that describes data. An account for instance, can be described by its name, location, number of employees, annual revenue etc. This is information that describes an account in general.

As of Summer release 15, Salesforce has given us a way to be able to create our own custom metadata type. Now why would you want to do this? One reason alone is very compelling. So you can stop putting application configuration data in custom objects or list custom settings, both of which have the huge limitation that you can't deploy or package them. With Custom metadata types, you can deploy the records you create from them as part of meta data. Yes you heard that right. Custom Metadata Type definition and records can be packaged and deployed as part of metadata.

So Custom Metadata Types are truly a special kind of metadata because similar to custom objects, they can have fields which describe records created as part of the Custom Metadata Type. These fields constitute metadata and will be deployed. But the cool part is the data or records created from the Custom Metadata Type Definitions are also considered as meta data and will be deployed as well. No need for manual error prone and expensive processes for transferring these records from one sandbox to another or to prod. This covers the customisable and  deployable advantages of Custom Metadata Types.

Another advantage that is more relevant to ISVs ( Independent Software Vendors) is that Custom Metadata Types are packageable and upgradeable. Normally with application configuration data in custom settings of custom objects, ISVs will have to run complicated post install scripts to create configuration records on their customers orgs. NO MORE
Another advantage depending on how you look at it, is the ISV's ability to create his metadata types as protected, meaning they are locked and can't be modified by customers downloading the package.

Let us look at an example of how to create a custom metadata type.

Example


Use case 


Build an email editor whose look and feel is customisable by region of running user. Regions are AMER, EMEA, LATAM, APAC.

Solution 


1.)  create an object ( metadata definition ) for our custom metadata type by going to Setup -> Develop -> Custom Metadata Types. Click on New Custom Metadata Type



Note the radio button "" An ISV can choose to limit the access of the custom metadata type only to the managed package, meaning the user who installs the package or any other code in his org will not be able to see and use this custom metadata type.

Add a few fields to the object you just created to define what aspects of the editor you will like to customise. Could look something like this;



Now click on "Manage Email Editor Configuration" to add records for the different regions. Remember that the beauty of Custom Metada Types lies in the fact that the object definition and the records are deployable and packageable.

Custom Metadata Types also have layouts that you can customise like normal custom object page layouts;




If you are creating records manually, use the clone button. Will save you tons of time especially if the configuration records differ only minimally from region to region


Protected

Notice that you can also set the records as protected. This simply means that only code that is in the same managed package as the protected record or the Custom Metadata Type to which the protected record belongs can see and use the record. Only developers of the managed package can modify the protected record and they can only do this with a package upgrade

Your final records could look something like this;


Now you have created your Custom Metadata Types, including configurations for the 4 different regions and can now access these configurations in APEX. 


APEX Access


Unfortunately APEX access is as of this writing Read-Only. But despite this fact, Custom Metadata Types are already incredible powerful. Here is how we would get out Email Editor Configuration Data and use it to customise our email editor look and feel;

 List<Email_Editor_Configuration__mdt> configuration = [  
    SELECT   
      Allow_Attachments__c, Allow_Document_Upload__c, Allow_Template_Use__c,   
      Default_Email_Folder__c, Editor_Height__c, Editor_Width__c, Region__c,   
      Save_As_Activity__c   
    FROM Focus_Product_Setting__mdt  
 ];  

Notice the "__mdt" ending for metadata type just we have "__c" for custom and "__r" for relationship.

Limitations


=> Number of fields that can be created for a custom meta data type definition are limited. See the following link for custom field types that are supported by custom metadata types Help & Training - Custom Metadata Types

= > Custom metadata types are still read-only as of this writing. Please vote here so we can see a change in this fast - Ability to update Metadata from Apex (Apex Metadata API)

Conclusion


Custom metadata types to me are pure magic because they can save us tons of hours and effort when building large customisable blocks of enterprise software or apps. I hope I was able to wet your appetite a little. I encourage you to take a look at Custom Metadata types. When you actually get to use them in real world projects, you will be blown away, positively of course. This I assure you.

For more on Custom Metadata Types go to Custom Metadata Types (CustomObject).

Please do not be shy to leave a comment. I appreciate your feedback, hints and critique.

The Fixer