Fallback Content and Google Maps API Version 3

I recently worked on a site for mobile devices that uses the Google Maps JavaScript API.  It was a pleasure to integrate and produced great results, but inevitably, we needed to have a fallback mechanism for users whose devices did not support Google Maps, or did not have JavaScript support at all.  (Currently the API only works on Android and iPhone devices.)

Back in API version 2, there was a GBrowserIsCompatible() function that one could use to detect compatibility. It’s not available in the version 3 API. In addition, that method was not useful for devices with no JavaScript support.

<noscript> Fallback

For my first attempt at solving the problem, I used <noscript> tags to provide content for scriptless browsers:

<noscript>
  <p>This content will show up when the browser has no JS support.</p>
</noscript>

As you can deduce, this only solves half of the problem.  The use of <noscript> has other problems as well – it somewhat violates the concept of “progressive enhancement” of websites, which involves using JavaScript to add additional functionality over the base content.  (In my case, the base content right now is a message that says “sorry, you can’t see our maps.”)

Progressive Enhancement

As I thought about the problem in this context, I realized that the solution should be simple.  The Google Maps API already provides a progressive enhancement mechanism, but I wasn’t taking advantage of it.  Your basic Google Maps example looks like this (mostly blatantly copied from the documentation):

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
  html { height: 100% }
  body { height: 100%; margin: 0px; padding: 0px }
  #map_canvas { height: 100% }
</style>
<script type="text/javascript"
    src="http://maps.google.com/maps/api/js?sensor=false">
