Sunday, September 04, 2005

PHP4/MySQL Error Handling with an Observer design pattern

I've had several emails from developers about the last blog entry and they all wanted more details on how to implement the Observer pattern for error handling. So, I have started writing an article that will be published by DevShed sometime in the near future.

You can read through the article and stay up to date with the creation. Right now the content is enough for any competent coder to abstract the concept and implement the solution into their application. I'll be adding content to the article as time allows and will hopefully have it finished soon.

While I'm adding content you can always read through it here: PHP4/MySQL Error Handling with an Observer design pattern

Saturday, September 03, 2005

Object registry and Observers...

The build on Chris's application is going well and we have finished implementing the core tiered architecture!

The first step was to construct a simple object registry so that the individual components can be shared via a composite pattern. In a nutshell, it is a basic text book Singleton with a twist. The code looks like this:

Singleton object registry class

001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
<?php
class Singleton{
    function &
getInstance ($class, $name = ''){
        static
$registry = array();
        
$_instanceName = notNull($name) ? $name : $class;
        if ( !isset(
$registry[$class][$_instanceName]) || !is_object($registry[$class][$_instanceName]) ) {
            
$registry[$class][$_instanceName] =& new $class;
        }
        return
$registry[$class][$_instanceName];
    }
}
?>

The code above is the backbone of the application since it is completely object oriented. The benefit is that the code (classes or objects) are reusable and are able to be shared among all yet only instantiated once. This adds tremendous flexibility while keeping system resource utilization to a minimum as the registry contains only references to the objects and NOT copies of the objects.

The bottom line is that the category pages are rendering in less than .03 seconds with .005 total MySQL time (of course, no caching yet). Almost forgot...only 5 queries! The performance is blistering fast and infinitely scalable * to the limits of MySQL*. The reason for the outstanding performance is that the application was coded from the bottom up with an eye on performance. Since we are sharing objects we eliminated a lot of redundant database queries and processing overhead with multiple instantiation.

In addition, we have implemented an Observer / Listener pattern. This will form the backbone of the first plug-and-play eCommerce shopping cart! Admittingly, our beta code is far from perfect but has tremendous potential. The idea is the place strategic hooks in the business logic (and maybe objects) which will enable notification to event Listeners. Thus far we have implemented 2 core systems that use the Observer pattern: error logging and also script/performance timers. Here is the base class:

Observer pattern class

001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
029 
030 
031 
032 
033 
034 
035 
036 
037 
038 
039 
040 
<?php
class Observer{
    var
$_observers;
    var
$_message;
    
    function
Observer(){
        
$this->_observers = array();
        
$this->_message = NULL;
    }
# end constructor
    
    
function attach(&$observer){
        
$this->_observers[] =& $observer;
    }
# end function
    
    
function detach(&$observer){
        foreach (
array_keys($this->_observers) as $key ){
            if (
$this->_observers[$key] === $observer){
                unset(
$this->_observers[$key]);
                return;
            }
# end if
        
} # end foreach
    
} # end function
    
    
function notify(){
        foreach (
array_keys($this->_observers) as $key ){
            
$observer =& $this->_observers[$key];
            
$observer->update($this);
        }
# end foreach
    
} # end function
    
    
function getState(){
        return
$this->_message;
    }
# end function
    
    
function setState($info){
        
$this->_message = $info;
        
$this->notify();
    }
# end function    
} # end class
?>

...example instantiation of Observer object and attachment of event hander

001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
029 
<?php
/////////
// This code is in application_top.php
/////////
/*
* Initialize the error handler (observer) class as a Singleton
* and attach the screen output object
*/
    
$errorHandler =& Singleton::getInstance('Observer', 'ErrorHandler');
    
$errorHandler->attach(Singleton::getInstance('ScreenOutputErrorLogger'));

/*
* Set the custom error handler function
*/
    
set_error_handler('observerErrorHandler');

/////////
// This code is a general (callback) function
/////////
  
function observerErrorHandler($errno, $errstr, $errfile, $errline, $errcontext){
      
$handler =& Singleton::getInstance('Observer', 'ErrorHandler');
    
$handler->setState( array('number' => $errno,
                              
'msg' => $errstr,
                              
'file' => $errfile,
                              
'line' => $errline
                              
)
                      );
  }
?>

ScreenOutputErrorLogger event handler class

001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
<?php
class ScreenOutputErrorLogger{
    var
$_errors;
    
