Login   Register  
PHP Classes
elePHPant
Icontem

File: class.SQLData.template

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Richard Munroe  >  SQL Data  >  class.SQLData.template  >  Download  
File: class.SQLData.template
Role: Auxiliary data
Content type: text/plain
Description: C++ template like class for generating proper inhertances to specific database implementations.
Class: SQL Data
Generate classes to store objects in SQL databases
Author: By
Last change: In the event that include_once doesn't do the right thing, prote
ct the class with defined brackets.
Date: 2007-12-26 08:14
Size: 13,194 bytes
 

Contents

Class file image Download
<?php

/**
 * @author Dick Munroe <munroe@csworks.com>
 * @copyright copyright (c) Dick Munroe, 2004-2007, All rights reserved.
 * @license http://www.csworks.com/publications/ModifiedNetBSD.html
 * @version 2.0.0
 */

//
// Base class for any object backed by SQL data.
//
// Edit History:
//
//  Dick Munroe munroe@csworks.com 09-Oct-2004
//      Initial Version Created.
//
//  Dick Munroe munroe@csworks.com 13-Oct-2004
//      Add a function to return all field names for a table.
//
//  Dick Munroe munroe@csworks.com 28-Oct-2004
//      Need to check for identity of null in constructions that
//      build SQL inserts and updates.
//
//  Dick Munroe munroe@csworks.com 06-Nov-2004
//	Normalize naming conventions.
//	Add a next function that allows reloading of the class from the "next"
//	row a a result.
//	Add a function that tells you if the data has been modified.
//
//  Dick Munroe munroe@csworks.com 08-Nov-2004
//	quote field names to avoid clashes with reserved words.
//
//  Dick Munroe munroe@csworks.com 16-Nov-2004
//	Added a way to unset data from the object.
//
//  Dick Munroe munroe@csworks.com 17-Nov-2004
//	Made the code formatting consistent with that used
//	by emacs in php mode with default settings.
//
//  Dick Munroe munroe@csworks.com 05-Dec-2004
//	Add in is_set function to determine if data exists
//	in the fields collection.
//
//  Dick Munroe munroe@csworks.com 06-Dec-2004
//	next would corrupt m_sqlFields if there was no data returned
//	by next
//
//  Dick Munroe munroe@csworks.com 08-Dec-2004
//	The update and insert methods should clear the modified
//	data flags.
//
//  Dick Munroe munroe@csworks.com 22-Dec-2004
//	Select should take a null selector and use needUpdateSelector.
//
//  Dick Munroe munroe@csworks.com 14-Mar-2006
//		Change licensing, reorganize includes.
//
//	Dick Munroe (munroe@csworks.com) 15-Oct-2006
//		Add database independence.
//
//	Dick Munroe (munroe@csworks.com) 26-Dec-2007
//		In the event that include_once doesn't do the right thing, protect the
//		class with defined brackets.
//

