<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The FileMaker Collective &#187; FM8.5</title>
	<atom:link href="http://fmcollective.com/category/fm85/feed/" rel="self" type="application/rss+xml" />
	<link>http://fmcollective.com</link>
	<description>Syndicating the best FileMaker blogs</description>
	<lastBuildDate>Tue, 27 Jul 2010 15:42:45 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.3</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Google Mapping Part Deux (Multiple Addresses)</title>
		<link>http://fmcollective.com/2007/09/05/google-mapping-part-deux-multiple-addresses/</link>
		<comments>http://fmcollective.com/2007/09/05/google-mapping-part-deux-multiple-addresses/#comments</comments>
		<pubDate>Thu, 06 Sep 2007 01:34:19 +0000</pubDate>
		<dc:creator>mike.lee</dc:creator>
				<category><![CDATA[FM8.5]]></category>
		<category><![CDATA[FM9]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">http://fmcollective.com/2007/09/05/google-mapping-part-deux-multiple-addresses/</guid>
		<description><![CDATA[In my first post on this topic, I showed you how to create a simple, API-driven Google Map directly within your FileMaker Pro database.  Today, I&#8217;ll be taking that one step further.  In the previous example, you were limited to mapping one address at a time.  In this example, I&#8217;ll show you [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a href="/?p=43">first post on this topic</a>, I showed you how to create a simple, API-driven Google Map directly within your FileMaker Pro database.  Today, I&#8217;ll be taking that one step further.  In the previous example, you were limited to mapping one address at a time.  In this example, I&#8217;ll show you how to produce maps with multiple addresses at once.</p>
<p><a href="http://fmcollective.com/wp-content/uploads/2007/09/picture-3.png" title="Example of Multi-address mapping"><img src="http://fmcollective.com/wp-content/uploads/2007/09/picture-3.png" alt="Example of Multi-address mapping" height="419" width="495" /></a></p>
<p><span id="more-88"></span></p>
<h2>Step One</h2>
<p>Step one, of course, is to read the <a href="/?p=43">original post</a>.  Familiarize yourself with the concepts.  Is essence, we&#8217;re leveraging PHP to create a javascript page which displays the map in a FileMaker Web Viewer.  In the original post, we used the <a href="http://www.phpclasses.org/browse/package/3801.html" title="Easy Google Map" target="_blank">Easy Google Map</a> PHP class, and we&#8217;ll do the same here.  You&#8217;ll also need a <a href="http://www.google.com/apis/maps/" title="Google Maps API">Google Maps API key</a> if you wish to run this on your own server.</p>
<p>This example will be staged at <a href="http://etc.proofgroup.com/fmcollective/" target="_blank">http://etc.proofgroup.com/fmcollective/</a>.  The Easy Google Map PHP class will be hosted here <a href="http://etc.proofgroup.com/fmcollective/EasyGoogleMap.class.php" target="_blank">http://etc.proofgroup.com/fmcollective/EasyGoogleMap.class.php</a>.  Neither of these links will prove very useful to you on their own, but they will be instrumental later when I build the actual application.</p>
<p>You will need a complementary PHP file to translate the FileMaker request (a GET request via HTTP) to the Easy Google Map class.  This is where it gets just a little bit tricky.  First off, how should we send multiple addresses via a GET HTTP request?</p>
<p>Perhaps something like this:</p>
<blockquote><p><code>http://DOMAIN/MYPHPFILE.PHP?</code><code>addr1=1st_Address</code><code>&amp;addr2=2nd_Address</code></p>
</blockquote>
<p>But I can see all sorts of trouble with that, not the least of which is that it involves an ever-growing number of parameters (one for every address we want to map).  It&#8217;s also not very PHP friendly.  With some research and testing, I settled on using a PHP Array.  PHP Arrays are very nice indeed.  The only problem, how to create a PHP Array (a complex data structure) in FileMaker and then transmit it to the complementary PHP file?  It turns out, PHP has a solution for that, too.  It&#8217;s called a <a href="http://www.php.net/serialize" title="Serialized Array" target="_blank">Serialized Array</a>.  According to the PHP manual, &#8220;This is useful for storing or passing PHP values around without    losing their type and structure.&#8221;  I like it!</p>
<p>Serialized arrays are strings which look something like this:</p>
<blockquote><p><code>a:2:{i:0;s:3:"foo";i:1;s:3:"bar";}</code></p>
</blockquote>
<p>That&#8217;s a 2-item array, the first item is &#8220;foo&#8221; (index 0) and the second item is &#8220;bar&#8221; (index 1).</p>
<p>Here&#8217;s my concept: serialize the data (manually or via custom function) in FileMaker, pass the string to the PHP, unserialize it there (turning it into a full-fledged array), and using the native PHP array to build the map data points via looping through the array items.</p>
<h2>The Details</h2>
<p>I mentioned a custom function above.  I&#8217;ll need a custom function to translate a carriage-return separated list of data, such as this:</p>
<blockquote><p><code>One<br />
Two<br />
Three</code></p>
</blockquote>
<p>Into this:</p>
<blockquote><p><code>a:3:{i:0;s:3:"One";i:1;s:3:"Two";i:2;s:5:"Three";}</code></p>
</blockquote>
<p>I wrote a recursive custom function, called cfSerializeData, which is the following:</p>
<blockquote><p><code>/*</code></p>
<p>By: Mike Lee<br />
Date: 4 May 2007<br />
Version: 1<br />
Fxn Name: cfSerializeData<br />
Parameter: &#8216;values&#8217; &#8211; a carriage-return delimited list of values that you want to turn into a PHP serialized array of data<br />
Description: This is a recursive function that takes a list of data in &#8216;Values&#8217; and turns it into a serialized array for use<br />
within PHP (see serialize() and unserialize() in the PHP documentation).  This can be useful for passing lists of data to<br />
a PHP function&#8211;either through HTTP calls or the PHP plugin.</p>
<p>Example Input: One¶Two¶Three<br />
Example Result: a:3:{i:0;s:3:&#8221;One&#8221;;i:1;s:3:&#8221;Two&#8221;;i:2;s:5:&#8221;Three&#8221;;}</p>
<p>*/</p>
<p>Let(<br />
[<br />
//Set variables<br />
$NumItems = Case( IsEmpty( $NumItems ) or $NumItems=&#8221;0&#8243; ; ValueCount( Values ) ; $NumItems );<br />
i = ValueCount( Values ) - 1;<br />
lastItem = RightValues(values;1);<br />
lastItem = Left(lastItem;Length(lastItem)-1);<br />
remainder = LeftValues(values;ValueCount(values)-1);<br />
headertxt = &#8220;a:&#8221; &amp; $NumItems &amp; &#8220;:{&#8221;;<br />
footertxt = Case(i+1=$NumItems;&#8221;}&#8221;)<br />
]<br />
;</p>
<p>//If remainder is not empty recurse, else clear the variable and write the header txt<br />
Case( not IsEmpty( remainder );cfSerializeData( remainder );Let( $NumItems = $null ; headertxt ))</p>
<p>&amp;</p>
<p>//Actual serialized data<br />
&#8220;i:&#8221; &amp; i &amp; &#8220;;s:&#8221; &amp; Length(lastItem) &amp; &#8220;:\&#8221;&#8221; &amp; lastItem &amp; &#8220;\&#8221;;&#8221; &amp;</p>
<p>//Write footer txt (built-in conditional)<br />
footertxt</p>
<p>)</p>
</blockquote>
<p>You can then use that custom function, or, if you don&#8217;t have FileMaker Pro Advanced, some form of script, to turn a list of addresses into a serialized array of addresses suitable for PHP.</p>
<p>List of addresses:</p>
<blockquote><p><code>1 Any Street, Anytown, Anystate, 12345<br />
2 Any Street, Anytown, Anystate, 12345<br />
3 Any Street, Anytown, Anystate, 12345<br />
4 Any Street, Anytown, Anystate, 12345</code></p>
</blockquote>
<p>Serialized array of addresses:</p>
<blockquote><p><code>a:4:{i:0;s:38:"1 Any Street, Anytown, Anystate, 12345";i:1;s:38:"2 Any Street, Anytown, Anystate, 12345";i:2;s:38:"3 Any Street, Anytown, Anystate, 12345";i:3;s:38:"4 Any Street, Anytown, Anystate, 12345";}</code></p>
</blockquote>
<h2>The Complementary PHP file</h2>
<p>All this talk about serialized arrays and custom functions and I almost forgot to say that you&#8217;ll also need a suitable, complementary PHP file to accept the request and turn it into the Google Maps request.  This is the file I&#8217;ve written, hosted at <a href="http://etc.proofgroup.com/fmcollective/googlemaparray.php" target="_blank">http://etc.proofgroup.com/fmcollective/googlemaparray.php</a>:</p>
<blockquote><p><code>&lt;?php</code></p>
<p><code>/*	File Name: googlemaparray.php<br />
File URI: http://etc.proofgroup.com/fmcollective/googlemap.php<br />
Description: Google Map API wrapper script<br />
Version: 1.1<br />
Author: Mike Lee, The Proof Group LLC<br />
Author URI: http://www.proofgroup.com<br />
*<br />
* Copyright (c) 2007-2008, The Proof Group LLC<br />
* All rights reserved.<br />
*<br />
* Redistribution and use in source and binary forms, with or without<br />
* modification, are permitted provided that the following conditions are met:<br />
* * Redistributions of source code must retain the above copyright<br />
* notice, this list of conditions and the following disclaimer.<br />
* * Redistributions in any form must reproduce the above copyright<br />
* notice, this list of conditions and the following disclaimer in the<br />
* documentation and/or other materials provided with the distribution.<br />
* * Neither the name of The Proof Group LLC nor the<br />
* names of its contributors may be used to endorse or promote products<br />
* derived from this software without specific prior written permission.<br />
*<br />
* THIS SOFTWARE IS PROVIDED BY THE PROOF GROUP LLC ``AS IS'' AND ANY<br />
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED<br />
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE<br />
* DISCLAIMED. IN NO EVENT SHALL &lt;copyright holder&gt; BE LIABLE FOR ANY<br />
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES<br />
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;<br />
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND<br />
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT<br />
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS<br />
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br />
*/</code></p>
<p><code>require 'EasyGoogleMap.class.php';</code></p>
<p><code>//Google Maps API Key<br />
$googlemaps_api_key = "XXX-XXX-XXX-INSERT-YOUR-KEY-HERE";</code></p>
<p>//Get the &#8216;addr&#8217; parameter from the GET request<br />
$addrarray = $_GET[&#8217;addr&#8217;];<br />
$addrarray = stripslashes($addrarray);</p>
<p>$addrarray = unserialize($addrarray);</p>
<p>$gm = &amp; new EasyGoogleMap($googlemaps_api_key);</p>
<p># Set address point(s)<br />
foreach( $addrarray as $key =&gt; $value){<br />
$gm-&gt;SetAddress($value);<br />
}</p>
<p># To Enable/Disable Map Type (Map/Satellite/Hybrid)<br />
$gm-&gt;mMapType = TRUE;</p>
<p># Set map size<br />
$gm-&gt;SetMapWidth(&#8217;700&#8242;);<br />
$gm-&gt;SetMapHeight(&#8217;500&#8242;);</p>
<p># Set map zoom<br />
$gm-&gt;SetMapZoom(8);</p>
<p><code></code><code></code><code>?&gt;<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&lt;title&gt;The Proof Group: Google Map Array API Example&lt;/title&gt;<br />
&lt;?php echo $gm-&gt;GmapsKey(); ?&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&lt;center&gt;<br />
&lt;?php<br />
echo $gm-&gt;MapHolder();<br />
echo $gm-&gt;InitJs();<br />
echo $gm-&gt;UnloadMap();<br />
?&gt;<br />
&lt;font face="arial, helvetica, verdana, sans-serif" size="-1"&gt;<br />
Google Maps Array API Example hosted by &lt;a href="http://www.proofgroup.com"&gt;The Proof Group&lt;/a&gt;.&lt;br&gt;<br />
See the original post on this topic at &lt;a href="http://fmcollective.com/?p=88"&gt;The FileMaker Collective&lt;/a&gt; for more information.&lt;p&gt;<br />
&lt;/center&gt;<br />
&lt;/font&gt;<br />
&lt;font face="arial, helvetica, verdana, sans-serif" size="-2"&gt;<br />
Terms of Use: Thank you for using &lt;a href="http://www.proofgroup.com"&gt;The Proof Group&lt;/a&gt; Google Maps API. (1) You may not use this API for commercial purposes (2) Use of this API is limited to 100 requests per IP per day (3) You are subject to all terms and conditions of the Google Maps API Terms of Use, &lt;a href="http://www.google.com/apis/maps/terms.html"&gt;<br />
http://www.google.com/apis/maps/terms.html&lt;/a&gt;.<br />
&lt;/font&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;</code></p>
</blockquote>
<p>The important part is the &#8216;foreach&#8217;, <code>foreach( $addrarray as $key =&gt; $value) {$gm-&gt;SetAddress($value);}</code>, which loops through the array and adds all the addresses as individual map points.  This is really the only major difference betweent he single-point mapping PHP file and this one.</p>
<h2>What of FileMaker</h2>
<p>How does this work from within FileMaker?  Essentially, using a list of addresses, you loop through the addresses and capture them to a carriage-return delimited list &#8211; the old <code>SetField(LIST;LIST &amp; myAddress &amp; ¶)</code> trick.</p>
<p>Once you&#8217;ve got the list, you&#8217;ll <em>serialize</em> it using the custom function &#8211; <code>SetField(ARRAY;cfSerializeData(LIST))</code>.</p>
<p>Then, it&#8217;s just a matter of calling the correct URL from within the Web Viewer:</p>
<blockquote><p><code>http://etc.proofgroup.com/fmcollective/googlemaparray.php?addr=ARRAY</code></p>
</blockquote>
<p>First, in FileMaker, you need a table of address data.  Here I&#8217;m using some <em>really</em> awful, made-up addresses:<img src="http://fmcollective.com/wp-content/uploads/2007/09/picture-1-copy.png" alt="Table of Addresses" /></p>
<p>I&#8217;ve also created a Globals table, with the fields: ARRAY, LIST, and URL (all of which are text, globals).</p>
<p>In layout mode, add a Web Viewer (here, in an enlarged header part), point it to the Globals::URL field and name it &#8216;wv&#8217; in the object information floating window:</p>
<p><img src="http://fmcollective.com/wp-content/uploads/2007/09/picture-4.png" alt="Mapping in Layout Mode" /></p>
<p>Within FileMaker, I wrapped the entire thing into a Script called &#8220;Update Map With Found Set&#8221;, a screenshot of which follows:</p>
<p><img src="http://fmcollective.com/wp-content/uploads/2007/09/picture-2.png" title="Update Map With Found Set Script" alt="Update Map With Found Set Script" /></p>
<p>For convenience, I also attached this script to a button on the layout to update the Web Viewer.  Back in browse, get a found set (more about that later), and press the button:</p>
<p><img src="http://fmcollective.com/wp-content/uploads/2007/09/picture-3.png" title="Example of Multi-address mapping" alt="Example of Multi-address mapping" /></p>
<p>For a found set of 25 records, the request URL will look something like this (pardon the mess):</p>
<blockquote><p><a href="http://etc.proofgroup.com/fmcollective/googlemaparray.php?addr=a:25:{i:0;s:35:%22Main%20Street,%20Wallingford,%20CT,%2006492%22;i:1;s:34:%22Main%20Street,%20New%20Canaan,%20CT,%2008640%22;i:2;s:34:%22Main%20Street,%20Manchester,%20CT,%2006042%22;i:3;s:34:%22Main%20Street,%20Ridgefield,%20CT,%2006877%22;i:4;s:33:%22Main%20Street,%20Riverside,%20CT,%2006878%22;i:5;s:33:%22Main%20Street,%20Greenwich,%20CT,%2006830%22;i:6;s:28:%22Main%20Street,%20Lyme,%20CT,%2006371%22;i:7;s:31:%22Main%20Street,%20Cos%20Cob,%20CT,%2006807%22;i:8;s:34:%22Main%20Street,%20Stonington,%20CT,%2006378%22;i:9;s:31:%22Main%20Street,%20Madison,%20CT,%2006443%22;i:10;s:35:%22Main%20Street,%20New%20Britain,%20CT,%2006053%22;i:11;s:34:%22Main%20Street,%20Farmington,%20CT,%2006032%22;i:12;s:30:%22Main%20Street,%20Darien,%20CT,%2006820%22;i:13;s:35:%22Main%20Street,%20Wallingford,%20CT,%2006492%22;i:14;s:32:%22Main%20Street,%20Westport,%20CT,%2006880%22;i:15;s:31:%22Main%20Street,%20Milford,%20CT,%2006460%22;i:16;s:32:%22Main%20Street,%20Simsbury,%20CT,%2006070%22;i:17;s:32:%22Main%20Street,%20Rowayton,%20CT,%2006853%22;i:18;s:29:%22Main%20Street,%20Essex,%20CT,%2006426%22;i:19;s:32:%22Main%20Street,%20Stamford,%20CT,%2006902%22;i:20;s:37:%22Main%20Street,%20West%20Hartford,%20CT,%2006110%22;i:21;s:35:%22Main%20Street,%20Wallingford,%20CT,%2006492%22;i:22;s:33:%22Main%20Street,%20Greenwich,%20CT,%2006830%22;i:23;s:30:%22Main%20Street,%20Orange,%20CT,%2006477%22;i:24;s:40:%22Main%20Street,%20Vernon%20Rockville,%20CT,%2006066%22;}" target="_blank">http://etc.proofgroup.com/fmcollective/googlemaparray.php?addr=a:25:{i:0;s:35:&#8221;Main Street, Wallingford, CT, 06492&#8243;;i:1;s:34:&#8221;Main Street, New Canaan, CT, 08640&#8243;;i:2;s:34:&#8221;Main Street, Manchester, CT, 06042&#8243;;i:3;s:34:&#8221;Main Street, Ridgefield, CT, 06877&#8243;;i:4;s:33:&#8221;Main Street, Riverside, CT, 06878&#8243;;i:5;s:33:&#8221;Main Street, Greenwich, CT, 06830&#8243;;i:6;s:28:&#8221;Main Street, Lyme, CT, 06371&#8243;;i:7;s:31:&#8221;Main Street, Cos Cob, CT, 06807&#8243;;i:8;s:34:&#8221;Main Street, Stonington, CT, 06378&#8243;;i:9;s:31:&#8221;Main Street, Madison, CT, 06443&#8243;;i:10;s:35:&#8221;Main Street, New Britain, CT, 06053&#8243;;i:11;s:34:&#8221;Main Street, Farmington, CT, 06032&#8243;;i:12;s:30:&#8221;Main Street, Darien, CT, 06820&#8243;;i:13;s:35:&#8221;Main Street, Wallingford, CT, 06492&#8243;;i:14;s:32:&#8221;Main Street, Westport, CT, 06880&#8243;;i:15;s:31:&#8221;Main Street, Milford, CT, 06460&#8243;;i:16;s:32:&#8221;Main Street, Simsbury, CT, 06070&#8243;;i:17;s:32:&#8221;Main Street, Rowayton, CT, 06853&#8243;;i:18;s:29:&#8221;Main Street, Essex, CT, 06426&#8243;;i:19;s:32:&#8221;Main Street, Stamford, CT, 06902&#8243;;i:20;s:37:&#8221;Main Street, West Hartford, CT, 06110&#8243;;i:21;s:35:&#8221;Main Street, Wallingford, CT, 06492&#8243;;i:22;s:33:&#8221;Main Street, Greenwich, CT, 06830&#8243;;i:23;s:30:&#8221;Main Street, Orange, CT, 06477&#8243;;i:24;s:40:&#8221;Main Street, Vernon Rockville, CT, 06066&#8243;;}</a></p>
</blockquote>
<h2>What could go wrong?</h2>
<p>There&#8217;s one problem with this technique.  Here&#8217;s how to reproduce the issue.  Show all records and update the map.  With all 177 records showing, the Web Viewer map should fail and the following should be shown:</p>
<blockquote><p> Request-URI Too Large</p>
<p>The requested URL&#8217;s length exceeds the capacity limit for this server</p>
</blockquote>
<p>I&#8217;m no Apache expert, but I know this is based on some form of compile-time configuration and is specific to a GET request.  Since the Web Viewer only allows me to use GET requests, we have this upper limit issue (somewhere around 100 records in this example).  Alternatively, you can re-compile Apache, but I&#8217;ll let you figure that one out.</p>
<p>The solution, of course, is to use POST, but I&#8217;ll leave that as an exercise for the reader.  Hint: you may have to do things completely differently and FM9 helps.</p>
<p>By the way, once you add &#8220;Labels&#8221; (one for each address, for example to show demographic info) and other display niceties (e.g. varying marker icons or colors) to your request URL, the maximum number of addresses you can map will plummet.  When I&#8217;ve fleshed this out, the max easily drops to below 50 records.</p>
<p>Do have fun and let me know what you think in the comments.</p>
<p>You can download a zipped copy of the example file <a href="http://fmcollective.com/wp-content/uploads/2007/09/mapping_fmcollectivefp7.zip" title="Mapping example file (zipped FP7 file)">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://fmcollective.com/2007/09/05/google-mapping-part-deux-multiple-addresses/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Google Mapping in FileMaker</title>
		<link>http://fmcollective.com/2007/05/23/google-mapping-in-filemaker/</link>
		<comments>http://fmcollective.com/2007/05/23/google-mapping-in-filemaker/#comments</comments>
		<pubDate>Wed, 23 May 2007 17:48:10 +0000</pubDate>
		<dc:creator>mike.lee</dc:creator>
				<category><![CDATA[FM8.5]]></category>
		<category><![CDATA[FM9]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">http://fmcollective.com/?p=43</guid>
		<description><![CDATA[UPDATE: I&#8217;ve written a follow up to this post which shows how to produce a map with multiple addresses.
Google Mapping in FileMaker
I&#8217;m sure you&#8217;ve seen the Web Viewer maps in FileMaker.  Sure, they&#8217;re serviceable, but you&#8217;ve got no control.  And with Google recently adding &#8220;Search Results&#8221; and &#8220;My Maps&#8221; to the screen as [...]]]></description>
			<content:encoded><![CDATA[<p>UPDATE: I&#8217;ve written a <a href="/?p=88" title="Multi-address mapping">follow up to this post</a> which shows how to produce a map with multiple addresses.</p>
<h2>Google Mapping in FileMaker</h2>
<p>I&#8217;m sure you&#8217;ve seen the Web Viewer maps in FileMaker.  Sure, they&#8217;re serviceable, but you&#8217;ve got no control.  And with Google recently adding &#8220;Search Results&#8221; and &#8220;My Maps&#8221; to the screen as well (a laudable feature, to be sure), the available real estate for the actual map shrunk by almost half.  What can be done?  I&#8217;ll show you how to roll you own mapping engine using PHP and the Google Map API.</p>
<p><span id="more-43"></span></p>
<h2>Using the built-in tools</h2>
<p>Simple Google maps can be produced in FileMaker using the Web Viewer object.  I&#8217;m sure you&#8217;ve all seen this:</p>
<p><img src="http://fmcollective.com/wp-content/uploads/2007/05/google_map_webviewer.png" alt="Google Map in the Web Viewer" height="547" width="630" /></p>
<p>This is the Web Viewer Setup for that example:</p>
<p><img src="http://fmcollective.com/wp-content/uploads/2007/05/google_map_webviewer_setup.png" alt="Web Viewer Setup for Standard Google Map" height="487" width="630" /></p>
<p><strong>What&#8217;s wrong here?</strong></p>
<p>The problem with this, in my opinion, is that the <em>Search Results</em> and <em>My Maps</em> area of the map takes up almost <em>half</em> of the screen. Further, you&#8217;ve got limited to no control of how this looks.  And, one click on a link and the user is off browsing the web—not exactly what you want them to be doing.</p>
<h2>Using the API</h2>
<p>I decided to turn to the Google Maps API to attempt to solve these issues.  The first step here is to sign up for a <a href="http://www.google.com/apis/maps/" title="Google Maps API" target="_blank">Google Maps API Key</a> for the site you&#8217;ll be hosting your maps from (the maps will still need a home).</p>
<p>So as not to re-invent the wheel, my first step was to search for a PHP wrapper for the Google Maps API that I could use as the basis for my mapping API. I found one that I came to like called the <a href="http://www.phpclasses.org/browse/package/3801.html" title="Easy Google Map" target="_blank">Easy Google Map</a> class.  This PHP class wraps all the JavaScript in PHP calls, so a PHP-buff like myself can easily use it.  You&#8217;ll need to download the Easy Google Map class (&#8221;EasyGoogleMap.class.php&#8221;) and install it on a webserver that supports PHP (the same one for which you got the Google Maps API key).</p>
<p>In this example, we&#8217;ll be staging the work at <a href="http://etc.proofgroup.com/fmcollective/" title="FMCollective Staging Area" target="_blank">http://etc.proofgroup.com/fmcollective/</a>, so the class will be located at <a href="http://etc.proofgroup.com/fmcollective/EasyGoogleMap.class.php" title="Hosted Easy Google Maps Class" target="_blank">http://etc.proofgroup.com/fmcollective/EasyGoogleMap.class.php</a>.  You can load this URL now, if you&#8217;d like, but you won&#8217;t get anything because it&#8217;s a PHP class and doesn&#8217;t return anything on its own.</p>
<p>The next step, of course, is to write a complementary PHP file that will actually be the <em>mapping API</em>. My thought was to make this simple to call from FileMaker, with a URL formatted like the following:</p>
<blockquote><p><code>http://DOMAIN/MYCOMPLIMENTARYPHPFILE.PHP?addr=The+Address+To+Map</code></p></blockquote>
<p>To do this I&#8217;ll need a PHP file that can grab the &#8216;addr&#8217; parameter and process it according to the needs of the Easy Google Mapping Class in order to produce a map.</p>
<p>Here&#8217;s what my file (which I have named &#8216;googlemap.php&#8217;) looks like:</p>
<blockquote><p> <code><br />
&lt;?php<br />
/*<br />
* File Name: googlemap.php<br />
* File URI: http://etc.proofgroup.com/fmcollective/googlemap.php<br />
* Description: Google Map API wrapper script<br />
* Version: 1.0<br />
* Author: Mike Lee, The Proof Group LLC<br />
* Author URI: http://www.proofgroup.com<br />
*<br />
* Copyright (c) 2007, The Proof Group LLC<br />
* All rights reserved.<br />
*<br />
* Redistribution and use in source and binary forms, with or without<br />
* modification, are permitted provided that the following conditions are met:<br />
* * Redistributions of source code must retain the above copyright<br />
* notice, this list of conditions and the following disclaimer.<br />
* * Redistributions in any form must reproduce the above copyright<br />
* notice, this list of conditions and the following disclaimer in the<br />
* documentation and/or other materials provided with the distribution.<br />
* * Neither the name of The Proof Group LLC nor the<br />
* names of its contributors may be used to endorse or promote products<br />
* derived from this software without specific prior written permission.<br />
*<br />
* THIS SOFTWARE IS PROVIDED BY THE PROOF GROUP LLC ``AS IS'' AND ANY<br />
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED<br />
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE<br />
* DISCLAIMED. IN NO EVENT SHALL <copyright> BE LIABLE FOR ANY<br />
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES<br />
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;<br />
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND<br />
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT<br />
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS<br />
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br />
*/<br />
require 'EasyGoogleMap.class.php';<br />
# Google Maps API Key<br />
$googlemaps_api_key = "XXX-XXX-XXX-INSERT-YOUR-KEY-HERE";<br />
# Get the 'addr' parameter from the GET request<br />
$addr = $_GET['addr'];<br />
$gm = &amp; new EasyGoogleMap($googlemaps_api_key);<br />
# Set address point(s)<br />
$gm-&gt;SetAddress($addr);<br />
$gm-&gt;SetInfoWindowText($addr);<br />
$gm-&gt;SetSideClick($addr);<br />
# To Enable/Disable Map Type (Map/Satellite/Hybrid)<br />
$gm-&gt;mMapType = TRUE;<br />
# Set map size<br />
$gm-&gt;SetMapWidth('700');<br />
$gm-&gt;SetMapHeight('600');<br />
?&gt;<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&lt;title&gt;EasyGoogleMap&lt;/title&gt;<br />
&lt;?php echo $gm-&gt;GmapsKey(); ?&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&lt;center&gt;<br />
&lt;?php<br />
echo $gm-&gt;GetSideClick();<br />
echo $gm-&gt;MapHolder();<br />
echo $gm-&gt;InitJs();<br />
echo $gm-&gt;UnloadMap();<br />
?&gt;<br />
&lt;/center&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;<br />
</copyright></code></p></blockquote>
<p>Copy that text and save it as &#8216;googlemap.php&#8217; (you&#8217;ll want to insert your own API key where indicated). That file is now hosted here: <a href="http://etc.proofgroup.com/fmcollective/googlemap.php" title="Hosted Google Map API" target="_blank">http://etc.proofgroup.com/fmcollective/googlemap.php</a>. You will want to put it in the same directory you put the EasyGoogleMap.class.php file.</p>
<p>A direct link to the file, which you can download, is here: <a href="http://fmcollective.com/wp-content/uploads/2007/05/googlemapphp.txt" title="Google Map PHP File">Google Map PHP File</a>. You will need to rename the file &#8216;googlemap.php&#8217;.</p>
<p>The fmcollective directory now looks like this:</p>
<blockquote><p><code>.<br />
|-- EasyGoogleMap.class.php<br />
`-- googlemap.php<br />
</code></p></blockquote>
<p>If you load the <a href="http://etc.proofgroup.com/fmcollective/googlemap.php" title="googlemap.php" target="_blank">googlemap.php</a> page right now, you&#8217;ll notice it&#8217;s blank, because you&#8217;ve not passed it any address to map (via the &#8216;addr&#8217; parameter).</p>
<p>A fully working example URL is the following: <a href="http://etc.proofgroup.com/fmcollective/googlemap.php?addr=1600+Amphitheatre+Pkwy,+Mountain+View,+CA+94043" title="Google Headquarters" target="_blank">http://etc.proofgroup.com/fmcollective/googlemap.php?addr=1600+Amphitheatre+Pkwy,+Mountain+View,+CA+94043</a>.</p>
<h2>Put the API into FileMaker&#8217;s Web Viewer</h2>
<p>Now, let&#8217;s go back to the top and put this into FileMaker&#8217;s Web Viewer.  Here&#8217;s a screenshot of what the finished product looks like:</p>
<p><img src="http://fmcollective.com/wp-content/uploads/2007/05/google_map_custom.png" alt="Google Map using a Custom PHP API" height="547" width="630" /></p>
<p>The Web Viewer setup is for a &#8216;Custom Web Address&#8217; set to the following:</p>
<blockquote><p><code>"http://etc.proofgroup.com/fmcollective/googlemap.php?" &amp; "addr=" &amp; /*Address=*/ Contact Preferred Address::Street &amp; ", " &amp; /*City=*/ Contact Preferred Address::City &amp; ", " &amp; /*State=*/ Contact Preferred Address::StateProv &amp; " " &amp; /*Zip Code=*/ Contact Preferred Address::PostalCode</code></p></blockquote>
<p>I hope you&#8217;ve enjoyed my first post and learned something useful.  Comments are welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://fmcollective.com/2007/05/23/google-mapping-in-filemaker/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Roll Your Own Edit Mode</title>
		<link>http://fmcollective.com/2007/05/19/roll-your-own-edit-mode/</link>
		<comments>http://fmcollective.com/2007/05/19/roll-your-own-edit-mode/#comments</comments>
		<pubDate>Sun, 20 May 2007 03:16:56 +0000</pubDate>
		<dc:creator>Ernest Koe</dc:creator>
				<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[FM7]]></category>
		<category><![CDATA[FM8]]></category>
		<category><![CDATA[FM8.5]]></category>
		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">http://fmcollective.proofgroup.com/?p=29</guid>
		<description><![CDATA[The Problem
As FileMaker developers, we take a lot of things for granted.  For example, FileMaker&#8217;s Browse Mode/Find Mode feature is actually pretty slick; just place a field on a layout and it becomes both a data-update field as well as a query field without additional coding. However, when a layout is set to &#8220;save [...]]]></description>
			<content:encoded><![CDATA[<h2>The Problem</h2>
<p>As FileMaker developers, we take a lot of things for granted.  For example, FileMaker&#8217;s Browse Mode/Find Mode feature is actually pretty slick; just place a field on a layout and it becomes both a data-update field as well as a query field without additional coding. However, when a layout is set to &#8220;save record changes automatically&#8221;, the frequency of people <em>thinking</em> they are in Find mode when they are actually happily clobbering data is enough to drive the most laissez-faire FileMaker developer nuts.</p>
<p>Sometimes,  calling such problems &#8220;training-issues&#8221; just isn&#8217;t enough.</p>
<p>One solution is to roll your own Edit Mode feature. This technique uses the power of global variables in FileMaker 8+. In this example, I am going to combine scripts, a global variable and a custom privilege set to regulate users&#8217; record-edit access.</p>
<p>Note: this article in intended to illustrate a general technique, do not rely solely on this example to secure your database.</p>
<p><span id="more-29"></span></p>
<p>The screenshots below are from a Mac but this tip is platform-agnostic.<a href="http://fmcollective.com/wp-content/uploads/2007/05/rollyourowneditmode.zip" title="Example File"></a></p>
<p><a href="http://fmcollective.com/wp-content/uploads/2007/05/rollyourowneditmode.zip" title="Example File">Download the Example File</a></p>
<p>Note: the top level account is &#8220;admin&#8221; with no password</p>
<h2>Step-by-Step</h2>
<p><strong>1. Create the table</strong><br />
In this example, I am going to start with a new file. I have defined a table called &#8220;contacts with a few basic fields.</p>
<p><a href="http://fmcollective.com/wp-content/uploads/2007/05/ryo_create_table.png" title="create table"><img src="http://fmcollective.com/wp-content/uploads/2007/05/ryo_create_table.png" alt="create table" height="304" width="402" /></a></p>
<p>Don&#8217;t worry about the &#8220;lock status&#8221; field for now; that is an interface bell-and-whistle that I added to give the user some visual feedback. Check out the example file to learn more about that later.<br />
<strong><br />
2. Create the &#8220;toggle&#8221; script</strong><br />
Next, I am going to create a basic script that toggles the edit mode.  The script is going to use a global variable as a switch. It sets a global variable to either 1 or zero each time the script is called.</p>
<p>I have chosen to name my global variable switch <code>$$__locked</code> but you could call it whatever you wish. Just make sure it is a <strong>global</strong> variable because we want the variable to hold on to its value after the script is run.</p>
<p>The script works by checking first to see if <code>$$__locked</code> is &#8220;on&#8221; (i.e. has a value that isn&#8217;t zero or empty). If <code>$$__locked</code> is &#8220;on&#8221;, the script turns our switch &#8220;off&#8221; by setting  <code>$$__locked </code>to zero. <code></code></p>
<p><a href="http://fmcollective.com/wp-content/uploads/2007/05/ryo_script.png" title="ryo_script.png"><img src="http://fmcollective.com/wp-content/uploads/2007/05/ryo_script.png" alt="ryo_script.png" height="281" width="439" /></a></p>
<p><strong>3. Configure record level access </strong></p>
<p>We need to tell FileMaker to check the global <code>$$__locked</code> before allowing our user to make record changes.  Since record access is controlled by FileMaker privilege,  I am going to  go over to the Define&gt;Accounts &amp; Privileges&#8230; menu and create a User account with a custom privilege set called &#8220;User&#8221;&#8230;</p>
<p><a href="http://fmcollective.com/wp-content/uploads/2007/05/ryo_define_accts.png" title="modify accounts"><img src="http://fmcollective.com/wp-content/uploads/2007/05/ryo_define_accts.png" alt="modify accounts" height="170" width="331" /></a></p>
<p><a href="http://fmcollective.com/wp-content/uploads/2007/05/ryo_edit_account.png" title="ryo_edit_account.png"><img src="http://fmcollective.com/wp-content/uploads/2007/05/ryo_edit_account.png" alt="ryo_edit_account.png" height="225" width="326" /></a></p>
<p>To configure the record data access setting, I select &#8216;Custom Privileges&#8217; from the &#8216;Records&#8217; pull down menu of the &#8216;Edit Privilege Set&#8217; screen&#8230;</p>
<p><a href="http://fmcollective.com/wp-content/uploads/2007/05/ryo_custom_priv.png" title="ryo_custom_priv.png"><img src="http://fmcollective.com/wp-content/uploads/2007/05/ryo_custom_priv.png" alt="ryo_custom_priv.png" height="314" width="498" /></a><a href="http://fmcollective.com/wp-content/uploads/2007/05/ryo_modify_data_access.png" title="ryo_modify_data_access.png"> </a></p>
<p>I am going to control access to the &#8220;contacts&#8221; table by highlighting it and changing the &#8216;Edit&#8217; privilege to &#8216;limited&#8230;&#8221;</p>
<p><a href="http://fmcollective.com/wp-content/uploads/2007/05/ryo_record_access.png" title="ryo_record_access.png"><img src="http://fmcollective.com/wp-content/uploads/2007/05/ryo_record_access.png" alt="ryo_record_access.png" height="265" width="488" /></a></p>
<p>My goal is to use a calculation expression to govern the user&#8217;s record modification activity. Records can be edited when:</p>
<blockquote><p><code>not $$__locked</code>.<code></code>..</p></blockquote>
<p><a href="http://fmcollective.com/wp-content/uploads/2007/05/ryo_edit_test.png" title="ryo_edit_test.png"><img src="http://fmcollective.com/wp-content/uploads/2007/05/ryo_edit_test.png" alt="ryo_edit_test.png" height="369" width="483" /></a></p>
<p>FileMaker will evaluate the expression <code>not $$__locked</code> each time the user tries to modify a record. If <code>$$__locked</code> is zero or empty, the expression <code>not $$__locked will</code> evaluate to true (not locked) and the user will get to edit records. If <code>$$__locked</code> is &#8220;1&#8243;, our expression will evaluate to false and our user will be blocked from making any changes to &#8216;contact&#8217; records.</p>
<p><strong>4. Bells &amp; Whistles</strong></p>
<p>In the example file, you&#8217;ll note that I have added couple of simple re-login scripts to toggle between my &#8220;user&#8221; account and my &#8220;admin&#8221; account.</p>
<p>Finally, let&#8217;s cap it off by attaching a button to our script and by adding a &#8220;lock status&#8221; calculation field to create a simple indicator of the record lock status.</p>
<p><strong> </strong></p>
<p><a href="http://fmcollective.com/wp-content/uploads/2007/05/ryo_simple_ui.png" title="ryo_simple_ui.png"><img src="http://fmcollective.com/wp-content/uploads/2007/05/ryo_simple_ui.png" alt="ryo_simple_ui.png" /></a></p>
<p>Cheers!</p>
]]></content:encoded>
			<wfw:commentRss>http://fmcollective.com/2007/05/19/roll-your-own-edit-mode/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