    function
ScreenOutputErrorLogger(){
        
$this->_errors = array();
    }
# end constructor
    
    
function update(&$error_handler){
        
$error = $error_handler->getState();
        
$this->_errors[] = $error;
    }
# end function
    
    
function errorCount(){
        return
sizeof($this->_errors);
    }
# end function
    
    
function output($hidden = false){
        if (
$hidden) echo '<!--' . "\n";
        echo
'<h1>Errors:</h1>' . "\n";
        echo
'<pre>' . "\n";
        
print_r($this->_errors);
        echo
'</pre>' . "\n";
        if (
$hidden) echo '//-->' . "\n";
    }
# end function
    
} # end class
?>

The basic operation is that once an Observer is instantiated other objects can register as an event handler. The great benefit is that there can be multiple event handlers for each! So, the ErrorHandler object is instantiated and then directly after that the ScreenOutputErrorLogger is attached. Thus, every non-fatal error that is triggered will send the Listener state to every object that is registered for notification (right now only the screen logger). The flexibility in this system is that other objects can be registered as well. As an example, we will create the email object next which can be registered as an event handler and email the administrator on database errors (instead of killing the script). In fact, we can create as many event handlers as we want. There could easily be a logger event handler that saves the errors to database or text file. The point is that event handlers can be attached and detached as needed without affecting the function of the others.

Another development milestone is the true tiered architecture. We have implemented a classic 4 tier architecture: presentation (template engine), business logic (meat and bones manipulating object interaction), accessor (database access), and persistence (database). We have tested the architecture by placing each tier on a different server that is physically separate from the others. The application performed beautifully and is confirmation the tiered architecture is complete and bug free.

This ground-up build has enabled me to finally implement my custom rolled template engine! There is no PHP in the templates and is completely separate from the code. Thus, inexperienced webmasters can tweak and modify the templates all they want without ever corrupting the core code. In addition, I feel a robust templating engine will afford more designers to quickly create skins. Here is the template class code:

Template engine class

001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
029 
030 
031 
032 
033 
034 
035 
036 
037 
038 
039 
040 
041 
042 
043 
044 
045 
046 
047 
048 
049 
050 
051 
052 
053 
054 
055 
056 
057 
<?php
class Template{
    
    var
$template;
    var
$variables;
    
    function
Template($template = ''){        
        
$this->template = notNull($template) ? file_get_contents($template) : NULL;
    }
# end class constructor
    
    
function Add($var_name, $var_data){
        
$this->variables[$var_name] = $var_data;
    }
# end fucntion Add()

    
function AddMulti($var_data){
        if (
is_array($var_data)){
            foreach (
$var_data as $name => $data ){
                
$this->variables[$name] = $data;
            }
        }
    }
# end fucntion Add()

    
function ResetVars(){
        
$this->variables = NULL;
    }
# end function
    
    
function EvaluateTag($data, $tag, $params = NULL){
        
$_tag = '<' . $tag;
        if (
notNull($params)){
            
$_tag .= ' ' . $params;
        }
        
$_tag .= '>' . $data . '</' . $tag . '>' . "\n";
        return
$_tag;
    }
# end function
    
    
function Remove($vars){
        if (
is_array($vars) ){
            foreach (
$vars as $index => $varname ){
                unset(
$this->variables[$varname] );
            }
# end foreach
        
} else {
            unset(
$this->variables[$vars]);
        }
    }
# end fucntion Add()
    
    
function Evaluate($direct_output = false){
        
$template = addslashes($this->template);        
        foreach (
$this->variables as $variable => $data ){
            $
$variable = $data;
        }
# end foreach        
        
eval("\$template = \"$template\";");        
        if (
$direct_output ) echo stripslashes($template);
        else return
stripslashes($template);        
    }
# end function Evaluate()
    
} # end class
?>

As you can see, we are making good progress on the build and will soon move onto finalizing the beta version of the shopping cart! However, there is still much left to do in order to launch this project. I still need to coordinate the acquisition of a dedicated server to host the project Subversion server. In addition, we need to attract a community to help in the beta testing. It is almost time to launch!

...almost there...stay tuned!

Friday, August 19, 2005

Application tiers, SOAP interfaces, and XSL transformations

I get a lot of instant messages asking me how the shopping cart project is coming along so thought a quick post about progress would be in order.

