[geeklog-cvs] MVCnPHP PersistenceManager.class.php,NONE,1.1.2.1 CHANGELOG,1.3,1.3.2.1 Constants.php,1.2,1.2.2.1 README.txt,1.4,1.4.2.1

tony at iowaoutdoors.org tony at iowaoutdoors.org
Tue Dec 14 15:23:22 EST 2004


Update of /var/cvs/MVCnPHP
In directory www:/tmp/cvs-serv21609

Modified Files:
      Tag: rel-1-0-php5-port
	CHANGELOG Constants.php README.txt 
Added Files:
      Tag: rel-1-0-php5-port
	PersistenceManager.class.php 
Log Message:
Merging...will this work?


Index: Constants.php
===================================================================
RCS file: /var/cvs/MVCnPHP/Constants.php,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -C2 -d -r1.2 -r1.2.2.1
*** Constants.php	14 Jul 2003 16:39:57 -0000	1.2
--- Constants.php	14 Dec 2004 20:23:20 -0000	1.2.2.1
***************
*** 46,50 ****
  define('MVC_TARGET', 'target');
  define('MVC_TYPE', 'type');
! define('MVC_MESSAGE', 'mvc_message');
  define('MVC_ERRORS', 'mvc_errors');
  define('MVC_PRINT', 1);
--- 46,50 ----
  define('MVC_TARGET', 'target');
  define('MVC_TYPE', 'type');
! define('MVC_MESSAGES', 'mvc_messages');
  define('MVC_ERRORS', 'mvc_errors');
  define('MVC_PRINT', 1);

--- NEW FILE: PersistenceManager.class.php ---
<?php

/**
* MVCnPHP - PersistenceManager.class.php
*
* This source file is subject to version 2.02 of the PHP license,
* that is bundled with this package in the file LICENSE, and is
* available at through the world-wide-web at
* http://www.php.net/license/2_02.txt.
* If you did not receive a copy of the PHP license and are unable to
* obtain it through the world-wide-web, please send a note to
* license at php.net so we can mail you a copy immediately.
*
* @author Jason Jones <jason at javacrawl.com>
* @author Tony Bibbs <tony at geeklog.net>
* @copyright Jason Jones 2003
* @package net.geeklog.mvc
* @version $Id: PersistenceManager.class.php,v 1.1.2.1 2004/12/14 20:23:20 tony Exp $
*
*/

/**
* A PHP Object Persistence Class
*
* This class allows seemless integration between your application models
* from a PHP MVC framework and the relational database it will hit.  Use of
* this in MVCnPHP is optional on an application-by-application basis and
* by a model-to-model basis.  Simply put, use it if it saves you time
* which it should.  Apologies to those who may find learning this difficult
* but should you take the time to learn it you should see the benefits of
* using it and MVC in general in your PHP applications.
*
* In addition to mapping your PHP objects to underlying data structures this
* package has the added benefit of handling parent-child relationships between
* models.  Additionally, child models are loaded lazily (as needed) from the
* database or immediately if explicitly asked to.
*
* For you Java nuts out there who happen to be programming PHP, this is loosely
* based on Hibernate.
*
* @author Jason Jones <jason at javacrawl.com>
* @author Tony Bibbs <tony at geeklog.net>
* @package net.geeklog.mvc
*
*/
class PersistenceManager {

    /**
    * Allows you to define DBMS table aliases
    *
    * @access private
    * @var array
    *
    */
    var $_tableAliases = array();
    
    /**
    * Maps model classes to database tables
    *
    * This will map your PHP classes to their corresponding
    * database table.  This should hold mapped entries for
    * all of the models you plan on using in your application
    *
    * @access private
    * @var array
    * @see setClass2TableMapping()
    *
    */
    var $_classTableMap = array('Comment' => 'COMMENT',
                                'Location' => 'LOCATION',
                                'Machine' => 'MACHINE',
                                'Organization' => 'ORGANIZATION',
                                'Role' => 'GMMS_USER_ROLE',
                                'User' => 'GMMS_USER');
                               