if (!class_exists('SQLData[DATABASE-SPECIALIZATION]'))
{
	include_once('dm.DB/class.[DATABASE-SPECIALIZATION].DB.php') ;
	include_once('SDD/class.SDD.php') ;

	class SQLData[DATABASE-SPECIALIZATION] extends [DATABASE-SPECIALIZATION]DB
	{
		var $m_modified = array() ;
		var $m_sqlFields = array() ;
		var $m_tableName = "" ;

		function SQLData[DATABASE-SPECIALIZATION](
			$_tableName,
			$_dataBase,
			$_host='localhost',
			$_login="",
			$_password="")
		{
			$this->m_tableName = $_tableName ;

			//
			// Initialize the database connection for this database.  The connection
			// resource is saved although it generally isn't used.
			//

			$this->[DATABASE-SPECIALIZATION]DB($_login, $_password, $_dataBase, $_host) ;
			$theConnection = $this->connect() ;

			if (is_string($theConnection))
			{
				die($theConnection) ;
			}
		}

		function death($theMessage)
		{
			print("<br><br>") ;
			$this->print_rd(debug_backtrace()) ;
			print("<br><br><bold)") ;
			print($theMessage) ;
			print("</bold>") ;
			die() ;
		}

		function print_rd($theVar)
		{
			print("<pre>\n") ;
			print_r($theVar) ;
			print("</pre>") ;
			print("<br>") ;
		}

		function print_r()
		{
			print(SDD::dump($this, !empty($_SERVER['DOCUMENT_ROOT']))) ;
		}

		function getTableFieldNames()
		{
			$theFieldsArray = $this->describeTable($this->m_tableName) ;

			if ($this->hasErrors())
			{
				return false ;
			}

			while ($theResultArray = $this->fetchAssoc())
			{
				array_push($theFieldsArray, $theResultArray['Field']) ;
			}

			return $theFieldsArray ;
		}

		function getFields()
		{
			return $this->m_sqlFields ;
		}

		function getModified()
		{
			return $this->m_modified ;
		}

		function get($field)
		{
			if (isset($this->m_sqlFields[$field]))
			{
				return $this->m_sqlFields[$field] ;
			}
			else
			{
				return null ;
			}
		}

		function initFields($theFields)
		{
			foreach ($theFields as $theField => $theValue)
			{
				$this->init($theField, $theValue) ;
			}
		}

		function init($field, $value)
		{
			$this->m_sqlFields[$field] = $value ;
			$this->m_modified[$field] = false ;
			if (is_object($value))
			{
				if (!is_subclass_of($value, 'SQLData'))
				{
					$this->death('Attempting to insert an object not a subclass of SQLData (' . get_class($value) . ')') ;
				}
			}
			else if (is_array($value))
			{
				foreach ($value as $theIndex => $theElement)
				{
					if (!is_subclass_of($theElement, 'SQLData'))
					{
						$this->death('Attempting to insert an object not a subclass of SQLData (' . get_class($theElement) . ')') ;
					}
				}
			}
		}

		//
		// True if any of the fields of the class have been modified.
		// false otherwise.
		//

		function modified()
		{
			foreach ($this->modified as $theIndex => $theFlag)
			{
				if ($theFlag)
				{
					return true ;
				}
			}

			return false ;
		}

		//
		// Force the state of the modified flags.
		// As per the insert, update, and delete logic, arrays and objects are
		// always forced to false.
		//

		function forceModified($theState = true)
		{
			if ($theState)
			{
				$theState = 'true' ;
			}
			else
			{
				$theState = 'false' ;
			}

			$this->m_modified =
				array_map(
					create_function(
						'$a',
						sprintf('
	if ((is_array($a)) || (is_object($a)))
		return false ;
	else
	return %s ;
	',
							$theState)),
					$this->m_sqlFields) ;
		}

		//
		// populate the class with the next value from the last query.
		// Internal state is reset so that no lingering data is left.
		//

		function next()
		{
			$this->reset() ;

			if (($xxx = $this->fetchAssoc()) !== false)
			{
				$this->m_sqlFields = $xxx ;
			}

			if ($this->hasErrors())
			{
				return false ;
			}

			if (!($this->m_sqlFields))
			{
				return false ;
			}

			foreach($this->m_sqlFields as $theFieldName => $theFieldValue)
			{
				$this->m_modified[$theFieldName] = false ;
			}

			return true ;
		}


		function reset()
		{
			$this->m_sqlFields = array() ;
			$this->m_modified = array() ;
		}

		function setFields($theFields)
		{
			foreach ($theFields as $theField => $theValue)
			{
				$this->set($theField, $theValue) ;
			}
		}

		//
		// The set function allows objects and arrays, but forces these items
		// to be set to "unmodified".  They will be processed assuming that
		// they are SQLData objects (which they will be because the set forces
		// them to be that).
		//

		function set($field, $value)
		{
			$this->m_sqlFields[$field] = $value ;
			if (is_object($value))
			{
				$this->m_modified[$field] = false ;
				if (!is_subclass_of($value, 'SQLData'))
				{
					$this->death('Attempting to insert an object not a subclass of SQLData (' . get_class($value) . ')') ;
				}
			}
			else if (is_array($value))
			{
				$this->m_modified[$field] = false ;
				foreach ($value as $theIndex => $theElement)
				{
					if (!is_subclass_of($theElement, 'SQLData'))
					{
						$this->death('Attempting to insert an object not a subclass of SQLData (' . get_class($theElement) . ')') ;
					}
				}
			}
			else
			{
				$this->m_modified[$field] = true ;
			}
		}

		function is_set($field)
		{
			return isset($this->m_sqlFields[$field]) ;
		}

		function un_set($field)
		{
			unset($this->m_sqlFields[$field]) ;
			unset($this->m_modified[$field]) ;
		}

		//
		// The select function will not fill out an object with all it's related
		// tables.  That's a job for the specific application object.
		//

		function select($theSelector=null)
		{
			//
			// Note that this assumes that only one row is returned by the selector.
			//

			if (!$this->rawSelect($theSelector))
			{
				return false ;
			}

			return $this->next() ;
		}

		function rawSelect($theSelector=null)
		{
			if ($theSelector === null)
			{
				$theSelector = $this->needUpdateSelector() ;
			}

			$theSQL = "SELECT * FROM " . $this->m_tableName . " " . $theSelector . " ;" ;

			$theResult = $this->query($theSQL) ;

			if ($this->hasErrors())
			{
				return false ;
			}

			return true ;
		}

		//
		// However, insert and update CAN call the update functions for all
		// sub objects, which they will do.
		//

		function insert()
		{
			//
			// The first thing to do is to walk the object's data and for
			// all enclosed objects, call their insert functions.  This will
			// work because there isn't any selector the call.  If I want
			// update to have this capability as well, I'll need to figure out
			// a way to get at a selector.
			//

			foreach ($this->m_sqlFields as $theField => $theValue)
			{
				if (is_object($theValue))
				{
					if (!$theValue->insert())
					{
						return false ;
					}
				}
				else if (is_array($theValue))
				{
					foreach ($theValue as $theArrayIndex => $theArrayValue)
					{
						if (!$theArrayValue->insert())
						{
							return false ;
						}
					}
				}
			}

			//
			// Now update the contents of all the modified fields.
			//

			$theSQL = "insert into " . $this->quoteIdentifier($this->m_tableName) . " (" ;

			$insertRequired = false ;

			foreach ($this->m_modified as $field => $modified)
			{
				if ($modified)
				{
					$insertRequired = true ;

					$theSQL .= $this->quoteIdentifier($field) . ", " ;
				}
			}

			if ($insertRequired)
			{
				$theSQL = substr($theSQL, 0, strlen($theSQL) - 2) . ") VALUES (" ;
			}
			else
			{
				$theSQL .= ") VALUES (" ;
			}

			foreach ($this->m_modified as $field => $modified)
			{
				if ($modified)
				{
					if (isset($this->m_sqlFields[$field]))
					{
						if ($this->m_sqlFields[$field] === null)
						{
							$theSQL .= "NULL, " ;
						}
						else
						{
							$theSQL .= "'" . $this->escape_string($this-> m_sqlFields[$field]) . "', " ;
						}
					}
					else
					{
						$theSQL .= "NULL, " ;
					}
				}
			}

			if ($insertRequired)
			{
				$theSQL = substr($theSQL, 0, strlen($theSQL) - 2) . ")" ;
			}
			else
			{
				$theSQL .= ")" ;
			}

			$this->query($theSQL) ;

			if ($this->hasErrors())
			{
				return false ;
			}
			else
			{
				$this->forceModified(false) ;
				return true ;
			}
		}

		function update($theSelector = null)
		{
			//
			// The first thing to do is to walk the object's data and for
			// all enclosed objects, call their update functions.
			// Each object is required to define a needUpdateSelector or
			// provide an explicit selector for each call to update and
			// define needUpdateSelector functions for any SQLData objects
			// contained in the one being written.
			//

			foreach ($this->m_sqlFields as $theField => $theValue)
			{
				if (is_object($theValue))
				{
					if (!$theValue->update())
					{
						return false ;
					}
				}
				else if (is_array($theValue))
				{
					foreach ($theValue as $theArrayIndex => $theArrayValue)
					{
						if (!$theArrayValue->update())
						{
							return false ;
						}
					}
				}
			}

			if ($theSelector == null)
			{
				$theSelector = $this->needUpdateSelector() ;
			}

			$theSQL = "update " . $this->m_tableName . " set " ;

			$updateRequired = false ;

			foreach ($this->m_modified as $field => $modified)
			{
				if ($modified)
				{
					$updateRequired = true ;

					if (isset($this->m_sqlFields[$field]))
					{
						if ($this->m_sqlFields[$field] === null)
						{
							$theSQL .= $this->quoteIdentifier($field) . "=NULL, " ;
						}
						else
						{
							$theSQL .= $this->quoteIdentifier($field) . "='" . $this->escape_string($this->m_sqlFields[$field]) . "', " ;
						}
					}
					else
					{
						$theSQL .= $this->quoteIdentifier($field) . "=NULL, " ;
					}
				}
			}

			if ($updateRequired)
			{
				$theSQL = substr($theSQL, 0, strlen($theSQL) - 2) . " " . $theSelector . ";" ;

				$this->query($theSQL) ;

				if ($this->hasErrors())
				{
					return false ;
				}
				else
				{
					$this->forceModified(false) ;
					return true ;
				}
			}
			else
			{
				return true ;
			}
		}

		//
		// However, insert, update and delete CAN call the update functions for all
		// sub objects, which they will do.
		//

		function delete($theSelector=null)
		{
			//
			// The first thing to do is to walk the object's data and for
			// all enclosed objects, call their delete functions.  This will
			// work because there isn't any selector the call.  If I want
			// update to have this capability as well, I'll need to figure out
			// a way to get at a selector.
			//

			foreach ($this->m_sqlFields as $theField => $theValue)
			{
				if (is_object($theValue))
				{
					if (!$theValue->delete())
					{
						return false ;
					}
				}
				else if (is_array($theValue))
				{
					foreach ($theValue as $theArrayIndex => $theArrayValue)
					{
						if (!$theArrayValue->delete())
						{
							return false ;
						}
					}
				}
			}

			if ($theSelector == null)
			{
				$theSelector = $this->needUpdateSelector() ;
			}

			$theSQL = "delete from " . $this->quoteIdentifier($this->m_tableName) . " " . $theSelector ;

			$this->query($theSQL) ;

			return !$this->hasErrors() ;
		}

		function needUpdateSelector()
		{
			$this->death("The subclass must provide selectors for all classes on request.") ;
		}
	}
}
?>