Script Variables

Script variables are an extremely important addition to scripting in FileMaker 8. If you've worked with other languages or development environments, you're familiar with a variable as a type of named, temporary storage. For example, in the PHP programming language, you might write this:

$x = 7;
$y = 9;
$z = $x + $y;

Here $x, $y, and $z are all variablestemporary names to which values are then assigned (the $ in PHP indicates that these are variable names, and FileMaker 8, as you'll soon see, uses a similar convention for variable names). In later expressions, the variable names stand in for the values stored in them. So you'd expect that when the preceding program is run, the variable $z will end up storing a value of 16.

Often, as you build up a program or routine, you'll find yourself wanting to rely on named, temporary storage elements like these. In previous versions of FileMaker, the only place to cache such data has been within FileMaker's database structures, by putting the data into one or another kind of field.

Consider the simplistic example of a script that beeps 10 times in succession. Previously, you might have defined a field with global storage to act as a counter, and written the script like this:

Set Field [Loop::gCounter; 1]
Loop
 Beep
 Pause/Resume Script [Duration (seconds):1]
 Set Field [Loop::gCounter; Loop::gCounter + 1]
 Exit Loop If [Loop::gCounter > 10]
End Loop

This has always worked fine, but it has some drawbacks:

  • Even though the counter field is used only in this script, it has to be defined within the field definitions for the table as a whole. It will always be there, cluttering up the list, even though it may apply to only a single script.
  • The storage is not as temporary as you would like. The field gCounter will go on holding its value and being accessible after the script completes. This is one reason it's necessary to reset the field to 1 at the start of the script. If the script has been run previously, it might still have its old value of 11, or it might have some other value altogether if someone edited the field directly and stored it in the database.

Global fields are still useful for many things in FileMaker 8, as you'll see, but they're not ideally suited to the kind of temporary named storage we need for something like a loop counter. This is where FileMaker 8's variables come to the forefront. FileMaker 8 script variables are defined within scripts, so they don't appear in the list of defined fields. And script variables can be truly temporary, coming into existence within a specific script and disappearing when the script completes.

About Local Variables

A local variable is one that exists and has meaning only within a single script: exactly what you'd want for the loop counting example shown previously. If you were to rewrite the looping script using FileMaker 8 script variables, it might look like this:

Set Variable [$counter; Value:1]
Loop
 Beep
 Pause/Resume Script [Duration (seconds):1]
 Set Variable [$counter; Value: $counter + 1]
 Exit Loop If [$counter > 10]
End Loop

Local variables are named using a single dollar sign ($), and they're created and manipulated using the Set Variable script step. The options for the Set Variable script step are shown in Figure 15.5.

Figure 15.5. The capability to set variables is a powerful new feature in FileMaker 8.

You'll notice that the Set Variable script step allows you to set the variable's value dynamically, using the Specify option. This means that a variable can be used to hold the results of any expression you can define using FileMaker's Calculation dialog. You could store the current username, the current date, or the results of an expression such as $counter + 1. You'll note also, by the way, that variables can be referenced from within such calculations just by using the variable name. For example, the following are perfectly valid calculation expressions:

$counter + 1

"Name: " & $userName

If a variable of the specified name is not currently defined, a reference to the variable returns an empty string (or a null result, if that term is more familiar). The first expression of the preceding two would give a result of 1, whereas the second would give a result of "Name:", if the respective variables were not defined.

About Variable Scope

You'll often hear computer-science types talking about the scope of a variable. It's a concept worth mastering. Scope can be defined as "that portion of a program for which a variable is defined or has meaning." Variables in FileMaker have one of two kinds of scope: either local scope or global scope.

So far, the variables we've examined have local scope. It's most common to refer to them as local variables. A local variable exists and has meaning only within the context of a single script. Consider the example of the $counter variable discussed previously. This variable exists only within the script in which it's defined and manipulated. After the script completes, the $counter variable in effect disappears. Likewise, if you called a subscript from within that script, the subscript would not have access to the value of $counter contained in the parent script.

Because local variables exist only within the context of a single script, this can lead to subtle confusion. Consider a parent script that uses a $counter variable that then also calls a subscript. If you were to try to access the value of $counter within the subscript, you'd get a null value because you'd be trying to access a variable that had never been set within the context of the subscript. And if you were to try to set the value of $counter within the subscript, using the Set Variable script step, this would create a new variable, local to the subscript, with the same name, $counter. There would thus be a total of two $counter variables: one local to the parent script, one local to the subscript. The two exist simultaneously and independently; they don't conflict, and they don't affect one another.

Local Variables Summary

So, to summarize what has been said about local variables in FileMaker 8:

  • Local variables are set using the Set Variable script step.
  • Local variables must have names beginning with $.
  • Local variables can be referenced within calculation expressions.
  • Local variables are limited in scope to the script in which they are defined (via the Set Variable script step). Neither any subscripts nor any parent scripts can access the value of a local variable.
  • Local variables do not appear in the Define Database dialog.

About Global Variables

Global variables, denoted with a double dollar sign ($$userName, $$currentLayout) share many features with local variables. The only difference is in their scope. Whereas local variables are limited in scope to a single script, global variables retain their value no matter what script is running, or whether a script is running at all. They can be used to store values that persist across any or all scripts, for the duration of a user's session.

The last point bears repeating. Whereas local variables have script scope, meaning that they are limited in scope to a single script, global variables have file/session scope. Like globally stored fields, global variables are unique to an individual user: Each user has his own copy of a global variable, so the variable $$userName can have a different value for each active user. And global variables also cease to exist when a user session ends. If you work with a global variable, quit FileMaker, and then open the same file again, the global variable will disappear, until some logic in the files creates it again.

Global variables also have scope only within a single file. There is no way to "reach across" to pull a global variable's data from one file into another. (Such a thing is, by contrast, possible with globally stored fields.) Global variables from other files cannot be accessed via relationships, because they don't appear in the field list.

So what good are global variables? When does it make sense to use them? We recommend that, by and large, you use global variables for user session data: data specific to one user that is intended to persist for just that user session. Examples include things like the name of the currently logged-in user, or user preferences such as a user's chosen default layout, or any other user-specific data you might be storing, such as a user's department or sales region.

It is also tempting to use global variables for general data transfer between scripts. For example, in a script that prompts the user for a dialog box choice, you might be tempted to store the user's choice in a global variable so that other scripts (a parent script, for example) could have access to the user's choice and act accordingly.

We can't stress too strongly that this is not a good use for global variables! FileMaker 8 provides a set of what we call script (input/output) capabilities that let you pass data into scripts, and now, in FileMaker 8, return results from scripts. If you simply need to move data from one script to another, script parameters and script results (discussed in the preceding section of this chapter) are the best way to accomplish that task. Using global storage, whether global variables or globally stored fields, for general data transfer between scripts will make your programs more fragile and less maintainable. Global storage, by definition, can be accessed from anywhere, so you can never quite be sure that you know where your data is coming from; it might have been modified by scripts other than those with which you're trying to communicate, perhaps even by accident.

In the dialog box example discussed previously, we chose to return the user's choice as a script result, rather than tossing it into a global variable. Using script results, we were able to avoid creating any temporary storage along the way.

Global variables cannot completely obviate the need for globally stored fields. Globally stored fields have several capabilities not shared by global variables:

  • Globally stored fields can be accessed across files by using relationships.
  • Globally stored fields can accept user input.
  • Globally stored fields can be used to drive relationships.
  • Globally stored fields can be used to store the content of an input field from a custom dialog.

For example, if you were implementing a filtered portal (a portal the contents of which change in response to user input), you would need to use a globally stored field to do so, both because you would need to capture user input, and because you would need to use that input to drive the portal relationship.

For more on filtered portals, see "Filtered Portals," p. 489.

 

Other Ways to Work with Variables

Variables in FileMaker 8 can be used in quite complex ways. When you're first starting out with variables, we recommend you try to stick to the following precepts until you feel you've mastered the basics:

  • Use local variables for temporary storage that is used within the context of a single script.
  • Use global variables to store user-specific session data (with the exceptions noted in the next point).
  • Use globally stored fields to store user-specific session data that must be captured directly from the user, must drive a relationship, or must be shared heavily across files.

Now that we've said all of that, if you have mastered the basic concepts of variables, there are some advanced points to be made about them. If you feel you're ready, read on!

Accessing Variables Across Files

We've said previously that there's no way to share global variables across files. This is not entirely true. Using FileMaker 8's new capability to return script results, you can have a script in file A return the value of a global variable from file A back to a script in file B. Consider the following one-line script:

Exit Script[Result: Evaluate( Get( ScriptParameter ) )]

This one-liner may appear puzzling at first. It simply takes whatever script parameter was passed in, uses Evaluate on it, and returns the result.

Now suppose that this script, living in file A, is called from file B with a parameter of "$$currentUserName" (quotes included!). The Evaluate function will evaluate the string "$$currentUserName", so if a global variable of that name exists in file A, Evaluate will return the value of that variable. This value in turn gets passed out of the script as a script result, and is returned to the calling function in file B.

The principal drawback to this technique is that it's scripted, so it doesn't give a means to access variables in other files in such a way that they could be used in calculation expressions. It's a highly specialized technique, but might come in handy from time to time.

Accessing Variables from Within a Let Statement

If our editors had offered us a way to put a big yellow flag over an entire section, to signal "Caution! Slow Down! Dangerous Curves Ahead!" we would probably have applied it to this section. You may work with variables for a while before you need to delve into these techniques, but because the capability does exist in FileMaker 8, we discuss it here for completeness.

It's important to know that script variables can be referenced and used within a Let statement, both within the variables block of the Let statement and within the body of the Let formula itself. For example, the following Let statement incorporates the value of a global variable called $$currentUserName:

Let (
[ dayNm = DayName( Get(CurrentDate)) ] ;
"Hello, " & $$currentUserName & ", it is " & dayNm )

In this example, we are only reading the value of $$currentUserName. But it's also possible to set the value of a variable from within the variables block of a Let statement, like this:

Let (
[
$$currentUserName = Get ( AccountName );
dow = DayOfWeek( Get(CurrentDate))
] ;
"Hello, " & $$currentUserName & ", it is " & dow )

This operation will actually set the value of $$currentUserName, and because this is a global variable, the value of the variable will persist even beyond the bounds of the Let statement!

The same considerations apply to local variables (those denoted with a single $); they can be read from within a Let statement, and can be set or reset within the variable block of a Let statement.

The capability of reading and writing script variables from within a Let statement is intriguing, but we would argue that this technique is best used with caution, and only when you're certain that there's no better or equally practical way to accomplish your goals. There are actually several scenarios here, and each is slightly different:

  • Reading a global variable from within a Let Global variables are intended to be global, so this is in fact a somewhat reasonable thing to do.
  • Writing to a global variable from within a Let Again, global variables are supposed to be global, so this is not unreasonable; but we'd recommend that you strictly limit the places you do this. For a given global variable, it's best if you write to it only from a few, known locations. Otherwise it can be very difficult to track down when and how a global variable is being set. This is especially true for Let statements because a tool like the Script Debugger will let you follow a script but will not step through the inner operations of a Let statement.
  • Reading/writing local variables from within a Let We view this practice as potentially suspect and trouble-prone. The reason is that a local variable has meaning only within a single script. The implication is that any calculations or custom functions that use a Let to manipulate local variables then become tightly associated with a particular script or scripts. Because one of the main points of encapsulating logic into calculations or custom functions is to make them more reusable, it cuts very much against the grain to then make those formulas dependent on specific scripts.

The story is different, though, for Let statements within calculations that are defined on the fly within scripts, such as those you might enter in the Specify box of many script steps. These are transient, script-only formulas that it may make sense to bind closely to the script by referencing script variables.

About Dynamic File Paths

There's another nice feature of variables in FileMaker 8 that's very much worth mentioning. Certain script steps, such as Export Records, as well as the new Save Records as Excel/PDF script step, allow you to specify the location of an output file by typing in a file reference. In FileMaker 8, that file reference may be taken from a variable, rather than being hard-coded.

If the usefulness of that isn't obvious, let it sink in for a moment. In the past, it hasn't been possible to create names for exported files on the fly: You either had to let the user enter a filename, or had to hard-code a single specific filename into the script step. If you wanted to name exported or saved files dynamically (say you wanted to include the current date in the filename), you were out of luck, unless you chose to use a third-party plug-in.

To save files to a dynamically specified file path, you'll need to create that file path in your script and put it into a variable. That variable can then be used in specifying a file path, as the following script example illustrates:

Go to Layout [ "Contacts" ]
Show All Records
Set Variable [ $filePath; Value: Let (
 [
 theDate = Get(CurrentDate);
 theYear = Year(theDate);
 theMonth = Month(theDate);
 theDay = Day(theDate);
 dateText = theYear & "_" & theMonth & "_" & theDay;
 filePath = Get ( FileMakerPath ) & "Export_" & dateText
 ];
 filePath ) ]
Save Records as PDF [ File Name: "$filePath"; Records being browsed ]

This script example uses no fewer than three new FileMaker 8 features: script variables, the capability to use script variables for dynamic file paths, and one of FileMaker 8's several new Get() functions, Get(FileMakerPath).Get(FileMakerPath) will return the path to the FileMaker application directory. This function is part of a family of new path functions in FileMaker 8 that also includes Get(DesktopPath), Get(DocumentPath), Get(PreferencesPath), and Get(SystemDrive). By using this suite of new functions, along with the new dynamic file path capability, you should now be able to save files with custom filenames to a wide variety of locations on a user's disk.

Viewing Your Variables

One final note on variables in FileMaker 8. We've made the point a few times that variables are beneficial in that they don't add clutter to the database schema: They don't appear in Define Database dialog, nor in the field lists that go along with operations such as Sort or Import Records. There's a disadvantage to this as well: There's currently no way to see a list of all the variables that are currently active in a FileMaker solution.

It is possible to view the values of individual variables in the FileMaker Pro Advanced Data Viewer, but you must enter the variable names one at a time, as with any other expression.

For more on the Data Viewer, see "Debugging Scripts," p. 517.



Part I: Getting Started with FileMaker 8

FileMaker Overview

Using FileMaker Pro

Defining and Working with Fields

Working with Layouts

Part II: Developing Solutions with FileMaker

Relational Database Design

Working with Multiple Tables

Working with Relationships

Getting Started with Calculations

Getting Started with Scripting

Getting Started with Reporting

Part III: Developer Techniques

Developing for Multiuser Deployment

Implementing Security

Advanced Interface Techniques

Advanced Calculation Techniques

Advanced Scripting Techniques

Advanced Portal Techniques

Debugging and Troubleshooting

Converting Systems from Previous Versions of FileMaker Pro

Part IV: Data Integration and Publishing

Importing Data into FileMaker Pro

Exporting Data from FileMaker

Instant Web Publishing

FileMaker and Web Services

Custom Web Publishing

Part V: Deploying a FileMaker Solution

Deploying and Extending FileMaker

FileMaker Server and Server Advanced

FileMaker Mobile

Documenting Your FileMaker Solutions



Using FileMaker 8
Special Edition Using FileMaker 8
ISBN: 0789735121
EAN: 2147483647
Year: 2007
Pages: 296

Similar book on Amazon

Flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net