    /**
    * Defines foreign key relationships between various models
    *
    * @access private
    * @var array
    * @see setForeignKeys()
    */
    var $_foreignKeys = array('LOCATION.ADDRESS_ID' => 'ADDRESS.ADDRESS_ID',
                              'ORGANIZATION.ADDRESS_ID' => 'ADDRESS.ADDRESS_ID',
                              'ORGANIZATION.RECORDS_ADDRESS_ID' => 'ADDRESS.ADDRESS_ID');
    
    /**
    * Constructor
    *
    * This doesn't currently do anything...it's just a stub
    *
    * @author Jason Jones <jason at javacrawl.com>
    * @access public
    *
    */
    function PersistenceManager()
    {
    }
  
    /**
    * Sets the class-to-table mapping for an application
    *
    * @author Tony Bibbs <tony at geeklog.net>
    * @access public
    * @param array $mappingArray Maps model class names to DB table names
    *
    */
    function setClass2TableMapping($mappingArray)
    {
        $this->_classTableMap = $mappingArray;
    }

    /**
    * Establishes the foreign key relationships between application
    * models
    *
    * @author Tony Bibbs <tony at geeklog.net>
    * @access public
    * @param array $foreignKeyArray Array of foreign key mappings of
    * the form array('<tableA>.<fieldA>' = > <tableB>.<fieldB>', etc.)
    *
    */
    function setForeignKeys($foreignKeyArray)
    {
        $this->_foreignKeys = $foreignKeyArray;
    }
    
    /**
    * Begins a SQL transaction using PEAR::DB
    *
    * @author Tony Bibbs <tony.bibbs at iowa.gov>
    * @access public
    *
    */
    function beginTransaction()
    {
        global $_DB;
        
        $_DB->autoCommit(false);
    }
    
