[SalesForce] Retrieve Folder Metadata using Metadata API (File based)

We are trying to retrieve zip file of metadata in Salesforce. After trying in several ways we are able to get the metadata in a zip file but, it only has "package.xml" not the folder detail file as explained in http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_folder.htm

<?xml version="1.0" encoding="UTF-8"?>
<DocumentFolder xmlns="http://soap.sforce.com/2006/04/metadata">
    <accessType>Public</accessType>
    <name>sampleFolder</name>
    <publicFolderAccess>ReadWrite</publicFolderAccess>
</DocumentFolder>

This above xml we can not get.

We are querying this way:

//Query Code

String session = 'session';
String instance = 'https://na17.salesforce.com';
MetadataService.MetadataPort service = MetadataUtils.createService(session, instance);
List<MetadataService.ListMetadataQuery> queries = new List<MetadataService.ListMetadataQuery>();
MetadataService.ListMetadataQuery queryLayout = new MetadataService.ListMetadataQuery();

queryLayout.folder = '';
queryLayout.type_x = 'DocumentFolder';

queries.add(queryLayout);
// return all folders name in xml
MetadataService.FileProperties[] fileProperties = new List<MetadataService.FileProperties>();

// query metadata items by callout
fileProperties = service.listMetadata(queries, '30.0');

Here we get all folder names.

Retrieval method. It is not working for folders:

// But we are getting a zip file with "package.xml" only. It must have other files also.
for(MetadataService.FileProperties fileinfo :fileProperties)
{
    // insert all folder names received in above query ex: Test_Document_Folder
    li.add(fileinfo.fullname);
}
typeAndItemMap.put('DocumentFolder',li);

// Creating AsyncResult by callout. Insert all type names in list to retrieve
MetadataService.AsyncResult asyncResult = MetadataUtils.retrieveMetadataItem(types, session, instance);
String asyncId;
if(asyncResult.Id != null)
{
 asyncId = asyncResult.Id;
}

Folder retrieval is listed in metadata type but not getting retrieved. Only "package.xml" is received.

Update: Here is the way to retrieve folder-meta.xml but it doesn't return document file.

Map<String,List<String>> typeAndItemMap = new Map<String,List<String>>();
List<String> li = new List<String>();
// Set up Document file retrieve
li.add('Test/AnyFile.txt');
typeAndItemMap.put('Document',li);

// clear the list to add folder to retrieve
li.clear();
// Add folder
li.add('My_Folder');

// combine folder and document to retrieve at once
typeAndItemMap.put('DocumentFolder',li);
MetadataService.AsyncResult asyncResult = MetadataUtils.retrieveMetadataItem(typeAndItemMap, session, instance);
if(asyncResult.Id != null)
{
  System.debug('asyncResult.Id------:'+asyncResult.Id);
}

Any help will be appreciated.

Best Answer

Folders are strange things indeed, there are four types of folders, document, email, report and dashboard, they do not exist as a physical Metadata Type, hence you don't see them listed here. Most of the time they don't work like regular Metadata components with the rest of the API either. The Folder documentation also further hints at their slightly 'special' nature!

Folders are stored in the corresponding component directory of the package. These directories are named documents, email, reports, and dashboards. Folders do not have a text file representation—they are containers for files. For each folder, an accompanying metadata file named FolderName-meta.xml is created at the same directory level. The FolderName-meta.xml metadata file contains the metadata information for that folder, such as the accessType. For example, for a documents folder named sampleFolder, there’s a sampleFolder-meta.xml within the documents folder of the package.

You cannot retrieve just the folder itself with the Metadata API retrieve operation, you have to request at least one file for it to create the folder and the associated metadata XML file for the folder. In my testing just now i can see that you can effectively put anything you like as the type when using retrieve and it just ignores (unlike other operations that throw errors) invalid ones, most misleading!

Fortunately you can use the latest readMetadata operation combined with the listMetadata to retrieve them instead! Here is an example using the Apex Metadata API to do just that...

MetadataService.MetadataPort service = new MetadataService.MetadataPort();
List<MetadataService.ListMetadataQuery> queries = new List<MetadataService.ListMetadataQuery>();
service.SessionHeader = new MetadataService.SessionHeader_element();
service.SessionHeader.sessionId = UserInfo.getSessionId();

MetadataService.ListMetadataQuery queryDocumentFolder = new MetadataService.ListMetadataQuery();
queryDocumentFolder.type_x = 'DocumentFolder';
queries.add(queryDocumentFolder);       
MetadataService.FileProperties[] fileProperties = service.listMetadata(queries, 30);
List<String> folderNames = new List<String>();
for(MetadataService.FileProperties fileProperty : fileProperties)
    folderNames.add(fileProperty.fileName.replace('documents/', ''));

List<MetadataService.DocumentFolder> folder = 
    (List<MetadataService.DocumentFolder>) 
        service.readMetadata('DocumentFolder', folderNames).getRecords();

Retrieve Metadata Demo Further Info

This screenshot shows the Retrieve Demo from the Apex Metadata API retrieving a document file and the document folder, you can see it retrieves the document metadata file. Again this only works IF you also retrieve a file as well sadly.

enter image description here

NOTE: Take a look at this code to see how the above works, to try it out enter the name of your folder in the Folder field, select Document from the drop down, select any file in the folder and click Retrieve.

Related Topic