fmAccounting Link (MYOB AccountRight Edition) Preview Video

We’ve just uploaded our first preview video for fmAccounting Link (MYOB AccountRight Edition). This video demonstrates the following:

  • authenticating against the MYOB AccountRight API
  • downloading a list of available AccountRight Company Files
  • selecting the AccountRight Company File and entering the credentials for the selected Company File
  • uploading a Contact from FileMaker Pro to AccountRight
  • uploading an Invoice from FileMaker Pro to AccountRight
  • uploading a Payment from FileMaker Pro to AccountRight
  • downloading Chart of Accounts, Tax Codes, Categories and Inventory Items from AccountRight to FileMaker

The video also demonstrates how you can integrate with MYOB AccountRight (a Windows only application) from a Mac OS X computer.

You can watch the video below or directly on YouTube via this link.

We should be releasing fmAccounting Link (MYOB AccountRight Edition) in the next couple of weeks – please Contact Us if you have any questions in the meantime.

FileMaker PHP API Layout Tips

Over the past few months we’ve been working on a large FileMaker PHP Project for a client that required a web based interface to their FileMaker solution that worked on smartphones and tablets (both iOS and Android),  as well as the traditional desktops (Mac and Windows). The web interface was for users who were out of the office for large amounts of the week but needed to access the office solution from their car, client meetings or at home.

We’ve done many FileMaker PHP projects since the PHP API was first released in 2007 but this was by far our largest. Having worked closely with the PHP API for many months we’ve picked up a few tips and tricks along the way that we wanted to share, starting with Layouts.

If you’re not familiar with FileMaker’s PHP API the way the API interacts with your database is via FileMaker layouts – if you wish to find, edit, create or delete a record you need to specify the layout to use. Specifying the layout establishes the context for the query. It’s also important to note that everything on the layout is returned when performing a API command such as finding a record – this is why best practise has always been to only included the fields required by the PHP pages. The XML data that is returned by the API is quite verbose so you want to keep this to an absolute minimum as it can have significant performance implications if you don’t optimise your layouts for the API.

The following are some tips that you should be aware of when working with FileMaker Layouts and the PHP API:

Watch out for hidden fields not visible on the layout

In the screenshot below you can see there are only 5 fields on the ‘ContactsDetailsWeb’ layout: Title, First, Last, Initial and Name:

ContactsDetailsWeb

If we use the PHP API to request all the fields on that layout and echo this back to the browser:

$layout = $fm->getLayout('ContactsDetailsWeb');
// Get an associative array with the names of all fields as keys and FileMaker_Field objects as the array values
$layoutFields = $layout->getFields();
echo '<p><pre>'.print_r ($layoutFields).'</pre></p>';

we get the following:

