Am I blind?

January 15, 2009

This is less of a blog post and more of a note so that I never forget this in the future, but has anybody ever had trouble configuring PEAR on a XAMPP installation on Windows?  For whatever reason I couldn’t find the damn setup utility and by a fluke while configuring FirePHP I came across it today. 

So Scott, next time remember to run: xampp\php\go-pear.bat

Thank you.


e^(2πi) is the loneliest number

January 10, 2009

Adobe Flex is cool and all, but why settle for one framework when you can make it more powerful with a second?  Recently I developed an application which was using all PHP on the backend, and all Javascript on the frontend.  I developed the PHP interface so that all interactions from the frontend occurred via AJAX calls to a gateway class which was just a list of entry functions that would in turn call library functions and then echo out a JSON encoded result.

Since all of the frontend functionality was focused on the gateway, and nothing past that, I figured I could really test this library by developing a second frontend with a second gateway.  Within about 2 hours I had a working frontend for the application running on Adobe AIR using AMFPHP as an interface for remoting calls to the PHP backend.  Here’s a run down of how I set this up.

You can grab AMFPHP from the developer’s homepage.  AMF is a binary serialization format for Action Script objects to all messages to be sent to server-side services, and AMFPHP is just a PHP implementation of that format.

Installation is quick and easy, just drop the amfphp/ root folder into the htdocs directory of your web server.  To test out the installation, go to http://localhost/amfphp/browser/.  If all goes well, you should be presented with a Flex application.

For the PHP code, we can keep it simple.  Create a file with a matching classname.  I named my class AirDemo and saved it as AirDemo.php:

class AirDemo {
    public function helloWorld( $a_name )
    {
        return "Hello, " . $a_name;
    }
}

Now stick that PHP file into a folder, let’s call it airdemo_library, and then stick the folder in the amfphp/services directory.  Restart the amfphp/browser/ application and you’ll now see airdemo_library in the left hand tree.  Expanding that will give you the AirDemo class, and then you will be able to test out communication by sending requests manually.

Setting up the Flex side is a little more involved.  First, create a services-config.xml file under your src/ directory:

<services-config>
     <services>
          <service id="amfphp-flashremoting-service" class="flex.messaging.services.RemotingService" messageTypes="flex.messaging.messages.RemotingMessage">
          <destination id="amfphp">
          <channels>
              <channel ref="my-amfphp"/>
          </channels>
          <properties>
               <source>*</source>
          </properties>
          </destination>
          </service>
     </services>
     <channels>
     <channel-definition id="my-amfphp" class="mx.messaging.channels.AMFChannel">
          <endpoint uri="http://localhost/amfphp/gateway.php" class="flex.messaging.endpoints.AMFEndpoint"/>
     </channel-definition>
     </channels>
</services-config>

The only thing to pay attention to here is the endpoint uri argument needs to point to your AMFPHP installation.  This essentially tells Flex where to find the remoting gateway.  We then tell Eclipse to look for this remoting gateway by adding a line to the Flex compiler options:

config_options

Now we’ve got Eclipse configured to compile your Flex/AIR application so that it’s aware of AMFPHP, all that’s left is to actually use it.  This is the easiest part.  I’ve created a simple application that provides a text box and a button, and when you click the button it calls the helloWorld( ) function that I’ve already declared on the PHP backend.  So the user will type in a name, click the button, and get a message back from the server.

To hook up the remoting methods, add this to the top of your MXML document:

<mx:RemoteObject id="airdemo_service" fault="faultHandler( event )" showBusyCursor="true" source="airdemo.AirDemo" destination="amfphp">
     <mx:method name="helloWorld" result="resultHandler( event )" />
</mx:RemoteObject>

The RemoteObject id is whatever you’d like to refer to your remote library as within your ActionScript, and the source is the library.class you are defining remote methods for.  Each mx:Method you declare uses a literal string to identify a remote function, as well as a local ActionScript function that will handle the result.  To call the function, just call it like you would any ActionScript function:

airdemo_service.helloWorld( txtName.text );

And that’s that.  Here’s a screenshot of the end result:

app_demo


Stubborn objects

January 7, 2009

When I think about persistent data the first idea that always pops into my head is, “singleton.” It’s simple, it’s elegant, and it works. It’s not difficult to implement a singleton in PHP. Set a private constructor, private static member and instantiate the object by calling some public function (usually instance( ) ).  Like so:

<?php
class Singleton {
     private static $singleton;  

     private function __construct( ) { }

     public static function instance( ) 
     {
          if ( ! isset( self::$singleton ) ) {
              $class = __CLASS__;
              self::$singleton = new $class;
          }

          return self::$singleton;
     }
}

$object = Singleton::instance( );
?>

The problem with using a singleton in a server-side language like PHP is scope.  Scope in PHP is based upon requests, which rules out using a singleton pattern if your application is trying to access the persistent data via an AJAX call or something of that sort.  In developing an application that used no PHP on the frontend and relied on all of it’s data by making AJAX calls to a PHP library, I wasn’t able to maintain state on my database with each request.

The goal of this application was to minimize database calls in order to speed up the operation.  We were using an older version of the app at the time which ran on EWD and essentially used a mixture of AJAX and direct database calls for every single operation.  It was slow.  My new design synchronized the database whenever needed and stored it on the PHP backend.  Lets call this class Database.

Database is a class which needed to behave like a singleton.  After all, this library was developed to be portable and therefore all communication was occurring through a series of gateway classes that acted as an interface for AJAX, AMFPHP, or whatever other framework one could dream up.  All of the operations happened during AJAX requests, and therefore a singleton implementation wouldn’t suffice for Database.  The class holds a replica of the existing database so that queries are made to the object rather than the database itself.  This eliminates calls assuming the data we have in the Database object is correct.  There was just no way to use a singleton pattern to keep this object alive and kicking from one request to the next.

Fortunately, PHP provides the tools necessary to handle this. Sessions are a persistent environment where you can store necessary data, and that’s exactly what I did.  Utilizing a tool built into PHP I was able to handle keeping my database object “alive” in the background while the Javascript on the frontend formatted and displayed whatever data I was sending back.  PHP has built-in object serialization (as most modern languages do).  Serializing encodes a custom object into a bytecode string which can then be transformed at any time back to it’s original data type and state. A typical call originating from my gateway would look like this:

public function someFunc( ) { 

    // Fetch the database from the session
    $database = unserialize( $_SESSION['database'] );

    // Query or tweak the database, letting the database
    // object handle any direct DBMS queries if the
    // database was altered. 

    // When finished, store the database back into the
    // session
    $_SESSION['database'] = serialize( $database );
}

So there we have it.  A custom database object that needs to remain persistent across requests stays alive in the session by using built-in serialization.


Follow

Get every new post delivered to your Inbox.