</script>
<script type="text/javascript">
  function initialize() {
    var latlng = new google.maps.LatLng(41.83, -111.83);
    var myOptions = {
      zoom: 8,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    var map = new google.maps.Map(document.getElementById("map_canvas"),
        myOptions);
  }

</script>
</head>
<body onload="initialize()">
  <div id="map_canvas" style="width:100%; height:100%"></div>
</body>
</html>

The basic premise here is that the API replaces the content of the map_canvas container with the map display.  So, why not just add some fallback content to that container?

<body onload="initialize()">
  <div id="map_canvas" style="width:100%; height:100%">
    <p>Sorry, your device does not support this feature.</p>
  </div>
</body>

Does it Work?

This seems to be a good generic solution to the fallback problem.  I tried it in the following scenarios:

  • Browser supporting Google Maps – the map displays correctly, and the fallback content is not shown.
  • Browser with JavaScript turned off – the fallback content is never replaced, and shows as expected.
  • Browser without Google Maps API loaded (to emulate a non-supported device) – the fallback content is never replaced.

Looks good so far!  I’ll update this post if anything comes up later.

Posted in Code | Tagged , , | Leave a comment

Using PostgreSQL with WordPress

This site has been using PostgreSQL as a back end for WordPress since the beginning.  This is possible with a nice little plugin PG4WP that will translate queries on the fly into something that PostgreSQL can understand.

I’m a big fan of PostgreSQL and use it on almost every project I do.  There is something about setting up a MySQL instance and managing it that bothers me, so this plugin makes my day.

I have pushed a copy of the plugin to GitHub so that I can keep track of tweaks I make to it as I find compatibility problems.  I am now running WordPress 3.0 and am monitoring my logs for database errors.

Posted in Code | Tagged | 6 Comments

Connect to Your Local Development Sites from VirtualBox Guests

Like many web developers, I do most of my work with a web server running on my local machine.  In my case, I’m running Apache HTTPD from MacPorts on my MacBook Pro, and I have various sites in development using either Ruby or PHP.  Due to the nature of the projects, or simply because it’s a good idea, I prefer to test my sites in various browsers, including Internet Explorer, which is not available on Mac OS.  So, I’ve set up multiple virtual machines using the freely available VirtualBox.

I’ve set up aliases to localhost, and corresponding NameVirtualHost settings for Apache, on my Mac for each of the sites I’m developing.  Then I can just enter, for example, “myproject.local” in my browser, and view my work in progress.  (I use the nice Ruby gem “ghost” to manage aliases.)  However, this doesn’t work with a default VirtualBox guest, so below is my method for getting this to work.

Start the VirtualBox VM Manager

  1. To begin, start your install of VirtualBox.  I believe that you need at least version 2.2.0, which introduced host-only networking.
    vbox_start
  2. Open the settings for the desired VM and navigate to the Network tab.  You should already have something in the Adapter 1 section.
    vbox_adapter1

Add a Local-Only Network Interface

  1. Click on the Adapter 2 tab.  You should typically see a disabled interface, something like this:
    vbox_adapter2
  2. Enable Adapter 2 by checking the box.  Then change the “Attached to:” box to “Host-only Adapter.”  The Name box shows “vboxnet0″ on my install:
    vbox_adapter2_new
  3. Save your settings and start your virtual machine.

Verify Host-Only Adapter Address

VirtualBox should create a new network interface on your host OS that is used for host-only networking.  On Mac OS, verify this by entering the following in a Terminal:

ifconfig vboxnet0

You should see something like the following.  Note the IP address – you will need it later:

vboxnet0: flags=8943

Set up Guest OS

You need to set up host aliases in your guest OS that match those you set up in your host, only that you will point them to the IP address you noted previously.  The following instructions apply to Windows XP and newer.

  1. Open your hosts file.  Use Start -> Run… and enter “notepad c:WINDOWSsystem32driversetchosts”.  UPDATE: On Windows Vista and Windows 7, there are additional protections on this file.  You will have to run Notepad (or your favorite text editor) as Administrator first – right click on its shortcut and choose “Run as administrator.”
  2. Add a line to the file that associates your host-only IP address with your development site aliases.  The IP address comes first, followed by each alias, separated by spaces.
    192.168.56.1    myproject.local otherproject.local

Test the Configuration

As long as your local web server is running on the host OS, you should be able to enter one of your site aliases in the guest’s browser and get the expected results.

Posted in Code | Tagged , | 5 Comments

Installing PostgreSQL on Mac OS X

Here is what I did to get PostgreSQL and the pg ruby gem installed on Mac OS X Leopard. This post is more for my personal reference, but if anyone finds it useful, so be it. There are other posts around that deal with the same issue, but I’ve not found one that has the complete picture.

Prerequisites

I’m using the Ruby and RubyGems that come installed with Leopard.

You will need to install the following first:

Installing PostgreSQL

Install PostgreSQL from MacPorts using the following command in your Terminal:

sudo port install postgresql84 postgresql84-server

Make sure to follow the instructions printed at the end of the installation, so that you can set up PostgreSQL to start automatically.

Installing pg Gem

Update: The “pg” gem is considered the most current of those that provide a PostgreSQL access layer. I previously mentioned the “postgres” gem.

This is the part that might trip you up if you try the standard gem install pg route. There are two ways to ensure that this works.

The first is to ensure that the directory containing PostgreSQL executables (notably pg_config) is in your PATH. You can add the following to /etc/profile:

export PATH=/opt/local/lib/postgresql84/bin:$PATH

Then run sudo gem install pg as usual.

If you do not modify your PATH, use the following in your Terminal instead so that the PostgreSQL headers and libraries are found:

sudo env ARCHFLAGS="-arch i386"
  gem install pg --
  --with-pgsql-include=/opt/local/include/postgresql84
  --with-pgsql-lib=/opt/local/lib/postgresql84

Update: On Mac OS X 10.6 Snow Leopard, you may need to use “x86_64″ instead of “i386″ in the above command.

I hope that’s the full story…

Posted in Code | Tagged , | 2 Comments

Not So Smarty

I’ve used the Smarty template engine on a large PHP project for many years now.  Back in my younger days (2002 or so) we thought it was great – we could finally get good separation of concerns on our web applications – no more view logic (and lots of echo statements) mixed in with our business logic.  Unfortunately, there have been a few bumps in the road since then, and I’ve begun to reconsider Smarty’s usefuless, and whether it even meets its declared goals.

Separation of Concerns

Here’s how the Smarty web site answers the question “Why Use Smarty?“:

One of Smarty’s primary design goals is to facilitate the separation of application code from presentation. Typically, the application code contains the business logic of your application, written and maintained in PHP code. This code is maintained by programmers. The presentation is the way your content is presented to the end user, which is written and maintained in template files. The templates are maintained by template designers.

Well-designed web applications strive to do exactly this – keep the view layer separate from the business logic.  In MVC architecture, that would be the V for view and M for model, respectively.  You might also include the “C for controller” layer with the business logic part.

Smarty tries to enforce this separation by introducing its own template language.  Their argument is that allowing PHP code in the templates will result in all sorts of chaos.  Ironically, there’s the {php} tag, which lets you embed PHP in your templates when you “just can’t get around it.”  Overall, Smarty has succeeded for us in this regard, but are the gains worth the quirks?

Ease of Use

Smarty claims to shorten the template development process with its easy template syntax that is “not much different than plain HTML.”  For example, displaying the value of a variable is about as concise as it gets:

{$variable}

But really, how much harder is it to type this:

<?php echo $variable; ?>

If you have enabled short PHP tags, you can do:

<?= $variable ?>

Having worked in Rails a bit, I tend to like this, which is available if you turn on ASP-style tags in PHP:

<%= $variable %>

Smarty also has variable modifiers, which let you filter the output of a variable through a function first:

{$variable|modifier}

Yes, it’s easy to type, but how much easier than:

<?= modifier($variable) ?>

I suppose the one thing Smarty has going for it here is that the template is more data-oriented, with the variable name coming first, than the function-oriented nature of plain PHP.  Hey, but I’m a programmer, right, so calling functions feels natural to me.

Smarty gets a little more sketchy when you want to access the values in an associative array, or call a method on an object.  Sure, you can do this:

{$hash_variable.key}
{$object->method()}

The former will work, as long as your associative array has keys that are alphanumeric strings.  You’ll get breakage if your keys are numbers, or contain spaces or punctuation characters.  The latter works great, but you can’t chain method calls.  This won’t work:

{$object->method()->another_method()}

Maintenance

Smarty is a “compiling” template engine, meaning that it transforms templates written in its own Smarty language into PHP code, saving the result out to disk to avoid repeated compilation.  This tends to fill up your disk with lots of compiled templates, and you must ensure that you have a folder on  your disk that is writable by your web server.  Occasionally, I’ll get a PHP Fatal Error in one of the compiled templates, and they’re nearly impossible to read.

Design

Smarty is a hybrid of object-oriented and procedural code.  The template parser and compiler is implemented as a class, but Smarty plugins and modifiers are simply PHP functions.  I find it handy to keep related custom view code together in a class, but it’s not easy to do with the current design.

Conclusion

Smarty has served well and I’ll likely continue to use it on some ongoing projects, mostly because of the sheer amount of work required to switch to something else.  I’m looking into the methods used by other PHP frameworks, like Zend Framework, since they have adopted a PHP-only approach to templating.  So far I’m a bit concerned about the baggage that comes along with these full MVC frameworks.  For now, I want only the template (“view”) portion.

I have something in the works here, and I’ll write about it later.  If you look hard enough, you might find it.

Posted in Code | Tagged , | Leave a comment