Array(
 [Title] => FileMaker_FieldObject([_impl] => FileMaker_Field_ImplementationObject([_layout] => FileMaker_LayoutObject([_impl] => FileMaker_Layout_ImplementationObject([_fm] => FileMaker_ImplementationObject([V73ee434e] => Array(
 [charset] => UTF - 8[locale] => en[logLevel] => 3[hostspec] => 127.0.0.1[recordClass] => FileMaker_Record[prevalidate] => [database] => ContactsStarterSolution[username] => Admin[password] =>
 ) [Vea4b3413] => [V9a3dcbce] =>) [_name] => ContactsDetailsWeb[_fields] => Array * RECURSION * [_relatedSets] => Array() [_valueLists] => Array() [Vab234ad8] => Array() [_database] => ContactsStarterSolution[_extended] =>)) [_name] => Title[_autoEntered] => [_global] => [_maxRepeat] => 1[_validationMask] => 0[_validationRules] => Array() [_result] => text[_type] => normal[_valueList] => [_styleType] => [_maxCharacters] => 0)) [First] => FileMaker_FieldObject([_impl] => FileMaker_Field_ImplementationObject([_layout] => FileMaker_LayoutObject([_impl] => FileMaker_Layout_ImplementationObject([_fm] => FileMaker_ImplementationObject([V73ee434e] => Array(
 [charset] => UTF - 8[locale] => en[logLevel] => 3[hostspec] => 127.0.0.1[recordClass] => FileMaker_Record[prevalidate] => [database] => ContactsStarterSolution[username] => Admin[password] =>
 ) [Vea4b3413] => [V9a3dcbce] =>) [_name] => ContactsDetailsWeb[_fields] => Array * RECURSION * [_relatedSets] => Array() [_valueLists] => Array() [Vab234ad8] => Array() [_database] => ContactsStarterSolution[_extended] =>)) [_name] => First[_autoEntered] => 1[_global] => [_maxRepeat] => 1[_validationMask] => 0[_validationRules] => Array() [_result] => text[_type] => normal[_valueList] => [_styleType] => [_maxCharacters] => 0)) [Last] => FileMaker_FieldObject([_impl] => FileMaker_Field_ImplementationObject([_layout] => FileMaker_LayoutObject([_impl] => FileMaker_Layout_ImplementationObject([_fm] => FileMaker_ImplementationObject([V73ee434e] => Array(
 [charset] => UTF - 8[locale] => en[logLevel] => 3[hostspec] => 127.0.0.1[recordClass] => FileMaker_Record[prevalidate] => [database] => ContactsStarterSolution[username] => Admin[password] =>
 ) [Vea4b3413] => [V9a3dcbce] =>) [_name] => ContactsDetailsWeb[_fields] => Array * RECURSION * [_relatedSets] => Array() [_valueLists] => Array() [Vab234ad8] => Array() [_database] => ContactsStarterSolution[_extended] =>)) [_name] => Last[_autoEntered] => [_global] => [_maxRepeat] => 1[_validationMask] => 0[_validationRules] => Array() [_result] => text[_type] => normal[_valueList] => [_styleType] => [_maxCharacters] => 0)) [Initial] => FileMaker_FieldObject([_impl] => FileMaker_Field_ImplementationObject([_layout] => FileMaker_LayoutObject([_impl] => FileMaker_Layout_ImplementationObject([_fm] => FileMaker_ImplementationObject([V73ee434e] => Array(
 [charset] => UTF - 8[locale] => en[logLevel] => 3[hostspec] => 127.0.0.1[recordClass] => FileMaker_Record[prevalidate] => [database] => ContactsStarterSolution[username] => Admin[password] =>
 ) [Vea4b3413] => [V9a3dcbce] =>) [_name] => ContactsDetailsWeb[_fields] => Array * RECURSION * [_relatedSets] => Array() [_valueLists] => Array() [Vab234ad8] => Array() [_database] => ContactsStarterSolution[_extended] =>)) [_name] => Initial[_autoEntered] => 1[_global] => [_maxRepeat] => 1[_validationMask] => 0[_validationRules] => Array() [_result] => text[_type] => calculation[_valueList] => [_styleType] => [_maxCharacters] => 0)) [Name] => FileMaker_FieldObject([_impl] => FileMaker_Field_ImplementationObject([_layout] => FileMaker_LayoutObject([_impl] => FileMaker_Layout_ImplementationObject([_fm] => FileMaker_ImplementationObject([V73ee434e] => Array(
 [charset] => UTF - 8[locale] => en[logLevel] => 3[hostspec] => 127.0.0.1[recordClass] => FileMaker_Record[prevalidate] => [database] => ContactsStarterSolution[username] => Admin[password] =>
 ) [Vea4b3413] => [V9a3dcbce] =>) [_name] => ContactsDetailsWeb[_fields] => Array * RECURSION * [_relatedSets] => Array() [_valueLists] => Array() [Vab234ad8] => Array() [_database] => ContactsStarterSolution[_extended] =>)) [_name] => Name[_autoEntered] => [_global] => [_maxRepeat] => 1[_validationMask] => 0[_validationRules] => Array() [_result] => text[_type] => calculation[_valueList] => [_styleType] => [_maxCharacters] => 0)) [Mobile] => FileMaker_FieldObject([_impl] => FileMaker_Field_ImplementationObject([_layout] => FileMaker_LayoutObject([_impl] => FileMaker_Layout_ImplementationObject([_fm] => FileMaker_ImplementationObject([V73ee434e] => Array(
 [charset] => UTF - 8[locale] => en[logLevel] => 3[hostspec] => 127.0.0.1[recordClass] => FileMaker_Record[prevalidate] => [database] => ContactsStarterSolution[username] => Admin[password] =>
 ) [Vea4b3413] => [V9a3dcbce] =>) [_name] => ContactsDetailsWeb[_fields] => Array * RECURSION * [_relatedSets] => Array() [_valueLists] => Array() [Vab234ad8] => Array() [_database] => ContactsStarterSolution[_extended] =>)) [_name] => Mobile[_autoEntered] => [_global] => [_maxRepeat] => 1[_validationMask] => 0[_validationRules] => Array() [_result] => text[_type] => normal[_valueList] => [_styleType] => [_maxCharacters] => 0)) [OfficeEmail] => FileMaker_FieldObject([_impl] => FileMaker_Field_ImplementationObject([_layout] => FileMaker_LayoutObject([_impl] => FileMaker_Layout_ImplementationObject([_fm] => FileMaker_ImplementationObject([V73ee434e] => Array(
 [charset] => UTF - 8[locale] => en[logLevel] => 3[hostspec] => 127.0.0.1[recordClass] => FileMaker_Record[prevalidate] => [database] => ContactsStarterSolution[username] => Admin[password] =>
 ) [Vea4b3413] => [V9a3dcbce] =>) [_name] => ContactsDetailsWeb[_fields] => Array * RECURSION * [_relatedSets] => Array() [_valueLists] => Array() [Vab234ad8] => Array() [_database] => ContactsStarterSolution[_extended] =>)) [_name] => OfficeEmail[_autoEntered] => [_global] => [_maxRepeat] => 1[_validationMask] => 0[_validationRules] => Array() [_result] => text[_type] => normal[_valueList] => [_styleType] => [_maxCharacters] => 0)) [OfficePhone] => FileMaker_FieldObject([_impl] => FileMaker_Field_ImplementationObject([_layout] => FileMaker_LayoutObject([_impl] => FileMaker_Layout_ImplementationObject([_fm] => FileMaker_ImplementationObject([V73ee434e] => Array(
 [charset] => UTF - 8[locale] => en[logLevel] => 3[hostspec] => 127.0.0.1[recordClass] => FileMaker_Record[prevalidate] => [database] => ContactsStarterSolution[username] => Admin[password] =>
 ) [Vea4b3413] => [V9a3dcbce] =>) [_name] => ContactsDetailsWeb[_fields] => Array * RECURSION * [_relatedSets] => Array() [_valueLists] => Array() [Vab234ad8] => Array() [_database] => ContactsStarterSolution[_extended] =>)) [_name] => OfficePhone[_autoEntered] => [_global] => [_maxRepeat] => 1[_validationMask] => 0[_validationRules] => Array() [_result] => text[_type] => normal[_valueList] => [_styleType] => [_maxCharacters] => 0)) [Fax] => FileMaker_FieldObject([_impl] => FileMaker_Field_ImplementationObject([_layout] => FileMaker_LayoutObject([_impl] => FileMaker_Layout_ImplementationObject([_fm] => FileMaker_ImplementationObject([V73ee434e] => Array(
 [charset] => UTF - 8[locale] => en[logLevel] => 3[hostspec] => 127.0.0.1[recordClass] => FileMaker_Record[prevalidate] => [database] => ContactsStarterSolution[username] => Admin[password] =>
 ) [Vea4b3413] => [V9a3dcbce] =>) [_name] => ContactsDetailsWeb[_fields] => Array * RECURSION * [_relatedSets] => Array() [_valueLists] => Array() [Vab234ad8] => Array() [_database] => ContactsStarterSolution[_extended] =>)) [_name] => Fax[_autoEntered] => [_global] => [_maxRepeat] => 1[_validationMask] => 0[_validationRules] => Array() [_result] => text[_type] => normal[_valueList] => [_styleType] => [_maxCharacters] => 0)) [PersonalEmail] => FileMaker_FieldObject([_impl] => FileMaker_Field_ImplementationObject([_layout] => FileMaker_LayoutObject([_impl] => FileMaker_Layout_ImplementationObject([_fm] => FileMaker_ImplementationObject([V73ee434e] => Array(
 [charset] => UTF - 8[locale] => en[logLevel] => 3[hostspec] => 127.0.0.1[recordClass] => FileMaker_Record[prevalidate] => [database] => ContactsStarterSolution[username] => Admin[password] =>
 ) [Vea4b3413] => [V9a3dcbce] =>) [_name] => ContactsDetailsWeb[_fields] => Array * RECURSION * [_relatedSets] => Array() [_valueLists] => Array() [Vab234ad8] => Array() [_database] => ContactsStarterSolution[_extended] =>)) [_name] => PersonalEmail[_autoEntered] => [_global] => [_maxRepeat] => 1[_validationMask] => 0[_validationRules] => Array() [_result] => text[_type] => normal[_valueList] => [_styleType] => [_maxCharacters] => 0)) [PersonalPhone] => FileMaker_FieldObject([_impl] => FileMaker_Field_ImplementationObject([_layout] => FileMaker_LayoutObject([_impl] => FileMaker_Layout_ImplementationObject([_fm] => FileMaker_ImplementationObject([V73ee434e] => Array(
 [charset] => UTF - 8[locale] => en[logLevel] => 3[hostspec] => 127.0.0.1[recordClass] => FileMaker_Record[prevalidate] => [database] => ContactsStarterSolution[username] => Admin[password] =>
 ) [Vea4b3413] => [V9a3dcbce] =>) [_name] => ContactsDetailsWeb[_fields] => Array * RECURSION * [_relatedSets] => Array() [_valueLists] => Array() [Vab234ad8] => Array() [_database] => ContactsStarterSolution[_extended] =>)) [_name] => PersonalPhone[_autoEntered] => [_global] => [_maxRepeat] => 1[_validationMask] => 0[_validationRules] => Array() [_result] => text[_type] => normal[_valueList] => [_styleType] => [_maxCharacters] => 0))
 )