First, I have agreed to help a close friend (Chris Larocque) code his application and in return he has agreed to help with foundation coding of the shopping cart. The great benefit to both of us is that the two applications are nearly identical in architecture and use of design patterns. For example, one requirement for Chris's project is a fully tiered application with tight integration of local versus SOAP gateway interface for the accessor tier.

So, we have identified core architecture features of both applications:

  • Traditional tiers (presentation, business logic, accessor, and persistence)
  • Gateway interface between tiers that support local and remote access (via SOAP)
  • Robust template engine for complete separation of presentation and business logic

In addition, we are going to implement a modular structure that will provide for hooks and may in the future be developed into a plug-n-play feature that is common with a CMS. However, right now it will be coded for data presentation modules as core modules will inevitably have code clashes.

A primary focus will be on performance and scalability. The tiered architecture with remote data access will provide the ability to physically separate the tiers on different servers and will also allow for clustered server load balancing. The end result is an infinitely scalable application that can handle Ebay or Amazon traffic volumes yet realize an insignificant degradation in page rendering performance. Of course if all the tiers are local to the same server it can save the overhead of creating web services and run faster with local access.

A secondary focus will be on the templating. I am seriously considering using XML data / XSL server side transformation for the actual templating but there is a learning curve. I'm most used to traditional templating engines but the power of XSL transformations are apparent.

OK. so now let's talk about timeframes. We expect to complete Chris's application within a week or two and then move on to polishing the various functions. Thus, once Chris's application is built it will serve as a guide for the shopping cart. Hopefully, this will decrease development time and give an indication of areas that need special attention.

Tuesday, August 16, 2005

PHP Design Patterns

Would this be more efficient with a Singleton, Iterator, Factory, Strategy, or Model-View-Controller design pattern?

The basic question of whether a design pattern will fit a particular task better than the usual prcedural script method is one asked by many coders over the course of any application build. Unfortunately, it has been some 7 or 8 years since I took the C++ class in college that covered patterns. Thus, I have found that my knowledge is really out of date with current patterns.

I started my search on a good reference for current PHP design patterns and found a great book: php|architect's Guide to PHP Design Patterns ($32.99 USD)

This book is one of the best references for PHP design patterns that is in my library. There are many examples for not only PHP5 but also PHP4 adaptations. The problem with PHP4 is that a lot of traditionally OOP features are not implemented...but there are a few workarounds. If you are into high level or professional PHP coding I highly recommend you get a copy.

Thursday, May 12, 2005

Owner of osc-help.net identified!

The site owner of the osCommerce contribution help website has been identified as Rigadin! I can't stress enough the usefullness of the site for osCommerce store owners since it provides a level of service and features concerning contributions that is seriously lacking in the community. Great job Chris! Keep up the good work!

Wednesday, May 11, 2005

osC Help - The site that helps you choosing your osCommerce contributions

I just stumbled across the osC Contribution Help website and must say that I'm THOROUGHLY impressed by their completeness of service.
From their homepage:
  • Automatic notification of contribution update.
  • Screenshots display when available.
  • Many categories to group the contributions.
  • Cross-reference between related contributions.
  • Contribution rating and reviews system.
  • Weekly newsletter with new and updated contributions.
  • Link to original osCommerce contribution page.
  • Link to support forum thread.
  • But: no contribution download from this site.
I highly recommend all osCommerce store owners stop by and take a look at the services offered by this website. I have no idea who is behind the genius idea but will give them full credit when I do find out! In my opinion, this is one of the best osCommerce resource sites for store owners. Don't be caught with your pants down...visit this site!

Thursday, April 28, 2005

osCommerce MS-2.2 API Documentation

osCommerce MS-2.2 API Documentation is published and maintained by Carine who is a very active and helpful support forum member. She has published several well coded contributions and is also a community sponsor. The osCommerce API documentation is generated by phpDocumentor which does a nice job of creating a cross-referenced structure. The only shortcoming is that it creates the documentation based on comments in the scripts...which are hardly not present in the stock code. I wish Carine the best of luck developing this resource as it will serve many novice osCommerce coders well!

Tuesday, April 26, 2005

Ultimate SEO URLs v3.0 Features

