As you have seen, Flash Remoting makes it really easy to create ColdFusion pages that supply information to Flash, or perform whatever other type of processing you want to trigger from movies playing in the Flash Player. Just think of each directory that contains such ColdFusion pages as a service, and of each individual page as a service function. Flash Remoting also makes it possible to use ColdFusion Components to supply information or other server-side processing to Flash. Nearly everything you do on the Flash side of things is exactly the same. The only difference is that each CFC constitutes a service, and each of the CFC's methods constitutes service functions. In other words, you can think of a service as a collection of functions. Whether you want to write those functions as pages in a directory or as methods of a CFC is up to you. Of course, if you go the CFC route, you get all the other benefits of CFCs for free, including automatic documentation and integration with Dreamweaver. But the greatest benefit of going the CFC route is the fact that your CFCs can be used internally by your ColdFusion pages (via the <cfinvoke> tag) or as Web Services, as well as by your Flash applications. See Chapter 22 for details about ColdFusion Components. NOTE I am talking about ColdFusion Components, special CFML code files executed on the server. ColdFusion Components are completely different from what Flash calls components; the latter show up in the Components panel in Flash and usually present themselves visually within the player.
I am assuming that you have already read about ColdFusion Components in Chapter 22. If not, you might want to glance at that chapter before continuing here. Or you can just keep reading to get a crash course in CFCs. ColdFusion Components as ServicesTo demonstrate how easy it is to use ColdFusion Components in your Flash applications, you will now create a CFC that takes the place of the ColdFusion pages used by the Merchandise Browser example in the previous section. The Merchandise Browser calls two ColdFusion pages as service functions: MerchRecordsetProvider.cfm (Listing 26.4) and MerchDetailProvider.cfm (Listing 26.8). Listing 26.9 creates a new ColdFusion Component called MerchProviderCFC which can be used instead. The component exposes two methods called MerchRecordsetProvider() and MerchDetailProvider() that correspond to the two ColdFusion pages already in place. Listing 26.9. MerchProviderCFC.cfcA CFC That Supplies Data to Flash, ColdFusion, or Other<!--- Filename: MerchProviderCFC.cfc Author: Nate Weiss (NMW) Purpose: Creates a ColdFusion Component that supplies data about products ---> <cfcomponent hint="Provides data about merchandise records." output="false"> <!--- getMerchList() function ---> <cffunction name="merchRecordsetProvider" returnType="query" access="remote" hint="Returns a recordset of all products in the Merchandise table." output="false"> <cfset var merchQuery = ""> <!--- Query the database for merchandise records ---> <cfquery name="merchQuery" datasource="ows"> SELECT MerchID, MerchName FROM Merchandise ORDER BY MerchName </cfquery> <!--- Return the query ---> <cfreturn merchQuery> </cffunction> <!--- merchDetailProvider() function ---> <cffunction name="merchDetailProvider" returnType="query" access="remote" hint="Returns details about a particular item in the Merchandise table." output="false"> <!--- MerchID argument (required) ---> <cfargument name="merchID" type="numeric" required="Yes" hint="The ID number of the desired Merchandise record."> <cfset var merchQuery = ""> <!--- Query the database for merchandise records ---> <cfquery name="merchQuery" datasource="ows" maxrows="1"> SELECT MerchID, MerchName, MerchDescription, ImageNameSmall, MerchPrice FROM Merchandise WHERE MerchID = #ARGUMENTS.merchID# </cfquery> <!--- Format the MerchPrice column in the appropriate currency format ---> <!--- (It's easier to do this with ColdFusion than with ActionScript) ---> <cfset merchQuery.lerchPrice = lsCurrencyFormat(merchQuery.MerchPrice)> <!--- Return the query ---> <cfreturn merchQuery> </cffunction> </cfcomponent>
Only methods that use access="Remote in their <cffunction> blocks are accessible to Flash Remoting. See Chapter 22 for details. If you compare the first <cffunction> block in this listing to the code in Listing 26.4, you will see that it's almost identical. The same query is run to get information about products from the database. The only difference is how the query is returned: instead of returning it specifically to the Flash Player with FLASH.feturn, this code returns it to whatever program is calling the method with the <cfreturn> tag. In other words, the two versions of the code are the same, except that the CFC version isn't coded specifically for Flash, which means you get the bonus of being able to use this method internally within your ColdFusion pages. The access="Remote" attribute means the method can also be accessed as a Web Service. The same goes for the second <cffunction> block; it's nearly identical to Listing 26.8, the ColdFusion page on which it is based. Instead of expecting a parameter called merchID to be passed from the Flash Player specifically, it simply expects that an argument named merchID be passed to the method, whether it's called by Flash, from a ColdFusion page via the <cfinvoke> tag, or by some other means. See Chapter 22 for further discussion of CFC concepts, and for details about <cffunction>, <cfargument>, and <cfreturn>. Calling CFC MethodsOnce the CFC in Listing 26.9 is in place, it's easy to use the component in your Flash applications. Just how easy, you ask? Well, to make the Merchandise Browser example use the new component to get its data instead of the ad-hoc ColdFusion pages it used previously, you change just one line of code. Go back to the code for the first frame of the MerchBrowser.fla example (Listing 26.5) and change this line: myService = gateway_conn.getService("ows.23", this); to this: myService = gateway_conn.getService("ows.23.MerchProviderCFC", this); That's it! You can now publish or test the movie again, and it will behave in exactly the same way it did before. As you can see, to create a service reference to a CFC, you simply refer to the CFC by name (that is, the filename without the .cfc extension). You specify the path to the CFC file's location in exactly the same way as you would with the <cfinvoke> tag, by using dots to separate the folder names in the path (rather than slashes). Once you've created the service reference variable, you can call its service functions (that is, the CFC's methods) by calling each function as a method of the variable, just as you did before. So, to call the MerchRecordsetProvider() method of the CFC in Listing 26.9, you can continue using the following line of code: myService.MerchRecordsetProvider(); To call the MerchDetailProvider() method of the CFC and provide the MerchID parameter, you can use this line, which is also unchanged from the original version in Listing 26.5: myService.MerchDetailProvider({MerchID:MerchListBox.getValue()}); Of course, if you were to change the name of this CFC method to getMerchDetails(), say, you would simply change the function call accordingly, like so: myService.getMerchDetails({MerchID:MerchListBox.getValue()}); NOTE You would also need to change the name of the event handler that executes when the data is received. Instead of MerchDetailProvider_Result, you would name it getMerchDetails_Result. Instantiated CFCsFlash Remoting doesn't provide a mechanism for directly accessing components stored in the APPLICATION or SESSION scopes as discussed in Chapter 23. When you call a method as a Flash service function, you are always calling the method statically, not via an instance of the component. This doesn't mean you have to rule out the idea of instance-based components in your Flash-based applications entirely, however. Listing 26.10 creates a ColdFusion Component called CallShoppingCartCFC. It exposes two methods to Flash: addItem() and getItemCount(). Within the CFC code, each of these methods interacts with an instance of the ShoppingCart CFC from Chapter 28, "Online Commerce."
I am assuming that you have already copied all the listings for Chapter 28 from the CD-ROM to the ows/28 folder on your ColdFusion server. If not, please do so now. See Chapter 28 for details on how the ShoppingCart component works internally. In other words, the CFC in Listing 26.10 is a wrapper around the session-based instance of the Shopping Cart component. This means ColdFusion pages can use the cart instance, and you can still expose it to Flash via the wrapper component. Listing 26.10. CallShoppingCartCFC.cfcUsing a Session-Based CFC Instance<cfcomponent output="false"> <!--- addItem() function ---> <cffunction name="addItem" access="remote" output="false" returnType="void" hint="Adds an item to the session's shopping cart."> <!--- Required argument: MerchID ---> <cfargument name="merchID" type="numeric" required="Yes"> <!--- Call the Add() method of the ShoppingCart CFC ---> <cfinvoke component="#SESSION.myShoppingCart#" method="add" merch> </cffunction> <!--- getItemCount() function ---> <cffunction name="getItemCount" returnType="numeric" access="Remote" output="false"> <cfset var cartContents = ""> <cfset var getCount = ""> <!--- Call the List() method of the ShoppingCart CFC ---> <cfinvoke component="#SESSION.myShoppingCart#" method="list" returnVariable="cartContents"> <!--- Use Query-of-Queries to get the number of items in cart ---> <cfquery dbtype="query" name="getCount"> SELECT SUM(Quantity) AS ItemCount FROM CartContents </cfquery> <!--- Return the total number of items to Flash ---> <cfreturn val(getCount.ItemCount)> </cffunction> </cfcomponent> NOTE To make this CFC work, you need to enable session variables and place the MyShoppingCart instance of the ShoppingCart.cfc component in the SESSION scope. The Application.cfc file included with this chapter's listings provides the needed code.. The CD-ROM for this book offers another version of the Merchandise Browser movie. The filename is MerchBrowserCart.fla. Visually, this version is exactly the same as the first one (MerchBrowser.fla), except that there is now a black Shopping Cart button in the upper right corner (Figure 26.10). Additionally, the Add To Cart button in the detail view for each product now works as expected (it was not operational in the original version). The ActionScript code in the movie is the same as the previous version (Listing 26.5), except for a small number of additions. The code in the first frame of the new movie is shown in Listing 26.11. Listing 26.11. ActionScript Code in the First Frame of MerchBrowserCart.fla// Include support for Flash Remoting Components #include "NetServices.as" // uncomment this line when you want to use the NetConnect debugger // #include "NetDebug.as" // -------------------------------------------------- // Handlers for user interaction events // -------------------------------------------------- // -------------------------------------------------- // Application initialization // -------------------------------------------------- if (inited == null) { // do this code only once inited = true; // set the default gateway URL (this is used only in authoring) NetServices.setDefaultGatewayUrl("http://localhost:8501/flashservices/gateway") // connect to the gateway gateway_conn = NetServices.createGatewayConnection(); // get a reference to a service // In this case, the "service" is the MerchProviderCFC component myService = gateway_conn.getService("ows.26.MerchProviderCFC", this); cartService = gateway_conn.getService("ows.26.CallShoppingCartCFC", this); // Call the service function that fills the ListBox with a list // of products (from ColdFusion) for the user to browse through myService.MerchRecordsetProvider(); } // This function executes when the user selects an item in the ListBox function MerchListBox_Changed() { // If this is the first time an item has been selected, // go straight to the frame that loads the detail information if (_currentFrame == 1) { gotoAndPlay("EndSlideOut"); // Otherwise, go to the frame that slides the display back in (hides it) // When it finishes sliding, it will load the detail information } else { gotoAndPlay("StartSlideOut"); } } // This function retrieves the detail information about the selected product. // It's executed when the last frame of the movie is reached // (when the detail view has finished hiding itself under the product list) function getSelectedItemDetails() { myService.MerchDetailProvider({MerchID:MerchListBox.getValue()}); } // -------------------------------------------------- // Handlers for data coming in from server // -------------------------------------------------- function MerchRecordsetProvider_Result(result) { // First, remove any existing items from the list box MerchListBox.removeAll(); //DataGlue.bindFormatStrings (MerchListBox, result, "#MerchName#", "#MerchID#"); // For each record in the recordset... for (var i = 0; i < result.getLength(); i++) { // Use the record variable to refer to the current row of recordset var record = result.getItemAt(i); // Add item to the MerchListBox widget, which is like a <SELECT> in HTML MerchListBox.addItem(record.MerchName, record.MerchID); }; } // This executes when a merchandise detail record has been received function MerchDetailProvider_Result(result) { // The result variable is a recordset that contains just one row // The detailRecord variable will represent the row of data var detailRecord = result.getItemAt(0); // Display detail information in text boxes _root.TitleTextBox.text = detailRecord.MerchName; _root.DescriptionTextBox.text = detailRecord.MerchDescription; _root.PriceTextBox.text = "Price: " + detailRecord.MerchPrice; // If the ImageNameSmall column contains an image filename, display it if (detailRecord.ImageNameSmall.length > 0) { // Load and display the product image loadMovie("../images/" + detailRecord.ImageNameSmall, _root.ImageMovie); // Hide the OWS logo OWSLogo._visible = false; // If there is no image file for this record, display the OWS logo instead } else { // Unload any product image that might already be showing unloadMovie(_root.ImageMovie); // Make the OWS logo visible OWSLogo._visible = true; } // Now that the information about the merchandise has been placed, // make the display slide back into view, revealing the information gotoAndPlay("StartSlideIn"); } // This function updates the Number Of Items display for the cart function refreshCart() { // Use Flash Remoting to get the number of items in cart // When the number has been retrieved, execution will continue // in the GetItemCount_Result() function, below cartService.GetItemCount(); }; // This executes when the number of items in the cart is received function GetItemCount_Result(result) { CartItemCount = "Items: " + result; }; // This executes when a user uses the Add To Cart button function addSelectedItemToCart() { cartService.AddItem({MerchID:MerchListBox.getValue()}); } // This executes after an item has been added to the cart function AddItem_Result(result) { // Show the new number of items in the cart refreshCart(); } // Show the number of items in the user's cart now refreshCart(); // Stop here, so animation doesn't occur until user selects a product stop(); Near the top of the template, a new Flash Remoting service object is created, called cart Service. This object represents the CallShoppingCartCFC component created in Listing 26.10. This is in addition to the myService object already being used to connect to the MerchProviderCFC component from Listing 26.9. I can call CallShoppingCartCFC methods using cartService; I will continue to call the other methods using myService. In addition, several new functions have been added near the bottom of the listing, calledrefreshCart(), GetItemCount_Result(), addSelectedItemToCart(), and AddItem_Result(). Note that refreshCart() is called right away, just before the stop() command. Aside from the code in Listing 26.11, the following code has been added to the Add To Cart button in the DetailUI layer: on (release) { addSelectedItemToCart(); } Finally, the following code has been added to the Shopping Cart button at the upper right corner, in a new layer called CartUI: on (release) { getURL("../28/StoreCart.cfm"); } When this version of the movie first appears, the refreshCart() function in Listing 26.11 executes (in addition to all the other code that executes in the original version of the movie). Inside refreshCart(), the cartService.GetItemCount() service function is called, triggering the GetItemCount() method on the ColdFusion server (see Listing 26.10). When the server returns its response, which is the number of items in the current session's shopping cart, the GetItemCount_Result() event handler executes. Within GetItemCount_Result(), the Flash variable called CartItemCount is updated with the current number of items. If the user clicks the Add To Cart button (refer to Figure 26.10), the addSelectedItemToCart() function is called. Within addSelectedItemToCart(), the cartService.AddItem() service method is called, executing the AddItem() CFC method from Listing 26.10. When the server responds, the AddItem_Result() event handler executes, calling the refreshCart() method to make sure the new number of items in the user's cart is correctly reflected. The user can go to the HTML version of the shopping cart (created in Chapter 28) by clicking the Shopping Cart button in the upper right corner. This causes the browser to navigate to the StoreCart.cfm page (from Chapter 28), where the user can check out, remove items, update quantities, or continue shopping. A neat thing about this application is that it proves that both the Flash player and normal ColdFusion pages can use the same SESSION scope. If you make changes in the HTML version of the cart, the Flash movie will reflect them, and vice versa. This is because the Shopping Cart CFC, and thus the THIS scope used internally by the component, is maintained in the SESSION scope. |