As you can see the result is quite verbose and includes some additional fields that you can’t see on the layout: Mobile, OfficeEmail, OfficePhone, Fax, PersonalEmail and PersonalPhone. So how does the PHP API see these fields? Let’s have a look at the same layout in Layout mode:

ContactsDetailsWeb Layout Mode

You can see these fields are hidden off to the right of the layout’s visible boundary and don’t appear in Browse mode using the FileMaker Pro client, but the PHP API sees all fields on the layout including the hidden fields. It’s advisable to not only have PHP specific layouts that contain just the fields you need for the PHP pages but don’t park/hide other fields off the edge of the layout. The PHP API will retrieve them as well and add additional overhead to your queries causing pages to take longer to load.

This only applies to those using FileMaker Pro/Server v12 or above – the ability to set a layout width was introduced in FileMaker Pro v12.

Beware of Layout Folder Names

We encountered an issue that caused quite a few hours of troubleshooting to resolve but seems obvious in hindsight. Here’s a screenshot showing a list of layouts in a FileMaker database:

List of Layouts

We had a PHP page that interacted with the ‘ContactsPHP’ layout – it would find records, edit records, create records etc and had been working fine for weeks without any issues when all of a sudden it stopped working one day. We ran multiple tests, double checked the spelling of the layout names, checked privileges etc but couldn’t understand what had happened.