    /**
    * Ends a SQL Transaction using PEAR::DB
    *
    * @author Tony Bibbs <tony.bibbs at iowa.gov>
    * @access public
    * @return boolean True if transaction worked, otherwise false
    *
    */
    function endTransaction()
    {
        global $_DB;
        
        $retval = $_DB->commit();
        
        if (DB::isError($retval)) {
            $retval = $_DB->rollback();
            if (DB::isError($retval)) {
                // Couldn't even rollback, should handle the error
                trigger_error('An error was encoungered in PersistenceManager::endTransaction().  We
                              were unable to roll the transaction back.  NOTE: this means you had two
                              problems, 1) something prevented the commit() to work and 2) the rollbock()
                              did not work');
            }
            $_DB->autoCommit(true);
            return false;
        }
        $_DB->autoCommit(true);
        return true;
    }
    
    /**
    * Inserts a new record for the model 
    *
    * NOTE: dataObject is pass-by-reference in this method
    *
    * Inserts the object into the database.  If the uniquely identifying field
    * is *not* set in the object then this method will assume that it is autogenerated
    * and it will populate the object with the new value
    *
    * @author Jason Jones <jason at javacrawl.com>
    * @access public
    *
    */
    function insert(&$dataObject)
    { 
        global $_DB;
        
        $table = $this->_classTableMap[ucfirst(get_class($dataObject))];
        $attribColumnMap = $dataObject->getAttributeColumnMap();
        $attribValuesMap = get_object_vars($dataObject);
        $uniqueAttributes = $dataObject->getUniqueAttributes();
        $uniqueAutoGenAttribute = NULL;
        $columnValueMap = array();
        foreach ($attribColumnMap as $attribute => $column) {
            $objVal = $attribValuesMap['_' . $attribute];
            if (in_array($attribute, $uniqueAttributes) && $objVal === NULL) {
                // unique attributes not contained in object -- need to return the later
                $uniqueAutoGenAttribute = $attribute;
            }
            if ($objVal !== NULL) {
                $columnValueMap[$column] = $objVal;
            } 
        }
        
        
        // now we need to check for "dotted" column names and handle any inserts that need 
        // to occur before the "main" insert
        $innerInsertTables = array();
        $innerInsertFKeys = array();
        $innerInsertMaps = array(); // array of arrays
        foreach($attribColumnMap as $attribute => $column) {
            if ($dotpos = strpos($column, '.')) {
                // if column is dotted (meaning it's in a PK table)              
                $fKeyCol = substr($column, 0, $dotpos);
                $pKeyEntry = $this->_foreignKeys[$table . '.' . $fKeyCol];
                $pKeyTable = substr($pKeyEntry, 0, strpos($pKeyEntry, '.'));
                $pKeyCol = substr($pKeyEntry, strpos($pKeyEntry, '.')+1);
                $pKeyTargetCol = substr($column, $dotpos+1);
              
                // setup arrays for inner insert later
                if (!array_key_exists($fKeyCol, $innerInsertTables)) {
                    $innerInsertTables[$fKeyCol] = $pKeyTable;
                    $innerInsertMaps[$fKeyCol] = array();
                }
                
                $innerInsertMap = &$innerInsertMaps[$fKeyCol];                
                $innerInsertFKeys[$fKeyCol] = $pKeyTable;
                $innerInsertMap[$pKeyTargetCol] = $columnValueMap[$column];
                
                unset($columnValueMap[$column]);                  
            }
        }
        
        foreach($innerInsertTables as $column => $innerTable) {
            $idResult = $this->_performInsert($innerTable, $innerInsertMaps[$column], FALSE);
            //echo '$idResult=' . $idResult . ' for ' . $column . '<br>';
            if ($idResult !== NULL) {
                $columnValueMap[$column] = $idResult;
                //echo 'setting new value for ' . array_search($column, $attribColumnMap) . ' to ' . $idResult . '<br>';
                $this->_setValueOnObject($dataObject, array_search($column, $attribColumnMap), $idResult);
            }
        }
        
        $idResult = $this->_performInsert($table, $columnValueMap, $uniqueAutoGenAttribute === NULL); 
        
        // NOTE:  This can only handle one autogenerated id column at this time
        if ($uniqueAutoGenAttribute !== NULL AND $idResult !== NULL) {
          $this->_setValueOnObject($dataObject, $uniqueAutoGenAttribute, $idResult);
        }  
        
    }

    /**
    * Loads data into a model given a set of criteria
    *
    * Returns one or more instaces of $class for all rows in the database that
    * are true for the where clause
    *
    * @author Jason Jones <jason at javacrawl.com>
    * @access public
    * @param string $class Name of the model
    * @param string $whereClause Criteria to get records against
    * @param string $orderByClause How to order the resulting data
    * @param string $limitAmount Allows us to limit the number of records retrieved
    * @param string $limitOffset Used to start the retrieval of records at a predefined position
    *
    */ 
    function load($class, $whereClause='1 = 1', $orderByClause='', $limitAmount='', $limitOffset=0) {
        global $_DB;
        
        $result = null;
        $attribMap = call_user_func(array($class,'getAttributeColumnMap'));
        $sqlCols = array();
        
        $fTableAlias = $this->_getTableAlias($this->_classTableMap[$class], 'NONE');
        if (!$fTableAlias) { 
            $fTableAlias = $this->_getNewTableAlias($this->_classTableMap[$class], 'NONE');
        }
        $sqlTableDef = $this->_classTableMap[$class] . ' ' . $fTableAlias;
        
        // need to check for possible joins
        foreach ($attribMap as $attrib => $column) {
            $fKeyTable = $this->_classTableMap[$class];
            if ($dotpos = strpos($column, '.')) {
              // if column is dotted (meaning it's in a PK table)              
              $fKeyCol = substr($column, 0, $dotpos);
              $pKeyEntry = $this->_foreignKeys[$fKeyTable . '.' . $fKeyCol];
              $pKeyTable = substr($pKeyEntry, 0, strpos($pKeyEntry, '.'));
              $pKeyCol = substr($pKeyEntry, strpos($pKeyEntry, '.')+1);
              $pKeyTargetCol = substr($column, $dotpos+1);
              $pTableAlias = $this->_getTableAlias( $fKeyTable, $fKeyCol);
              if (!$pTableAlias) {
                  // need to add join to sqlTableDef
                  $pTableAlias = $this->_getNewTableAlias($fKeyTable, $fKeyCol);
              }
              if (strpos($sqlTableDef, $pTableAlias) === false) {
                  $sqlTableDef .= " LEFT OUTER JOIN {$pKeyTable} {$pTableAlias} ON {$fTableAlias}.{$fKeyCol} = {$pTableAlias}.{$pKeyCol}";
              }
              
              $sqlCols[] = $pTableAlias . '.' . $pKeyTargetCol;
              
            } else {
                $sqlCols[] = $fTableAlias . '.' . $column;
            }
        }
        
        // limit clause (called TOP in SQLServer)
        $orderBy = ($orderByClause ? ' ORDER BY ' . $orderByClause : '');
        
        $sql = 'SELECT ' . $topClause . ' ' . implode(', ',$sqlCols) . ' FROM ' . $sqlTableDef . 
               ' WHERE ' . $whereClause . $orderBy;
        if ($limitAmount) {
          $dbresult = $_DB->limitQuery($sql, $limitOffset, $limitAmount);
        } else {
          $dbresult = $_DB->query($sql);
        }
  
        if (DB::isError($dbresult)) { 
            trigger_error($dbresult->toString(), E_USER_ERROR);
            return;
        }

        while ($row = $dbresult->fetchRow(DB_FETCHMODE_ORDERED)) {
          $instance = new $class();
          foreach ($attribMap as $attrib => $column) {  
              // check for foreign key
              if ($dotpos = strpos($column, '.')) {
                 $fKeyCol = substr($column, 0, $dotpos);
                 $primaryColumn = substr($column, $dotpos+1);                
                 $column = $this->_getPrimaryColDef($class, $fKeyCol, $primaryColumn);
              } else {
                $column = $fTableAlias . '.' . $column;
              }
              $colNum = array_search($column, $sqlCols);
              if ($colNum !== false) {          
                  $dbValue = $row[$colNum];
                  if ($dbValue) {
                      // if a value exists for the column that maps to the attribute, call
                      // the setter on the current instance
                      $this->_setValueOnObject($instance, $attrib, $dbValue);
                  }
              }
          }
          if ($result == null) { 
              $result = $instance;
          } else if (is_object($result)) {
              // if theres an object then this is the second time around and 
              // we shoudl conver $result into an array
              $result = array($result);
              $result[] = $instance;
          } else {
            $result[] = $instance;
          }
          
        }
        $dbresult->free();
       
        return $result;
  
    }
  
    /**
    * Updates data from a given model
    *
    * Updates the data in the object to the database.  Note that this method does so indiscriminantly. 
    * It does *not* know which fields have changed.  DO NOT TRY TO UPDATE THE ID FIELDS.  Or any fields
    * that make up the uniquely identifiable array.  This will yield unpredicatble results.
    *
    * @author Jason Jones <jason at javacrawl.com>
    * @access public
    * @param object $dataObject Model object to get data from
    *
    */
    function update($dataObject) {
        global $_DB;
        
        $table = $this->_classTableMap[ucfirst(get_class($dataObject))];
        $attribColumnMap = $dataObject->getAttributeColumnMap();
        $attribValuesMap = get_object_vars($dataObject);
        $uniqueAttributes = $dataObject->getUniqueAttributes();
        
        // create map for autoExecute()
        $columnValueMap = array();
        foreach ($attribColumnMap as $attribute => $column) {
            // need to skip unique attributes...we can't change these
            $objVal = $attribValuesMap['_' . $attribute];
            if ($objVal !== NULL && !in_array($attribute, $uniqueAttributes)) {                 
                $columnValueMap[$column] = $attribValuesMap['_' . $attribute];
            }
        }
        
        // now we need to check for "dotted" column names and handle any updates that need 
        // to occur before the "main" update
        $innerUpdateTables = array();
        $innerUpdateFKeys = array();
        $innerUpdateMaps = array(); // array of arrays
        foreach($attribColumnMap as $attribute => $column) {
            if ($dotpos = strpos($column, '.')) {
                // if column is dotted (meaning it's in a PK table)              
                $fKeyCol = substr($column, 0, $dotpos);
                $pKeyEntry = $this->_foreignKeys[$table . '.' . $fKeyCol];
                $pKeyTable = substr($pKeyEntry, 0, strpos($pKeyEntry, '.'));
                $pKeyCol = substr($pKeyEntry, strpos($pKeyEntry, '.')+1);
                $pKeyTargetCol = substr($column, $dotpos+1);
              
                // setup arrays for inner Update later
                if (!array_key_exists($fKeyCol, $innerUpdateTables)) {
                    $innerUpdateTables[$fKeyCol] = $pKeyTable;
                    $innerUpdateMaps[$fKeyCol] = array();
                }
                $innerUpdateMap = &$innerUpdateMaps[$fKeyCol];                
                $innerUpdateFKeys[$fKeyCol] = $pKeyTable;
                $innerUpdateMap[$pKeyTargetCol] = $columnValueMap[$column];
                unset($columnValueMap[$column]);                  
            }
        }
        
        foreach($innerUpdateTables as $column => $innerTable) {
            $innerUpdateMap = &$innerUpdateMaps[$column];
            $whereValue = $columnValueMap[$column]; 
            $pKeyEntry = $this->_foreignKeys[$table . '.' . $column];
            $pKeyTable = substr($pKeyEntry, 0, strpos($pKeyEntry, '.'));
            $pKeyCol = substr($pKeyEntry, strpos($pKeyEntry, '.')+1);
            if (is_string($whereValue)) {
                $result = '\'' . $whereValue . '\'';
            }            
            $innerWhereClause = $pKeyCol . ' = ?';
            $innerWhereValue = array($whereValue);
            unset($innerUpdateMap[$column]); 
            $innerResult = $this->_performUpdate($innerTable, $innerUpdateMap, $innerWhereClause, $innerWhereValue); 
            if (DB::isError($innerResult)) { 
                trigger_error($innerResult->toString(), E_USER_ERROR);
            }

        }
       
        $whereClause = $this->_generateWhereClause($dataObject->getUniqueAttributes(), $dataObject, TRUE);       
        $valuesArray = $this->_generateValuesArray($dataObject->getUniqueAttributes(), $dataObject);
        $result = $this->_performUpdate($table, $columnValueMap, $whereClause, $valuesArray); 
        if (PEAR::isError($result)) { 
            trigger_error($result->toString(), E_USER_ERROR);
            return PEAR::raiseError('problem updating record');
        }
    }
  
    /**
    * Deletes a record corresponding to a model
    *
    * Deletes the record that corresponds to this object.  More accurately it deletes the record in the
    * database that has the same values for the uniquely identifying attributes.
    *
    * @author Jason Jones <jason at javacrawl.com>
    * @access public
    * @param object $dataObject Model to delete data for
    *
    */
    function delete($dataObject)
    {
        global $_DB;
        
        $whereClause = $this->_generateWhereClause($dataObject->getUniqueAttributes(), $dataObject);
        $valueArray = $this->_generateValuesArray($dataObject->getUniqueAttributes(), $dataObject);
        
        $sql = "DELETE FROM {$this->_classTableMap[ucfirst(get_class($dataObject))]} WHERE {$whereClause}";
        $preparedStmt = $_DB->prepare($sql);
        $result = $_DB->execute($preparedStmt, $valueArray);
        if (DB::isError($result)) { 
            trigger_error($result->toString(), E_USER_ERROR);
        }
    }
    
    
    /**
    * Generates the right 'alias.column_name' for a column in a table that is linked to the main class
    * as specified in $foreignClass.  Assumes that the alias already exists and it is safe to call 
    * _getTableAlias without checking
    *
    * @author Jason Jones <jason at javacrawl.com>
    * @access private
    * @param string $foreignClass Name of the foreign class
    * @param string $foreignKey Name of foreign key
    * @param string $primaryColumn Primary column name
    * @return string table.fieldname result
    *
    */
	function _getPrimaryColDef($foreignClass, $foreignKey, $primaryColumn)
	{
	    $foreignTable = $this->_classTableMap[$foreignClass];
	    $primaryCombo = $this->_foreignKeys[$foreignTable . '.' . $foreignKey];
	    $dotpos = strpos($primaryCombo, '.');
	    $primaryTable = substr($primaryCombo, 0, $dotpos);
	    $primaryAlias = $this->_getTableAlias($foreignTable, $foreignKey);
	    return $primaryAlias . '.' . $primaryColumn;
	} 
	
	/**
	* Generates a new table alias for the foreignKey table and column passed in.  Note, this does not
	* check to see if the alias it's creating already exists, nor is it able to handle a _tableAliases
	* array that contains gaps.
	*
	* @author Jason Jones <jason at javacrawl.com>
    * @access private
    * @param string $foreignKeyTable Name of foreign table
    * @param string $foreignKeyCol Name of foreign key in foreign table
    * @return string Corresponding table alias
    *
	*/
	function _getNewTableAlias($foreignKeyTable, $foreignKeyCol) {
	    $result = 'table' . (sizeof($this->_tableAliases)+1);	
	    $this->_tableAliases[$foreignKeyTable . '.' . $foreignKeyCol] = $result;
	    return $result;
	}
	
	/**
	* Simple getter method that retrieves the alias for a table/field pair
	*
	* @author Jason Jones <jason at javacrawl.com>
    * @access private
    * @param string $foreignKeyTable Name of table
    * @param string $foreignKeyCol Name of field
    * @return string table alias
	*
	*/
	function _getTableAlias($foreignKeyTable, $foreignKeyCol)
	{
	  $result = false;
	  if (array_key_exists($foreignKeyTable . '.' . $foreignKeyCol, $this->_tableAliases)) {
	      $result = $this->_tableAliases[$foreignKeyTable . '.' . $foreignKeyCol];
	  }
	  return $result;
	}
	
	/**
	* Returns a where clause with the given attributes set equal to the values of object
	*
	* This function can generate raw WHERE clauses or even parameterized for use
	* in a prepare statement
	*
	* @author Jason Jones <jason at javacrawl.com>
    * @access private
    * @param array $attributes Array of field names to use in where clause
    * @param object $dataObject Model holding data to use in where clause
    * @param boolean $parameterized Indicates if we should build standard WHERE or one for DB::prepare()
    * @return string Generated where clause
    *
	*/
    function _generateWhereClause($attributes, $dataObject, $parameterized = TRUE)
    {
        $attribMap = $dataObject->getAttributeColumnMap();
        $whereClause = "";
        foreach($attributes as $attribute) {
            $column = $attribMap[$attribute];
            if ($whereClause != "") {
                $whereClause .= ' AND ';
            }
            $whereClause .= "{$column} = ";
            
            if ($parameterized) {
                $whereClause .= '?';
            } else {
                $methodName = 'get' . ucfirst($attribute);                     
                $result = call_user_func(array(&$dataObject, $methodName));
                if (is_string($result)) {
                    $result = '\'' . $result . '\'';
                }
                $whereClause .= $result;
            }           
        }
        
        return $whereClause;
    
    }
    
    /**
	* Returns a sequential array of the values from $dataObject for $attributes
	*
	* @author Jason Jones <jason at javacrawl.com>
    * @access private
    * @param array $attributes Array of field names to use in where clause
    * @param object $dataObject Model holding data to use in where clause
    * @return array Array ofvalues
    *
	*/
    function _generateValuesArray($attributes, $dataObject) {
        $result = array();
        foreach($attributes as $attribute) {
            $methodName = 'get' . ucfirst($attribute);                     
            $result[] = call_user_func(array(&$dataObject, $methodName));
        } 
        return $result;   
    }
    
    /**
	* Does insert and possibly returns autogenerated ID value
	*
	* @author Jason Jones <jason at javacrawl.com>
    * @access private
    * @param string $table Table to insert into
    * @param array $dataArray Array of values to insert
    * @param boolean $containsUnique Inidicates that table uses an autongenerated ID
    * @return int|null Will return autogenerated ID of table uses one
    *
	*/
    function _performInsert($table, $dataArray, $containsUnique) {
        global $_DB;
        
        $result = $_DB->autoExecute($table, $dataArray, DB_AUTOQUERY_INSERT); 
        if (DB::isError($result)) {
            trigger_error($result->toString(), E_USER_ERROR);
        } else {
	        // this part is not very generic
	        $idResult = NULL;
	        if (!($containsUnique)) {
	            $idResult = $_DB->getOne("SELECT IDENT_CURRENT('{$table}') AS IDENT");
	        }
	        if (DB::isError($idResult)) {
	            trigger_error($idResult->toString(), E_USER_ERROR);
	        } else {
	            return $idResult;
	        }   
	    }
    }
    
    /**
	* Does insert and possibly returns autogenerated ID value
	*
	* @author Jason Jones <jason at javacrawl.com>
    * @access private
    * @param string $table Table to update
    * @param array $columnValueArray Array of key/value pairs
    * @param string $whereClause Any additional where clause settings
    * @param array $whereValues Array of values to use in where clause
    *
	*/
    function _performUpdate($table, $columnValueArray, $whereClause, $whereValues) {
        global $_DB;
        
        $sql = 'UPDATE ' . $table . ' SET ';
        $valuesArray = array();
        foreach($columnValueArray as $column => $value) {
            if (sizeof($valuesArray) > 0) {
                $sql .= ', ';
            }
            $sql .= $column . ' = ?';
            $valuesArray[] = $value;  
        }
        $sql .= ' WHERE ' . $whereClause;
        $valuesArray = array_merge($valuesArray, $whereValues);
        $pStmt = $_DB->prepare($sql); 
        $result = $_DB->execute($pStmt, $valuesArray);
        if (DB::isError($result)) {
            trigger_error($result->toString(), E_USER_ERROR);
            return PEAR::raiseError($result->getMessage());
        }  
    }
    
    /**
	* Calls the setter on $object for $attribute with $value
	*
	* NOTE: assumes all object setters are of the form setSomeattr.  In
	* otherwords, if you have an attribute called fname then the setter
	* must be called setFname()
	*
	* @author Jason Jones <jason at javacrawl.com>
    * @access private
    * @param object $object Instance of object to call setter on
    * @param string $attribute Attribute to set
    * @param string $value Value to set attribute to
    *
	*/
    function _setValueOnObject(&$object, $attribute, $value) {
        $methodName = 'set' . ucfirst($attribute);
        call_user_func(array(&$object, $methodName), $value);   
    }
     
}