Ultimate SEO URLs v3.0 Development was posted today as an open call to the community to offer their feedback as to requested features of the next generation of SEO URLs. It is so much easier to add features while in development than to add then later in maintenance releases. Planned development for v3.0 series:
  • Abstract the code
  • Integration of automatic 301 redirect script
  • Introduce more cache features
  • More scalable code
  • Better regex for HTML characters
  • Ability to choose URL keywords
  • Improved install/un-install script for database settings

Monday, April 25, 2005

Ultimate SEO URLs - by Chemo [support thread]

Ultimate SEO URLs - by Chemo contribution has been released since mid January 2005 and already up to 50 pages of support! Most people don't realize the amount of work it takes to create, release, support, and maintain a good contribution...epecially one as active and popular as Ultimate SEO URLs. I've invested huge amounts of time on this contribution in particular since it is an area that the osCommerce application is lacking. The traditional SEF option merely creates an atificial directory structure that will put the product pages 6 or 7 levels deep! The farther away from the domain root the less relevancy of that page (or so the theory goes). Creating contributions is a thankless job. I've released more than I can count and have received countless "this is broken" or "your code broke my site" nasty-o-gram emails and only 4 genuine and heartfelt THANK YOU's. Nobody releases a contribution to get rich or even make enough money from donations to buy a cup of coffee...however, we sure as hell don't do it to get the negative feedback either. However, as of late there have been a few store owners posting very positive feedback on how the contribution affected their traffic. It is very satisfying to read these as it reminds me of why I support the osCommerce community -> helping store owners. So, the next question is what to do with the contribution in terms of future development? The code is mature and production ready in it's current state. I have even offered an automatic redirect script that sends 301 headers for old URLs to new URLs thereby preserving the established page seniorities. It is feature rich, easy to install, and very functional. Can I improve it? I would like to create a base class for the code instead of embedding it into the tep_href_link() function. This will make for easier upgrades and offer a level of abstraction. Both of these are important since 95% of store owners think PHP reads like Latin. By creating a class that can easily be upgraded by simply overwriting the file I will surely eliminate the extra support from those that error in cut-n-paste directions. The main benefit is that once abstacted it can be used on the admin side for scripts that create URLs for datafeeds (Froogle, etc). There have been a lot of store owners report postiive benefits from the contribution on the catalog side but their data feed URLs still use old parameter driven ones.

Sunday, April 17, 2005

Custom Coding & Contributions

What would my blog be without mentioning Chris's website? This is the site for Chris Larocque who is one of the fastest rising stars of the osCommerce coder community. There are not many that have the talent and potential as Chris does. We have worked on several projects collaboratively such as the JS Infobox contribution for osCommerce. If anyone needs subcontract programming done I highly recommend Chris for their needs. Chris is the only person in the world that has ever received FTP and admin credentials to my osCommerce development server.

Saturday, April 16, 2005

John Colascione on Website Marketing

This is one of the most informational articles on beginning website marketing and should be required reading for all new store owners. It has a thorough presentation of search engine and algo basics as well as some more advanced theories. Highly recommended reading!

Sunday, February 27, 2005

Chemo's Corner

Chemo's Corner Of course the second entry in this blog will have to cover my osCommerce development server! This is the domain that I use for development of contributions, client custom coding, or just to try new stuff out. Here are some quick links to important parts of the site:
  • osCommerce Contribution List This page has a list of my publicly released osCommerce contributions. Also, each entry has a short description.
  • osCommerce Programming Portfolio This page has a quick list of sites that I have modified code for. I have plastered everywhere the fact that I'm NOT a designer yet some people still don't grasp the facts. The sites listed on the portfolio page are NOT my design but have been modified, optimized, or otherwise "fixed" by my hand.
  • Chemo's Search Engine Simulator - Beta This tool is currently under development as a future replacement for the stock osCommerce search function. As the number of contributions installed by a store owner increases the less relevant the search becomes. Currently, it can be used to check a stores meta and page content. In addition, it has a selectable user agent (Googlebot, Chemo's Spider, and Firefox) and is a highly effective test for osCsid settings.
  • Chemo's PHP Code Pastebin This tool allows developers to exchange code easily. Simply paste the code into the bin and allow someone to submit revisions.

osCommerce Profile - Chemo

osCommerce Profile - Chemo This is a link to my osCommerce support forum profile. The list of contributions and contact information should be current no matter when you read this blog.

osCommerce, Open Source E-Commerce Solutions

osCommerce, Open Source E-Commerce Solutions The first post of the blog has to be a quick note to the osCommerce development team: reorganize the team.