We used the API to list out all the layouts in the database and echo this back to the browser:

$layout = $fm->getLayout('ContactsDetailsWeb');
$layouts = $fm->listLayouts();
echo '<p><pre>'.print_r ($layouts).'</pre></p>';

This returned the following array showing the ‘ContactsPHP’ layout:

Array(
 [0] => StartupScreen[1] => - [2] => Contacts[3] => ContactDetails[4] => Contacts | iPad[5] => ContactDetails | iPad[6] => Contacts | iPhone[7] => ContactDetails | iPhone[8] => Contacts | Web[9] => ContactDetails | Web[10] => ContactsDetailsWeb[11] => - [12] => Labels[13] => ContactList[14] => - [15] => ContactsPHP[16] => [17] => [18] => [19] => [20] => [21] => [22] => [23] => [24] => [25] =>
 )

Once again we couldn’t spot any issues with the layouts – the ‘ContactsPHP’ layout was amongst the list of layouts returned.

We then decided to rename the layout, update the PHP page and run some tests and it started working again. We renamed it back to ‘ContactsPHP’ and it failed immediately. Finally the penny dropped – we had a layout folder with exactly the same name that appear above the layout in the list of layouts. We tried renaming the layout folder and voila it started working again. It seems that for certain commands having a layout folder with the same name as the layout works fine, but there are times when it will cause the API to fail. We haven’t been able to isolate the specific circumstances yet but the safest approach is to simply avoid having layout folders with the same names as actual layouts entirely – remember that layout folders are special layout types and it appears that the PHP API can still interact with them when they share the same name as actual layouts.

