Bugs in Phing on Windows
I use Phing to deploy my projects, and as they become more complex I expand on my use of Phing tasks. For instance, I have a ZIP archive of zip codes that Phing extracts and then imports into a database when deploying the application.
I maintain two development environments. One on a Linux server, and one locally on my Windows laptop using WAMP. So naturally, my PHP projects are cross-platform compatible and run on either Windows or Linux. And for the most part that simply means being careful about buildings paths, filenames, and file permissions.
To my surprise, the Unzip task defined in my build.xml that imports the Zip code data failed in mysterious ways: It reports success, but there's no extracted files to be found. It works on Linux, but not on Windows.
I dug into it and found two issues. First, the Phing's Unzip Task doesn't have the most solid error checking, and errors coming back from the Archive_Zip PEAR component. Second, the Archive_Zip PEAR component doesn't correctly check for absolute paths on Windows. Both problems have been reported on Phing's web site as Issue #261 and #262.
Print This Post
Zend_DB_Select Woes
It's no secret, I'm a fan of the Zend Framework, which I've been using since version 0.15. A lot of components have been added since then, and many of the initial components have been refactored and enhanced, and have matured. And that includes the Zend_Db_Select component, which has been evolving quite nicely, and even Zend_Db_Table_Abstract based classes make use of Zend_Db_Table_Select, which extends Zend_Db_Select.
But ultimately, there's still something lacking: Support for vendor specific SQL extensions, such as MySQL's SQL_CALC_FOUND_ROWS. Generally speaking, keeping Zend_Db_Select ANSI SQL compliant is a Good Thing™, as it forces (mostly) standards compliant queries (with the exception of the LIMIT clause, which invokes the database adapter to generate the SQL snippet), which may help with portability. Still, full support for features offered would be nice, and often is the reason why a particular database was chosen to begin with (among other reasons such as performance, budget, corporate policy, developer experience, etc).
Up until now I've always patched my local copy of the Zend/Db/Select.php file with support for that particular extension. That way I could call $select->calcFoundRows(true)->from([..]); and not have to give up using Zend_Db_Select. Of course doing it this way is not exactly best practice — a vendor specific extension shouldn't be implemented like that in a more universal component. For my purposes that's fine, since I just work with MySQL and SQLite, but ultimately there needs to be better support for these extensions.
A cleaner way to implement the extra functionality is to extend Zend_Db_Select, and add the extension support there. With ZF 1.6 RC1 that means overwriting the protected static $_partsInit, and adding the correlating _render*() method that gets called in Zend_Db_Select::assemble().
There are discussions about this on the Zend Framework mailing list, and they provide interim solutions. It's especially useful in conjunction with the proposed Zend_Paginator, which is part of ZF 1.6 RC1.
However, getting a select object with $dbAdapter->select(); is still an issue. Instead, one would have to manually call $select = new My_Db_Select($dbAdapter);, and that's something I'd like to avoid. It would also trigger a chain reaction and require one to extend Zend_Db_Table_Abstract with My_Db_Table_Abstract, which calls My_Db_Table_Select instead of Zend_Db_Table_Select, which in return extends My_Db_Select instead of Zend_Db_Select. Not pretty. And it's definitely a good example of why I, like many other OO developers, favor "composition over inheritance."
I'd almost like to see PHP getting proper support for mixins. I could see Zend_Db_Select emulating mixins or supporting plugins by registering plugin classes and using __call() to iterate over those classes to add functionality to the core, which the individual database adapters then register — something like Zend_Db_Select_Plugin_Mysql.php, but honestly, that seems a bit overkill, and a tad bit too unclean for my taste, but perhaps that's the way to go. It's how Doctrine implements Table plugins, and who knows, maybe it paves the road to what could one day be supported natively by PHP 6.3 or 7. After all, Perl, Python, Ruby, JavaScript and many other dynamic languages support it.
Print This Post
Paginating Zend_Search_Lucene results
This short entry was inspired by a snippet of inefficient code I encountered, which involved iterating over an array with a loop and breaking out of it once enough results were fetched.
Zend_Search_Lucene does not paginate results. It simply returns an array. While it does allow you to specify to only return the first N results (using Zend_Search_Lucene::setResultSetLimit($limit)), this is not really all too useful.
$lucene = Zend_Search_Lucene::open('index');
$hits = $lucene->find('author:"mark twain"');
$page = 1;
$perpage = 10;
return array_slice($hits, $page * $perpage - $perpage, $perpage);
The key element here, of course, is the use of array_slice(), which can be used with any array. So this isn't specific to Zend_Search_Lucene in any way.
Print This Post
Debugging web sites with the BlackBerry Simulator
I've never used a BlackBerry. Yet, I was tasked with debugging a web site that apparently had some issues with the BlackBerry. This rather outdated site was using frames, which is the first hint that there may be problems. However, according to the BlackBerry Developer's Guide (PDF) frames aren't an issue. They're simply processed and displayed sequentially in the same order they're defined in.
First thing I needed to do is grab that BlackBerry Simulator, a Verizon-branded 8130. Also needed is the Email and MDS Services Simulator, which enables the BlackBerry Simulator to use the Internet Browser, and have email functionality.
After that it's all fairly straight forward. Start the BlackBerry Simulator, fire up the MDS Services, go to Applications, open the Internet Browser, navigate to the desired site and look at the results.
And it wasn't pretty. Everything showed up correctly — well, as correct as it can on such a small screen — but some of the links were simply not working. Normally the cursor turns into a hand icon when hovering over a link, but it wasn't happening. Initially I thought maybe there was a style sheet issue, where perhaps the "hitbox" for the actual link had moved or been covered by something. However, that turned out to not be the case.
I employed a strategic debugging methodology which mainly consisted of "remove code until it works." And so I stripped down the files, deleting sections of html at a time — figuring it would eventually all fall into place. But it wasn't so. After I had reduced both frames to valid html in its simplest form — html, body tags, and a list of five links — the issue became apparent. There's a bug in the BlackBerry Web Browser. When the frames are merged, all links, except for the first two per each frame, are unclickable. They still look like links, they're blue, they're underlined, but when you hover over them with the cursor it doesn't turn into a hand, and the links are simply not clickable. They behave more like an a tag without the href attribute.
Print This Post