Saturday, May 28, 2011

Case Insensitive Diff Algorithm in PHP

So, one day the business analyst wanted to compare what people where typing in as their address and the corrected/validated results we use. My first thought was "Oh that'd be easy, we just use a diff function on a report!" What I didn't think about was that most people type in the lowercase, but the corrected address are in all caps (as per Post Office specs).

Okay, so we just need a case insensitive diff algorithm, but wait, there's more. "Marshal Hollow Rd" and "Maral Hollow Rd" only show up as a tiny difference, but obviously they're completely different addresses. We needed to highlight the differences in the words more. So, now we need a case insensitive diff that judges differences based on words rather than characters.

What follows was my solution to this need. I wrote this a number of years ago, and I no longer remember much about it. I do know that I did not invent the diff algorithm. There was a comment with this link in it. Likely I just wrote what is said on that page and modified it to handle our special needs. If I read the website in the comment and studied the code, I could probably regain my understanding of this algorithm, but I don't think I really need to understand it anymore as in the intervening years I've not needed a similar algorithm since.

Here's the code!

Levenshtein Distance in Javascript

Okay, now this is an odd code snippet. I really can't remember why I needed a javascript implementation of the Levenshtein Distance algorithm. I mean, most back end languages have an implementation in their libraries that'd be far more efficient. Oh well, since I saved it, I might as well share it.

Friday, May 27, 2011

Using Zend framework MVC in a subdirectory of an existing project

I like MVC frameworks. Zend framework isn't my favorite, but my company is using [an older] Zend framework for it's mobile site. I might as well stick with it. Unfortunately, the desktop web site is still a jumbled mess of plain old PHP scripts with logic, database calls, and HTML in a single file. So what does one do when they want to develop new features in an MVC framework? Create a new virtual host just for those features? (This is how our mobile site works, it's in /var/sites/example.com/mobile) Create your own framework or use one that was designed for standalone use? No, you figure out how to use the newest version of the Zend framework from within a subdirectory of the current site!!

Research

First, a quick trip to google.. this looks promising Zend Framework Run in a Subdirectory ... it's a dead link.. crap.. Well, I guess I should just try it and see what happens.

Experiment

I used the zf.sh command line tool to create a ZF project in a subdirectory /var/sites/example.com/zf_test. Changed my .htaccess file to include "RewriteBase /zf_test/public/" and then fired up Chrome and hit the URL.

Of course I got a blank white screen and a PHP error message. The odd part was the PHP error had a call stack in the mobile site's bootstrap file.. hmm... So the problem was that APPLICATION_PATH and APPLICATION_ENV where already being defined in the mobile site's code and for some reason (I'm still not sure why) the mobile site's bootstrap was being called. So I changed them to DESKTOP_APPLICATION_PATH and DESKTOP_APPLICATION_ENV in zf_test/public/index.php and zf_test/config/application.ini.

Save, upload, restart apache for good measure, and hit refresh.

PHP Fatal error: Undefined class constant 'EXCEPTION_NO_ROUTE' in ... Hmm... a quick trip to google helped me find this was because the version of zend framework on the server on the one on my development box where a bit off. So, can I include the full ZF library in the project locally like I can with Rails? Yep, and almost as easily. I simply copied the
library/Zend folder from my local install to zf_test/library, uploaded, refreshed :

PHP Fatal error: Cannot redeclare class zend_loader in ... Okay, so something is initializing the old zend loader before my new zend framework can (dang "php_value auto_prepend_file ..."). Well, there can't be that many differences between the versions of zend loader can there? Let's just get rid of the new one and let the old one handle loading.
rm -rf /var/sites/example.com/zf_test/library/Zend/Loader*

Refresh and ... An error occurred Page not found

I'm starting to get annoyed. Okay, it looks like it's actually loading something in the App. After a bit of playing around, I set resources.frontController.params.displayExceptions = 1 and find that it's searching for a controller called zf_test. That's what I was afraid would stop the subdirectory thing from working. I google and find Base URL and subdirectories that sounds promising. So, added to index.php :

<?php
$ctrl  = Zend_Controller_Front::getInstance();
$router = $ctrl->getRouter();
$router->setRewriteBase('/zf_test');

PHP Fatal error: Call to undefined method Zend_Controller_Router_Rewrite::setRewriteBase() in ... &^$%$#&@$#!^&*!! I dig into the ZF front controller code and find it has a function setBaseUrl() that is passed to the router. Well, that's easy.

<?php
$ctrl  = Zend_Controller_Front::getInstance();
$ctrl->setBaseUrl('/zf_test/');

Save, upload, refresh...

Success!!



Find something else to work on

Okay, now I'm tired of playing with Zend Framework in a subdirectory of a project. I'll implement something in it later.

Salesforce.php library intial release

Okay, so "initial release" sounds a little more important than is true. I'm just open sourcing the small object mapping library for the Salesforce.com partner API. It's on github (https://github.com/mgfreshour/salesforce.php)

A little background may be in order. One day my boss tells me, "We want to integrate our site with Salesforce.com." My initial reaction was "cool, a few more weeks of job security." After a decent amount of work learning about the Salesforce API and creating an prototype library for this project, the project was dropped. So now, I've posted that initial library to github incase other would find it useful.

The idea behind it was to provide an ActiveRecord'ish interface to the salesforce partner API. The salesforce_Table class is meant to be a base class for the table mapping classes.

<?php
class mySalesforceAccount extends salesforce_Table {
  public function __construct() {
    parent::__construct('Account');
  }

  public function DoBusinessStuffToAccount($param) {
    // ...
  }
}

Then one could use the child object to manipulate data in the Salesforce Accounts table.
<?php
// ...
$account = new mySalesforceAccount();
$account->getById($account_id);

if ($account->name == 'Acme Co.') {
  echo 'Don\'t buy rockets!!  They are defective!!'
}

There is [some] support for loading the layouts from Salesforce's meta data. Currently salesforce_TableLayout handles the display and only does very basic HTML. The future plan was to make this an abstract base class so different displays for layouts would be created by extended the classes.

<?php
$account = new mySalesforceAccount();
$account->getById($account_id);
$layout = new salesforce_TableLayout($account);

// This should show and HTML form similar to the one on salesforce
//  with the fields containing values from $account already
echo $layout->getLayoutDisplay('editLayoutSections');

Finally, save works as well, err.. a good part of the time :P

<?php
$account = new mySalesforceAccount();
$account->getById($account_id);

// pretending we just received a post from an edit layout form
$account->fieldsFromArray($_POST);

try {
  $account->save();
  echo 'Yay!!  We Saved it!!'
} catch (Exception $e) {
  echo 'ERROR : '.$e->getMessage();
}

Oh well, it's out on github (https://github.com/mgfreshour/salesforce.php) now if you're interested. I'd like to work some more on it and perhaps even get it production ready, but that'd require doing programming at home as well as at work! *yuck*