We’ve run a number of tests and have been able to reproduce this many times on a sample file. We’ve found that if you’re checking for a 401 ‘no records found’ error with a find command like this:

if (FileMaker::isError($result)) {
    if ($result->code = 401) {
    $findError = $result->getMessage(). ' (' . $result->code . ')</p>';
    } else {
    $findError = $result->getMessage(). ' (' . $result->code . ')</p>';
    }
}

you will be mislead into thinking there was a real 401 ‘no records found’. If you examine the FileMaker_Error Object you should see it’s returning a 102 error:

[code] => 102

which is “Field is missing” and makes more sense if it’s using the Layout Folder instead of the actual Layout with the same name (we’ve also seen other instances where the API returns a misleading 401 error, such as when the XML returned is too large for the PHP XML  parser to handle – another reason to carefully optimise your PHP layouts). We first noticed this when we had a Layout Folder named ‘Websites’ and another layout used for a PHP find command called ‘WebSites’, but we have been able to reproduce this with other names as well.

Find Commands and the setResultLayout method

As we’ve discussed it’s ideal to optimise your FileMaker layouts used for the PHP API to only have the required fields on the layout necessary for the particular command, such as creating a new record or performing a find. It’s also possible to further optimise your queries to use separate layouts for the find command and the find results. For example you might have a form on your website that allows users to search for contact records by first name and last name only, however the PHP page is using a layout that has 25 fields from the Contacts table as you using the one Contacts layout for all PHP requests. For smaller record sets you can probably get away with this, but if you would like to optimise this further you can create a layout just for the find command with the 2 fields that you can search on and then have a separate layout that is used to display the find results, which might only require 6 fields for first name, last name, company, email, phone and mobile.

A typical PHP API find command that uses the one layout for both the find request and the find results looks like this:

$request = $fm->newFindCommand('ContactsDetailsWeb');
$request->addFindCriterion('FirstName', 'John');
$result = $request->execute();
if (FileMaker::isError($result)) {
    if ($result->code = 401) {
    $findError = 'There are no Records that match that request: '. ' (' . $result->code . ')';
    } else {
    $findError = 'Find Error: '. $result->getMessage(). ' (' . $result->code . ')';
    }
} else {
$records = $result->getRecords();
}

Here we are performing a find command on the ContactsDetailsWeb layout for any records that have a FirstName that equals ‘John’. We are then checking for any errors with the find command – if there are no matching records it will return a 401 error code, otherwise it will return another find error. If there is no error we are then retrieving all the found records.

To modify the find request to also use a different layout for the find results (to reduce the amount of XML data returned by the API by specifying a layout with just the fields required to show the search results) would look like this:

$request = $fm->newFindCommand('ContactsDetailsWeb');
$request->addFindCriterion('FirstName', 'John');
$request->setResultLayout( 'ContactsSearchResults' );
$result = $request->execute();
if (FileMaker::isError($result)) {
    if ($result->code = 401) {
    $findError = 'There are no Records that match that request: '. ' (' . $result->code . ')';
    } else {
    $findError = 'Find Error: '. $result->getMessage(). ' (' . $result->code . ')';
    }
} else {
$records = $result->getRecords();
}

The only difference between the 2 examples is the addition of this line that uses the setResultLayout method :