?>
Index: README.txt
===================================================================
RCS file: /var/cvs/MVCnPHP/README.txt,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -C2 -d -r1.4 -r1.4.2.1
*** README.txt	14 Jul 2003 17:02:55 -0000	1.4
--- README.txt	14 Dec 2004 20:23:20 -0000	1.4.2.1
***************
*** 16,19 ****
--- 16,22 ----
      INSTALLING THE QUCKFORM EXAMPLE
      INSTALLING FOR GENERAL USE
+ THE PERSISTENCE MANAGER
+     PERSISTENCE MANAGER REQUIREMENTS
+ DOCUMENTATION
  TODO
  KNOWN BUGS
***************
*** 45,49 ****
  you are a Java purist and insist on a 100% Struts compatible version you may
  feel welcome to rework what I have here OR check out the Phrame project at
! http://phrame.itsd.ttu.edu/.  
  
  MVC FEATURES
--- 48,52 ----
  you are a Java purist and insist on a 100% Struts compatible version you may
  feel welcome to rework what I have here OR check out the Phrame project at
! http://phrame.itsd.ttu.edu/ 
  
  MVC FEATURES
***************
*** 133,138 ****
  can be easily extended to use other packages for the creation of views.  Furthermore, 
  MVCnPHP includes QF_View.class.php as part of the base distribution so that you could begin
