All pastes #562873 Raw Edit

Untitled

public text v1 · immutable
·published 2007-06-12 22:56 UTC
rendered paste body
<?php

require_once('XMLReturn.php');
require_once('SOAPReturn.php');
require_once('ireturn.php');

/**
 * @author Josh Team <jteam@creditsolutions.com>
 * @version 1.0
 */

/**
 * A namespace for exceptions thrown in the CRUD
 * @version 1.0
 * @author Josh Team <hteam@creditsolutions.com>
 * @package Exception
 */
class CRUDException extends Exception{}

/**
 * Creation, Read, Update, Delete, FindID, Validate Model Objects
 *
 * The CRUD class is the backbone to all DataStores. DataStores are generated for you
 * based on your database. All of your DataStores extend CRUD which handles the core
 * functionality of each Store. You shall not instantiate the CRUD itself however extend it
 * and then change whatever functionality you need. For instance, the CRUD only supports
 * grabbing one row of a table per ID passed into the read method. If you need to grab other
 * records as per a join, or a subselect you would need to make your own read method in the
 * corresponding DataStore to do so:
 * <code>
 * //will over ride the CURD::read() method
 * class MyDataStore extends CRUD {
 *  public function read($id=0) {
 *   //Anything custom you need
 *  }
 * }
 * </code>
 *
 * All creation and updates are passed through Validation that matches it per Database
 * Meta information.
 *
 * @abstract
 * @package Model
 */
abstract class CRUD {
    
    /**
     * Stores an array of all fields to ignore when doing queries. You can extend
     * per DataStore to add or take away as need, per DataStore:
     * <code>
     *  class MyDataStore extends CRUD {
     *   $this->ignoreFields = array('propCount','anotherNonSelectableField');
     *  }
     * </code>
     *
     * <b>Warning:</b> If you decide to add more fields in your implemintation class
     * YOU MUST ADD propCount or it will start selecing, validating, etc. the propCount
     * which would cause unforseen errors.
     * 
     * @var array a protected default only has propCount, can add to via DataStore.
     */
    protected $ignoreFields = array('propCount');
    
    /**
     * Stores the return type of the read method. If not defined in the controller
     * then it will return php types (Arrays/Strings), otherwise it looks for
     * XML or Soap.
     *
     * @var string The return type you expect. PHP by default (xml/soap)
     */
    public $returnType = 'php';
    
    /**
     * Will return an entire record from the DataStore corresponding DB table, it
     * pulls all values that are stored in the DataStore's props array, except for fields
     * that are stored in the ignoreFields array.
     *
     * <code>
     *  class MyDataStore extends CRUD {
     *    //Will store an array of client with the id of 5 if exist
     *    $client5 = $this->read(5);
     *  }
     * </code>
     *
     * @todo I need to build logic at some point that allows you to ignore items in the DataStore based off a variable.
     *
     * @param mixed $id Can be an array or an ID
     * @return array - Will return an array, or a multi-dimensional array.
     */
    public function read( $id = null ) {
        
        if(is_numeric($id) || $id == null) {
            
            $fields = array_keys($this->props);
            
            if( is_array( $fields ) ) {
                
                foreach($fields as $field) {
                    
                    if(!in_array($field, $this->ignoreFields) && substr($field,0,8) != "link_ID_" ) {
                        
                        $select .= "$field, ";
                        
                    }
                    
                }
                
                if( $id > 0 ) {
                    
                    $whereClause = " WHERE ".$fields[0]." = $id";
                    
                }
                
                $select = substr($select, 0, -2);
                
                $query = "SELECT $select FROM ". substr(get_class( $this ),0,-5) ."$whereClause";
                
                if($id > 0) {
                    
                    try {
                        
                        return $this->dbObj->getRow($query);
                        
                    } catch (Exception $e) {
                        
                        $this->_handleError( $e );
                        
                    }
                    
                } else {
                    
                    try {
                        
                        return $this->returnData($this->dbObj->getAll($query));
                        
                    } catch (Exception $e) {
                        
                        $this->_handleError( $e );
                        
                    }
                    
                }
                
            }
            
        } else if(is_array($id)) {
            
            $this->read($id);
            
        } else {
            
            throw new CRUDException('You must pass in an ID to '.get_class($this).'::read()');
            
        }
        
    }
    
    /**
     * Will return the value of ID in the table mapped by the DataStore where the
     * field  you pass in is equal to the value you also passed in.
     *
     * <code>
     *  class MyDataStore extends CRUD {
     *    //Will store the ID of the record where the field email has 'myemail@something.com'
     *    $ID = $this->findID('email','myemail@something.com');
     *  }
     * </code>
     *
     * @param string $field Field Searching
     * @param string $value Value Searching
     * @return integer
     */
    public function findID( $field, $value ) {
        
        $query = "
            SELECT
                ID
            FROM
                ". substr(get_class( $this ),0,-5) ."
            WHERE
                ". $field ." = '". $value ."'
            LIMIT 1
        ";
        
        try {
            
            return ((int)$this->dbObj->getField( $query ));
            
        } catch (Exception $e) {
            
            $this->_handleError($e);
            
        }
        
    }
    