$request->setResultLayout( 'ContactsSearchResults' );

The setResultLayout method requests that the command’s result be returned in a layout different from the current layout. This certainly helps speed up the display of search results, however it does have one side effect. When you use the setResultLayout method as part of your find command and there are find errors (such as no records found) the API no longer returns a FileMaker_Error Object but instead returns a FileMaker_Result Object. This is a subtle but important difference – it means you can no longer simply trap for any find errors by calling:

if (FileMaker::isError($result)) {

as you will not get a FileMaker_Error Object. You can check for the number of matching records found, e.g.:

$found = $result->getFoundSetCount();

but it is certainly not as neat as simply checking for a FileMaker_Error Object.

I had trouble finding out more information about the setResultLayout method and ended up submitting a bug report with FileMaker Inc. The response they came back with suggests this is a known limitation when using the setResultLayout method. It would be great if this could be addressed in a future release of the PHP API.

(N.B. all references are to FileMaker Pro/FileMaker Server v14 which was the current shipping version at the time this article was written)

A Beginner’s Guide to Working with Lists in FileMaker Pro

As you become more familiar with FileMaker Pro and make the leap from beginner to intermediate developer you will inevitably become accustomed to working with lists. By list I’m referring to a series of values separated by carriage returns such as

apple
banana
pear
mango

The list might be referencing a series of repeating fields, some related fields from another table, or it might be a series of values that you concatenate manually to achieve the desired result. You might use your list in a script as part of a loop that iterates through the list and performs actions for each value in the list, such as creating a new record or sending an email. You might be creating a list of delimited data to use in a chart or you might be generating a list to use as a match field in a relationship (see below for more details).

List Related Functions

FileMaker Pro has a number of native calculation functions to help you generate lists and extract values from a list:

List ( field { ; field…} ) – the list function was originally introduced with FileMaker Pro 8.5 (there hasn’t been a .5 release since) and as it’s name suggests its sole purpose is to generate a list of values.

The field reference can be any related field, repeating field, or set of non-repeating fields; an expression that returns a field, repeating field, or a set of non-repeating fields, or a variable. For example you might wish to generate a list of all the Invoice Numbers for a particular Contact record. Assuming you have a table occurrence named Invoices that is related to Contacts by a Contact ID match field the following calculation:

List ( Invoices::InvoiceNumber )

would return the list of Invoice Numbers for the current customer record. You can mix and match field references, variables and literal strings – for example:

List ( "INV1056" ; Invoices::InvoiceNumber ; $invoiceID )

It’s important to note that the List function ignores blank values – List ( “apple” ; “” ; “banana” )  would return:

apple
banana

ValueCount – this returns a count of the total number of values in specified list. For example ValueCount ( List ( “apple” ; “banana” ; “orange” ) ) returns 3.

LeftValues ( text; numberOfValues)  – this returns the first numberOfValues from the specified list. N.B. the resulting list of values returned always ends with a carriage return. For example LeftValues ( List ( “apple” ; “banana” ; “orange” ) ; 1 ) returns:

apple¶

RightValues ( text; numberOfValues ) – this returns the last numberOfValues from the specified list. N.B. the resulting list of values returned always ends with a carriage return. For example RightValues ( List ( “apple” ; “banana” ; “orange” ) ; 1 ) returns:

orange¶

MiddleValues( text ; startingValue ; numberOfValues)  – this returns the middle numberOfValues from the specified list, starting at startingValue. N.B. the resulting list of values returned always ends with a carriage return. For example MiddleValues ( List ( “apple” ; “banana” ; “orange” ) ; 2 ; 2 ) returns:

banana
orange¶

FilterValues ( textToFilter ; filterValues ) – this returns all the items in textToFilter that are also in filterValues, in the order they were originally entered in textToFilter. This allows you to compare two lists to find the values they both have in common. N.B. the resulting list of values returned always ends with a carriage return. For example FilterValues ( List ( “apple” ; “banana” ; “orange” ) ; “banana¶orange” ) returns:

banana
orange¶

GetValue ( listOfValues ; valueNumber )  – this allows you to retrieve a specified value from a list of values, typically used when you are looping through a list and performing some actions for each value in the list. N.B. the value returned does NOT end with a carriage return. For example GetValue ( List ( “apple” ; “banana” ; “orange” ) ; 2 )returns:

banana

Multi-Key fields

One of the more common uses for lists mentioned above was for use as a match field in a relationship. Most relationships typically use a single field/value on both sides of the relationship. For example the Company ID field in the Companies table (primary key) matches the Company ID field in the Users table (foreign key). FileMaker Pro also lets you enter mutliple values into the same field which has the effect of increasing the number of possible matching values on the other side of the relationship. You simply enter the values separated by carriage returns and FileMaker will look for matches for every line/value you have entered.

If you entered the following values into a text field (you would typically use a text field with global storage):

C1045
C2784
C3698
C1077

FileMaker Pro will then look for any matching records for each of these 4 values. Multi-key fields can be a very powerful feature of FileMaker Pro and are also often referred to as multi-line keys.

Generating a list of values from a field in a found set of records

One of my favourite new features of FileMaker Pro v13 was the new “List of” option when creating a Summary field. This option creates a return-delimited list of non-blank values in specified field for the current found set of records. One obvious purpose of this function is to create a list to use for a Multi-key field – you can’t use a Summary field itself as the match field in a relationship but you can use the result it generates in a global or calculation field.

I would also recommend reading the fileMakerhacks series on using Summary list fields in relationships.

Custom Functions and Plug-in Functions

There will be times where you need to manipulate lists and go beyond the native FileMaker functions – for example you might want to compare two lists and return all the values that are different in both lists, sort the list of values, or you might want to remove any duplicate values from a list. Here’s some of the custom functions and external plug-in functions that I use on a regular basis:

SortList ( ValueList ; Sort ; Type ) – this custom function allows you to sort a list with options for ascending or descending order

XORvalues ( ListA ; ListB ) – this custom function returns all lines that are different in two lists. If you only specify one list it will also eliminate duplicates from the list and return a single instance of each value

ZapValues ( ListA ; ListB ) – this custom function will compare two lists and remove the items in List B from List A (this is the inverse of the native FilterValues function)

Trim4 ( text ) – if you are using the native functions that also return a trailing carriage return you can use this custom function to remove this at the same time

AddRemoveListItem ( theList ; value ) – this custom function will add an item to a list if it does not already exist; otherwise the item is removed from the list

There will be times when you are not able to use a custom function due to the limitations of custom functions – recursive custom functions are limited to either 10,000 interactions or 50,000 iterations depending on the style of recursion they use (this article has more details on the limitations). When you hit these limitations you will need to use a plug-in function which are not bound by the same limitations as custom functions. Databuzz is a proud sponsor of the open source BaseElements plug-in which has a number of handy list related functions including:

BE_Values_Unique ( listOfValues {; caseSensitive } ) – this removes any duplicate values from the specified list

BE_Values_Sort  ( listOfValues ) – this sorts the list in alphanumeric order

BE_Values_FilterOut ( textToFilter ; filterValues {; caseSensitive } ) – similar to the ZapValues custom function, this will compare two lists and remove items from the textToFilter list that are found in the filterValues list
(N.B. all references are to FileMaker Pro v14 which was the current shipping version at the time this article was written)

FileMaker 14 Certified Developer

Databuzz is pleased to announce that Andrew Duncan recently passed the FileMaker 14 Certification Exam and is now FileMaker Certified in v8, 9, 10, 11, 12, 13 and 14. FileMaker 14 Certification is the official credential offered by FileMaker, Inc.

FileMaker Certification is your validation that you are hiring an experienced FileMaker professional who has technical knowledge of the complete FileMaker product line and has passed the “Developer Essentials for FileMaker” certification exam. Being a certified developer demonstrates to clients, peers and management that you’ve achieved an essential level of knowledge, experience and skills in developing FileMaker solutions.

certified_14_logo_4clr

 

Installing 32-bit and 64-bit plug-ins in FileMaker Pro v14

The recently released FileMaker Pro v14 is the first version of FileMaker Pro that can be installed and run as either a 32-bit application or a 64-bit application – on Windows you have to choose which version to install, and on OS X FileMaker Pro is installed as a single application bundle containing both 64- and 32-bit versions (you can choose which version to run via the Get Info window).

When using the 64-bit FileMaker Pro application you will need to ensure that any plug-ins you install are the 64-bit versions – 32-bit plug-ins won’t load with the 64-bit FileMaker Pro application. The same applies to the 32-bit FileMaker Pro application – it will only load 32-bit plug-ins.

How do you check which version of FileMaker Pro v14 is installed in order to install the appropriate version of the plug-in? FileMaker have added a new function to v14 for just this purpose – Get ( ApplicationArchitecture ). This function will return the following depending on the platform:

  • i386 for the 32-bit version of FileMaker Pro
  • x86_64 for the 64-bit version of FileMaker Pro, FileMaker Server, FileMaker WebDirect, and Custom Web Publishing
  • arm7 for FileMaker Go running on an ARMv7-based device
  • arm7s for FileMaker Go running on an ARMv7s-based device
  • arm64 for FileMaker Go running on a 64-bit ARM-based device

As plug-ins are only supported by FileMaker Pro and FileMaker Server you can ignore the FileMaker Go options. To install a plug-in for the appropriate version/architecture/platform you can write a script that incorporates the following:

  1. use the Get (ApplicationVersion) function to determine whether you are running under FileMaker Pro/Pro Advanced, FileMaker Server or the Web Publishing Engine
  2. also use the the Get (ApplicationVersion) function to determine the version of the FileMaker client you are running
  3. if the client is FileMaker Pro/Pro Advanced and the version is less than 14 you can simply install the 32-bit version of the plug-in using the Install Plug-In File script step – you can check the installed version using the Get(InstalledFMPlugins) function
  4. if the client is FileMaker Pro/Pro Advanced and the version 14 or higher you can use the Get ( ApplicationArchitecture ) function to determine is it is a 32-bit or 64-bit installation and then use the Install Plug-In File script step to install the appropriate version
  5. if the client is FileMaker Server and the version is 13 or higher you will need to install the 64-bit version of the plug-in. For FileMaker Server v12 you need to install the 32-bit version of the plug-in. Remember to check the options in the FileMaker Server Admin Console under the Database Server > Server Plug-Ins tab to enable FileMaker Server to use plug-ins and update them via the Install Plug-In File script step.

Plug-in vendors will typically supply 3 versions of each plug-in:

  1. the Mac OS X version of the plug-in – this is a single binary plug-in (file extension .fmplugin) containing both the 32-bit and 64-bit versions of the plug-in
  2. a Windows 32-bit plug-in (file extension .fmx)
  3. a Windows 64-bit plug-in (file extension .fmx64)

You can store each of these plug-in files in separate container fields to be referenced by the Install Plug-In File script step, once you have branched for your FileMaker client, version and architecture.

If you’re using plug-ins with FileMaker Server’s Web Publishing Engine you’ll need to install these manually on your server – see the FileMaker Server Help guide for details on where to install these (the Custom Web Publishing Engine has been a 64-bit process since FileMaker Server v12.0v2).

This FileMake Knowledge Base article has more information about FileMaker Pro v14 and 64-bit operating systems – FileMaker Pro/Advanced and Windows 64 bit operating systems.

fmAccounting Link (Xero Edition) and FileMaker Pro v14

We’re pleased to report that fmAccounting Link (Xero Edition) v1 is compatible with FileMaker Pro/Pro Advanced v14 that was released today. We haven’t encountered any issues so far in our testing and have been able to send single and bulk messages successfully.

If you encounter any issues with fmAccounting Link (Xero Edition) v1 and FileMaker Pro v14 please let us know.

fmSMS and FileMaker Pro v14

We’re pleased to report that fmSMS v3 is compatible with FileMaker Pro/Pro Advanced v14 that was released today. We haven’t encountered any issues so far in our testing and have been able to send single and bulk messages successfully.

If you encounter any issues with fmSMS v3 and FileMaker Pro v14 please let us know.