! using HTML QuickForm right out-of-the-box.  To use the example, edit the index.php file and
! change $mvcBase to point to where you installed MVCnPHP.
  
  INSTALLATION FOR GENERAL USE
--- 136,140 ----
  can be easily extended to use other packages for the creation of views.  Furthermore, 
  MVCnPHP includes QF_View.class.php as part of the base distribution so that you could begin
! using HTML QuickForm right out-of-the-box.  
  
  INSTALLATION FOR GENERAL USE
***************
*** 148,156 ****
     application one for each functional area of your application.  Each 
     controller will require it's own configuration settings.
! 3) If you plan to use MVCnPHP in a number of applications, you should consider adding the
!    folder location to your php.ini's include_path.  The sample applications assume this is the 
!    case but, to get around the fact some of you may not be able to edit php.ini we change the 
!    value of include_path at runtime through code.  If you want to do something similar in your
!    code, feel free to borrow those code snippets.
  
  TODO
--- 150,176 ----
     application one for each functional area of your application.  Each 
     controller will require it's own configuration settings.
! 3) ...coming soon
! 
! THE PERSISTENCE MANAGER
! -----------------------
! 
! Unique to this MVC impelmentation is a set of classes for implementing object-relational
! mappings between your MVCnPHP models and your backend database.  Using the persistence
! manager can reduce or eliminate the amount of database coding youwould normally have to do
! in your models.  Use of the persistence manager is optional however we do encourage you to
! give the persistence manager version of the contact manage a look so that you can see the
! difference for yourself.
! 
! PERSISTENCE MANAGER REQUIREMENTS
! --------------------------------
! 
! To use the Persistence Manager, we require PEAR::DB be installed.  With fairly new versions
! of PHP PEAR::DB is installed by default.
! 
! DOCUMENTATION
! -------------
! 
! The programming documentation for this package can be found at:
! http://project.geeklog.net/~tony/docs/MVCnPHP/
  
  TODO