    /**
     * Takes an array of values and validates the values based on the properties
     * of the DataStore which holds all meta data then calls the protected method
     * save which simply loops through the array and puts the value of the index
     * in the field of the index.
     *
     * <code>
     *  $client = array('first_name'=>'Joe','last_name'=>'Bob');
     *
     *  //Will create a record in the client table, and set fields accordingly
     *  //Assumes that no other undefined fields are required
     *   $c = new ClientStore();
     *   $c->create($client);
     * </code>
     * 
     * @todo Will need to go back and add logic to match the values to the table properties and such.
     *
     * @param array $values
     */
    public function create( $values ) {
        
        try {
            
            $this->_validate( $values, $this->props );
            $this->save('INSERT into',$values);
            
        } catch (Exception $e) {
            
            $this->_handleError($e);
            
        }
        
    }
    
    /**
     * Takes an array of values and validates the values based on the properties
     * of the DataStore which holds all meta data then calls the protected method
     * save which simply loops through the array and puts the value of the index
     * in the field of the index where the ID matches the ID passed in.
     *
     * <code>
     *  class MyDataStore extends CRUD {
     *    //Gets client1
     *    $client1 = $this->read(1);
     *
     *    //Changes first name
     *    $client1['first_name'] = 'Bob';
     *
     *    //Save Changes
     *    $this->update($client1);
     *  }
     * </code>
     * 
     * @todo Will need to go back and add logic to match the values to the table properties and such.
     *
     * @param int $id The ID of the record you want to save
     * @param array $values
     */
    public function update($id, $values) {
        
        try {
            
            $this->_validate( $values, $this->props );
            $this->save('UPDATE',$values);
            
        } catch (Exception $e) {
            
            $this->_handleError($e);
            
        }
        
    }
    
    protected function save($type, $values) {
        
        /**
         * Extract the ID and store it elsewhere so that we can't change the
         * Id of the row that we are changing. I will need to write a method later
         * that allows you to change the ID.
         */
        if(isset($values['ID'])) {
            
            $id = $values['ID'];
            unset($values['ID']);
            
        }
        
        $i = 1;
        
        //Loops through the values and builds out the SQL
        foreach($values as $index=>$value) {
            
            $v .= $index ." = '$value'";
            
            if(count($values) > $i) {
                
                $v .= ", \n";
                
            }
            
            $i++;
        }
        
        //If we are updating, add the where clause
        if($type == 'UPDATE') {
            
            $v .= ' WHERE ID = '. $id ;
            
        }
        
        //Puts the entire query togather.
        $query = "
            $type
               ". substr(get_class( $this ),0,-5) ."
            SET
                ".$v."
        ";
        
        try {
            
            $this->dbObj->query( $query );
            
        } catch (Exception $e) {
            
            $this->_handleError($e);
            
        }
        
    }
    
    /**
     * Removes the entire record from the table mapped by the DataStore
     *
     * For now, it simply deletes the record from the table where the ID is the ID that
     * you pass in.
     *
     * <code>
     *  class MyDataStore extends CRUD {
     *    //Grabs ID of row
     *    $id = $this->findID('email','something@someone.com');
     *
     *    //Removes the record
     *    $this->delete($id);
     *  }
     * </code>
     *
     * @todo I need to go back and write logic in this that allows you to flag rather to delete the record or to mark the record as Active=0. I also need to write some logic that will allow you to store more information when a delete happens and also be able to flag rows as not deletable.
     * @param int $id The ID of the record you want to delete
     */
    public function delete( $id ) {
        
        $query = "
            DELETE FROM
                ". substr(get_class( $this ),0,-5) ."
            WHERE ID = ". $id ."
            LIMIT 1
        ";
        
        try {
            
            $this->dbObj->query( $query );
            
        } catch (Exception $e) {
            
            $this->_handleError( $e );
            
        }
        
    }
    
    private function _validate($values, $properties) {
        
        $v = new Validation();
        
        try {
            
            $v->validate($values, $properties);
            
        } catch (Exception $e) {
            
            throw new CRUDException($e->getMessage());
            
        }
        
    }
    
    private function _handleError(Exception $e) {
        
        $l = new Log();
        $l->saveException( $e );
        throw new CRUDException($e->getMessage());
        
    }
    
    /**
     * Returns the last ID entered
     */
    public function getLastID() {
        return $this->dbObj->getLastID();
    }
    
    /**
     * A factory on what type of data to return
     */
    private function returnData($data) {
        
        switch($this->returnType) {
            
            case "xml":
                $class = 'XMLReturn';
                break;
            
            case "soap":
                $class = 'SOAPReturn';
                break;
            
            default:
                return $data;
                break;
            
            $r = new $class();
            return $r->read($data);
            
        }
        
    }
    
}

?>