Case Study: Handling MySQL Growth With a PHP Class
Sick of updating your MySQL database to add new fields half way through a project? In this article Bjorn discusses his PHP class that you can use to make changes to your MySQL database on the fly!
Case Study: Handling MySQL Growth With a PHP Class - The Tricky Part (Page 3 of 5 )
Here comes the tricky part -– keeping the structure defined in the object and the structure of the database and its tables in sync. Here's the entire function, called syncTable:
function syncTable() { // Step 1: Create table if it does not exist $fullSQL = "CREATE TABLE IF NOT EXISTS `$this->tableName` ("; for( $i=0; $i<count($this->fields); $i++) { $fieldName = $this->fields[$i][0]; $fullSQL .= "`$fieldName`"." ".$this->fields[$i][1].", "; } $fullSQL .= "PRIMARY KEY ($this->uniqueField));";
// Execute query on database $result = WSdb::query($fullSQL);
// Step 2. Traverse through the fields and see if they match, if not -modify $sql = "SHOW FIELDS FROM `$this->tableName`"; $result = WSdb::query($sql);
// populate the table_fields array with results while($row=mysql_fetch_array($result)) { $table_fields[] = array($row[0],$row); } $this->table_fields = $table_fields;
// Traverse through alle the field in the structure and compare for( $i=0; $i<count($this->fields); $i++) { // The following code simply runs through the array searching for // a field with the same name from the table_fields array. $fieldName = $this->fields[$i][0]; $fieldExists = false; $fieldPosition = -1; // holds the position of the field in the table_fields array
if($fieldExist) { // We found the field, now we can move on! :) // the names match, does the type? $field_type = substr($this->fields[$i][1],0,strlen($table_fields[$i][1][1])); if($field_type==$table_fields[$i][1][1]) { echo "Field match! Field comparator : ".$this->fields[$i][0]." $field_type<br>"; $this->fields_ok[] = $this->fields[$i]; } // the type does not match, modify it else { $sql = "ALTER TABLE `$this->tableName` CHANGE `$fieldName` `$fieldName` ".$this->fields[$i][1]; echo $sql."<br>"; $result = WSdb::query($sql); $this->fields_ok = $this->fields[$i]; } } } // for $j.. } // for $i if(count($this->fields_ok)==count($this->fields) ) { echo "<strong>all fields are OK! :) </strong><br>"; } else { echo "<strong>there are some fields missing</strong> <br>"; for( $i=0; $i<count($this->fields); $i++) { $field_is_ok = false; $fieldName = $this->fields[$i][0]; for( $j=0; $j<count($this->fields_ok); $j++) { if($fieldName==$this->fields_ok[$j][0]) { $field_is_ok = true; } } if(!$field_is_ok) { $this->missing_fields[] = $this->fields[$i]; } } // Now that we've found the fields that are missing, add them for( $i=0; $i<count($this->missing_fields); $i++) { $sql = "ALTER TABLE `$this->tableName` ADD `".$this->missing_fields[$i][0]."` ".$this->missing_fields[$i][1]; echo $sql."<br>"; $result = WSdb::query($sql); $this->fields_added = true; } } }
Don't be confused by the code. It works... believe me! Here's a basic overview of what the code does:
Create the table if it doesn’t exist
Get the list of fields from the table and store them in an array
Run through the list of fields and match the names
If the names match, see if the field types match (ex: int(11) == int(11) )
If the field types match, nothing needs to be done
If they don’t match, update the field so they match
If the field name is not found, then add the field to the table
That's it! But there are some details I left out when showing you the class WSDynamicObject. Here is the complete variable list of the class:
class WSDynamicObject { var $fields; // an array of the fields in this structure var $newobject; // is this a new object or loaded values from db? var $table_fields; // the database equivalent of $this->fields var $fields_ok; // control-list during update var $missing_fields;// a list over the fields not added to the table var $formmode; }