***************
*** 159,163 ****
  2) Remove dependence on $_SESSION superglobal since not all application may
     use it.
- 3) Branch and port to PHP5
  
  KNOWN BUGS
--- 179,182 ----
***************
*** 170,175 ****
  -------
  
! This package is considered a final release and is supported.  Send any bugs, comments or
! questions to Tony Bibbs, tony at geeklog.net.
  
  CREDITS
--- 189,194 ----
  -------
  
! This package is considered a production quality and is supported. Please send any bugs,
! comments or questions to Tony Bibbs, tony AT geeklog DOT net.
  
  CREDITS
***************
*** 180,185 ****
  project and a special shout-out to Jason Sweat who is a regular contributor to Phrame.
  
! At one point we had considered combining our efforts but their Phrame project is GPL'd which
! doesn't lend itself for use in proprietary PHP systems. MVCnPHP uses the PHP License which gets
! around this.  For those looking for an MVC implementation be willing to consider both and 
! understand the main differences as it will be an important decision.
--- 199,205 ----
  project and a special shout-out to Jason Sweat who is a regular contributor to Phrame.
  
! At the time of this writing no decision on the future of this project and Phrame has been
! decided.  I am in constant communication with the Phrame developers hoping we can combine 
! what I have built here into some of the Phrame principles that were omitted in this package. 
! By doing so I hope to end up with *the* definitive PHP-MVC package and, at that time, we would
! look at submitting this framework to PEAR.

