HomePHP Page 3 - Building Object-Oriented Database Interfaces in PHP: Processing Data through Data Access Objects
Source code ahead: listing the code for the "DBIGenerator" class - PHP
With websites now featuring full-blown dynamic applications that link to databases, data accessing has become a critical process. Often, an object-oriented solution is wanted to manage the data access operations. This works well, except when certain statements are hard-coded in that can cause headaches when a update is required. Alejandro Gervasio explains how a new category of tools, known as database interfaces, help to solve this problem.
In order to have a general idea of the structure of the class, its first version looks like this:
class DBIGenerator{ // define data members var $name; var $path; var $options; function DBIGenerator($name='DEFAULTNAME.php', $path='DEFAULTPATH/',$options=array()){ $this->name=$name; $this->path=$path; $this->options=$options; } function create(){ // create class data members definition $str='<?php'."n"; $str.='class '.$this->name.'{'."n"; foreach($this->options as $option){ $str.='var $'.$option.'='';'."n"; } // create constructor $str.='function '.$this->name.'(){}'."n"; // create modifiers and accessors foreach($this->options as $option){ $str.='function set'.$option.'($'.$option.'){'."n"; $str.='$this->'.$option.'=$'.$option.';'."n"; $str.='}'."n"; $str.='function get'.$option.'(){'."n"; $str.='return $this->'.$option.';'."n"; $str.='}'."n"; } // create "submit()" method $str.='function submit(&$db){'."n"; // build insert query $str.='$sql="INSERT INTO users SET '; foreach($this->options as $option){ $str.=($option!='id')?$option.'='$this->'.$option.'',':''; } $str.='";'."n"; // remove trailing comma $str=preg_replace("/,"/",""",$str); // perform query $str.='$db->performQuery($sql);'."n"; $str.='$this->id=&$db->getInsertID();'."n"; $str.='}'."n"; // create "load" method $str.='function load(&$db){'."n"; // build query $str.='$sql="SELECT * FROM users WHERE id='$this->id'";'."n"; // perform query $str.='$result=$db->performQuery($sql);'."n"; $str.='$row=$result->fetchRow();'."n"; $str.='return $row;'."n"; $str.='}'."n"; // create "update" method $str.='function update(&$db){'."n"; // build query $str.='$sql="UPDATE users SET '; foreach($this->options as $option){ $str.=($option!='id')?$option.'='$this->'.$option.'',':''; } // remove trailing comma $str=preg_replace("/,$/","",$str); $str.=' WHERE id='$this->id'";'."n"; // perform query $str.='$db->performQuery($sql);'."n"; $str.='}'."n"; // create "delete" method $str.='function delete(&$db){'."n"; // build query $str.='$sql="DELETE FROM users WHERE id='$this->id'";'."n"; // perform query $str.='$db->performQuery($sql);'."n"; $str.='}'."n"; $str.='}?>'; // write contents to class file $fp=fopen($this->path.$this->name.'.php',"w") or die('Error creating class file'); fwrite($fp,$str); fclose($fp); } function getObject(){ // create object if(file_exists($this->path.$this->name.'.php')){ require_once($this->path.$this->name.'.php'); return new $this->name; } return false; } }
As mentioned before, let's dissect the class code to properly understand what it does. To begin with, the constructor accepts as parameters the name of the DB interface to be created, defined as $name; the path where the class file will be physically located, that is $path; and finally an $options array that directly represents the field names of the database table tied to the interface. Again, this is merely for example purposes. Once we've finished developing our "DBIGenerator" class, it will be capable of handling the table fields for us.
As you can see, I've specified default values for the name of the DB interface class, as well as for the path where it will be generated. The constructor simply assigns these arguments as class properties:
function DBIGenerator($name='DEFAULTNAME.php', $path='DEFAULTPATH/',$options=array()){ $this->name=$name; $this->path=$path; $this->options=$options; }
Now, let's take a look at the "create()" method, which handles the process to create the proper class file for making the DB interface work.
In general terms, all that this method does is concatenate strings, in order to build the different methods that will compose the DB interface class. Based on this simple principle, the data members' declaration and the constructor are built as follows:
// create class data members definition $str='<?php'."n"; $str.='class '.$this->name.'{'."n"; foreach($this->options as $option){ $str.='var $'.$option.'='';'."n"; } // create constructor $str.='function '.$this->name.'(){}'."n";
See how the class code is being progressively generated? That's not rocket science at all. So, let's get on with the next sections of code, showing how the modifiers and accessors are created:
// create modifiers and accessors foreach($this->options as $option){ $str.='function set'.$option.'($'.$option.'){'."n"; $str.='$this->'.$option.'=$'.$option.';'."n"; $str.='}'."n"; $str.='function get'.$option.'(){'."n"; $str.='return $this->'.$option.';'."n"; $str.='}'."n"; }
Using a regular "foreach" loop, the "set()" and "get()" methods are generated for each option passed as an argument. To clarify things, let's say that we've passed a table field parameter named "firstname." As a result, the DB interface class will have two methods, "setfirstname()" and "getfirstname()" respectively. In a similar way, if we have an "id" field name, the proper "setid()" and "getid()" methods will be created.
By this time, I assume the underlying idea of generating the class code is already understood. The next step is to create the "submit()", "load()", "update()" and "delete()" methods, useful for locating DML statements within the class structure. The next section of the article explains the mentioned methods.