Aloofness
So I've been a bit out of pocket the past few weeks. Most people probably know why. For one thing, I was doing a personal experiment to see how going without IM and IRC during work hours affected my productivity. The change seems to have been positive, so I'm most likely going to stick with it for the time being. I'll continue checking Twitter and e-mail throughout the day, but I just seem to get more done by limiting my focus to just those things and my work.
That's not the only reason for me having been out of the picture, though. I've been making preparations to speak at ZendCon for the first time, which will be comprised of an official session on Creating Web Services with Zend Framework as well as uncon session on Web Scraping with PHP. As time-consuming as it can be to make arrangements to attend a conference, it's all the more so if you're speaking at one. Putting an hour-long presentation together from nothing is quite the daunting task, especially when you have to do it twice.
Lastly, I've secured an agreement with a publisher to author a book on web scraping using PHP. I've had a number of people ask me if there were any good books on the subject and I've never been able to suggest any. I've also become a frequent "go to" person of sorts for web scraping applications. It's been on my personal list of goals to author a book, so it seems a good way to kill two birds with one stone. The book should be coming out sometime later this year and I'll post to my blog again to announce it when the time comes.
Some of you may know that tropical storm Gustav recently came onto the scene in the Gulf of Mexico. At the time of this writing, it is a borderline hurricane and currently projected to sweep right through Vermilion Bay, about 10 miles from where I live. At the moment, I plan to evacuate west with my family to stay with relatives until the storm has passed. Tropical storm Hannah is likely to be only a few days behind Gustav, however, so that may extend my absence. Internet connectivity will likely be limited or unavailable where I am, but I will continue to use my phone to send messages to Twitter where cell coverage is available. For those of you who are spiritual, I ask that you keep my family and other residents of this area in your thoughts and prayers during this time.
The Lafayette CampFiber
Just a quick post to inform local residents about a very exciting local development.The Lafayette CampFiber, a barcamp-style event, will be hosted on October 4th at the Travis Technology Center in Lafayette. I've been waiting for an event like this to take place in Lafayette for several years and am very much looking forward to it. More information is available on Lafayette CampFiber BarCamp.org page. Registration is free, but limited due to seating limitations, so sign up early!
From BarCamp.org: "Inspired by the community, ad hoc, unconference model of BarCamp, and driven by the desire to spark the imagination of developers to create the next generation of big bandwidth applications, the Lafayette CampFiber will bring together local developers in the Lafayette area to discuss the opportunities being created by the deployment of LUSFiber, soon to be one of the fastest residential networks in the country."
Environmental Awareness Quickie
I ran into an instance recently where someone was trying to run Phergie in an environment where the exec function was disabled. This causes a warning in the Quit plugin, which uses exec to automatically detect the full path to the PHP CLI binary on non-Windows systems that it will later use that path to initiate a new PHP CLI process to "restart" the bot.
I realized when I started digging into this issue that I wasn't aware of a way to check the PHP configuration to see whether or not a function was disabled, save for using the ini_get function to get the value of the disable_functions setting and parse it manually.
Thanks to Johannes Schlüter for cluing me into the fact that the SPL ReflectionFunction class has an isDisabled method, which is exactly what I was looking for. Unfortunately, there's no equivalent method in the SPL ReflectionClass class for the disable_classes setting. Thankfully, though, I haven't run into a use case for that yet.
Update: Apparently I inspired Johannes to write a patch to add ReflectionClass::isDisabled(). It most likely won't make it in until 5.3.1, but at least the patch is there if you need the feature. Thanks Johannes!
EAV Modeling - Square Peg in a Round Hole?
So I got the June 2008 issue of php|architect (or volume 7 issue 6 for those of you who track it that way) in recently. Right off, I found the cover article on EAV modeling to be of interest seeing as my current employment is in the medical IT industry and I'd never heard of this technique for storing data. I actually more or less knew what it was, but had never put a name to the face so to speak.
The mental image that came to me when reading about this approach to data modeling was taking the traditional relational table and turning it on its head. Despite what the Wikipedia article on the topic might tout early on, there are disadvantages to using the EAV approach. EAV actually has to circumvent, work around, or reimplement features that most mainstream database servers today provide "for free" to the traditional relational counterparts of EAV in order to get equal functionality. These include native data type validation and data type-specific operations without explicit typecasting (if you're not separating EAV values by data type), row-level referential integrity, and schema metadata. EAV also adds a dimension of complexity to query construction in an era where storage is becoming cheaper and database technologies are evolving. It may work, but I don't foresee it scaling very well for larger systems. In short, it seems an attempt to force a square peg into the round hole that are traditional relational database systems.
In a MySQL world, there are alternative approaches for deploying DDL modifications. One is to implement master-slave replication to propagate DDL modifications and load balancing to maintain uptime as changes are propagated from server to server. Another is to use MySQL Proxy to direct queries to servers hosting unmodified schemas and queue DML operations in the binary log while DDL modifications are made. Once DDL is complete, the server goes into "read only" mode while queued DML operations are applied and incoming DML operations received during that time are blocked until the queue is empty. (This may be a potential point of improvement.)
Outside of MySQL, there are document-focused database systems such as Apache Lucene and its current .NET and PHP ports as well as Apache CouchDB. While some of these are still a little early in development, I see them as being more ideal for applications demanding more fluid data storage and hope that the development of similar solutions continues.
Simplifying Zend_View_Helper_Url
When I first began working with Zend_View on a project at work, I noticed that the Url view helper was a bit of a pain to use. It was rare that I didn't want to specify one or more of the action, controller, and module in my call along with the other Route assembly parameters. Having to label them with an array index made the calls to the helper ugly and more difficult to read. As well, I often wanted to refer to actions in the same controller or controllers in the same module with respect to the current action.
To get around this, I wrote a view helper that extended Zend_View_Helper_Url and had three optional parameters specifically for the action, controller, and module. Everything else was passed into the fourth parameter, an associative array of any other parameters I needed to include. If any component of the route is excluded or specified as null, I simply get its value from the current request.
My friend Andy Best took this a step further and added in support for specifying custom routes, which he's using for a project of his own but I didn't need myself because I only use the default routes provided by the standard rewrite router. The result is the code below.
<?php
require_once 'Zend/Controller/Front.php';
require_once 'Zend/View/Helper/Url.php';
class App_View_Helper_Route extends Zend_View_Helper_Url
{
public function route($action = null, $controller = null,
$module = null, $params = array(), $route = null)
{
$front = Zend_Controller_Front::getInstance();
$request = $front->getRequest();
$router = $front->getRouter();
if ($action === null) {
$action = $request->getActionName();
}
if ($controller === null) {
$controller = $request->getControllerName();
}
if ($module === null) {
$module = $request->getModuleName();
}
$urlOptions = array_merge($params, array(
'action' => $action,
'controller' => $controller,
'module' => $module
));
if ($router->hasRoute($controller) && $route === null) {
$route = $controller;
} else if ($route === null) {
$route = 'default';
}
return $this->url($urlOptions, $route, true);
}
}