Index: CHANGELOG
===================================================================
RCS file: /var/cvs/MVCnPHP/CHANGELOG,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -C2 -d -r1.3 -r1.3.2.1
*** CHANGELOG	14 Jul 2003 17:03:32 -0000	1.3
--- CHANGELOG	14 Dec 2004 20:23:20 -0000	1.3.2.1
***************
*** 4,7 ****
--- 4,22 ----
  -------------------
  
+ 12/14/2004
+ -----------
+ - Ported over to PHP5
+ - Introduced loose namespaces (PHP5 doesn't support namespaces yet)
+ - Removed sample applications and Quick Form code.
+ - Various bug fixes.
+ 
+ 3/22/2004
+ -----------
+ - Incorporated a number of minor bugs fixes and changes from Lars Heuer (thanks to Lars!)
+ 
+ 
+ Prior to 3/22/2004
+ --------------------
+ 
  - Added QF_View.class.php which adds support for PEAR::HTML_QuickForm.  This class is a unique child of
    the view.  MVCnPHP typically separates validation logic into a command whereas HTML_QuickForm couples
***************
*** 10,13 ****
  - Fixed bug with QuickForm example that was caused because the Controller::ProcessRequest() method expects
    all commands. (02 May 2003)
! - Now assume that MVCnPHP folder is in PHP's include_path. Also changed some terminology in config files 
!   (XML and .php) to avoid confusion (15 June 2003)
--- 25,27 ----
  - Fixed bug with QuickForm example that was caused because the Controller::ProcessRequest() method expects
    all commands. (02 May 2003)
! - Now assume that MVCnPHP folder is in PHP's include_path. Also changed some terminology in config files (XML and .php) to avoid confusion (15 June 2003)




More information about the geeklog-cvs mailing list