CLICK HERE TO BUY IT TODAY! OR GET IT FREE VIA TRIALPAY  

PHP Demo Application - Source Code

/Framework/Model/DataObjects/_Abstract.php

<?php
/**
* Script Contents: Apeel_Framework_Model_DataObjects_Abstract Class
* @package Apeel_Framework_Model_DataObjects
*/

/**
* Core functionality to handle reading and writing data to the database.  

* A "data object" class in the Apeel Framework manipulates data derived from one
* or more database tables. 

* This core abstract class contains all the PDO code for connecting to the 
* database, reading and writing data.  

* Concrete classes derived from this base class contain the specifics of which
* tables/fields to read, what kind of editor should be used with each field 
* (e.g. text box, dropdown, autocomplete etc) and could represent (for example) 
* the data required to populate a data entry form, or a grid, or to populate
* a drop down list, or any other use you can think of.  

* In a typical usage pattern, another abstract class will extend this one and
* fulfill the abstract method getDbConnectionInfo(), which supplies database 
* connection details.  Concrete Data Objects will extend this class.  

* The structure of Data Objects is based on the Template Design Pattern.  
*  
* @package      Apeel_Framework_Model_DataObjects 
* @version      1.1.0
* @author       John W. King (email: contact@apeelframework.net)
* @copyright    City Business Logic Limited 2001-2011
* @license      Dual MIT / GNU Lesser General Public License Version 3
*/
abstract class Apeel_Framework_Model_DataObjects_Abstract {

    
/**
    * Stores PDO Object.  
    * 
    * @var PDO object
    */
    
protected $_pdo;
    
    
    
/**
    * Stores PDO Statement Object.  
    * 
    * @var PDO Statement
    */
    
public $statement;
    
    
    
/**
    * Collection of parameters to be bound to a SQL query.  
    * 
    * @var Apeel_Framework_Model_DataObjects_Parameters_Collections_DataItems
    */
    
protected $_parameters NULL;
    
    
    
/**
    * Generated SQL INSERT clause.  
    * 
    * @var string
    */
    
protected $_insert;
    
    
    
/**
    * Generated SQL UPDATE clause.  
    * 
    * @var string
    */
    
protected $_update;
    
    
    
/**
    * Generated SQL DELETE clause.  
    * 
    * @var string
    */
    
protected $_delete;
    
    
    
/**
    * Generated SQL WHERE clause.  
    * 
    * @var string
    */
    
protected $_where;
    
    
    
/**
    * Generated SQL ORDER BY clause.  
    * 
    * @var string
    */
    
protected $_orderBy;
    
    
    
/**
    * Generated MySQL LIMIT clause.  
    * 
    * @var string
    */
    
protected $_limit;
    
    
    
/**
    * Stores number of matching records, after executing a query with record
    * count requested.  
    * 
    * @var integer
    */
    
protected $_recordCount = -1;

    
    
/**
    * Return a description of the data represented by the concrete Data Object.  
    * 
    * Concrete classes must implement this method which returns a human readable 
    * name that describes the data that the data object represents.  
    * 
    * @return string
    */
    
abstract public function getDataObjectName();
    
    
    
/**
    * Return the name of the main table referenced in the concrete Data Object.  
    * 
    * Concrete classes must implement this method which returns the name of the
    * main table used in this data object, and is used by the INSERT, UPDATE 
    * and methods: generateInsert(), generateUpdate() and generateDelete().  
    * 
    * @return string
    */
    
abstract public function getMainTableName();    
    
    
    
/**
    * Return details of Primary Key for this data object.  
    * 
    * Concrete classes must provide this method which returns the primary key 
    * field(s) that uniquely identify a single data row.  
    * 
    * Single fields are returned as a string, whilst multiple fields are 
    * returned as a simple array in the form array('field1', 'field2', ...)
    * 
    * @return string | array
    */
    
abstract public function getPrimarykey();
    
    
    
/**
    * Return type for supplied field parameter.  
    * 
    * Concrete classes must provide this method that takes field name and 
    * returns a shorthand value representing the PDO parameter type: 
    * (s - String, i - Integer, b - Boolean.  Default is s)
    * If requested field does not exist then it should throw an exception.
    * 
    * @param string
    * @return char (s, i, b or s)
    */
    
abstract public function getFieldDefinition($field);
    
    
    
/**
    * Produce SQL SELECT clause.  
    * 
    * Concrete classes must provide this method which returns the SELECT clause
    * of the SQL Statement that will populate the data object.  
    * 
    * @return string
    */
    
abstract protected function getSelect();
    
    
    
/**
    * Produce SQL FROM clause.  
    * 
    * Concrete classes must provide this method which returns the FROM clause
    * of the SQL Statement that will populate the data object.  
    * 
    * @return string
    */
    
abstract protected function getFrom();    
    
    
    
/**
    * Specify Database Connection Parameters.  
    * 
    * Typically an abstract class will extend this base class and implement the
    * parameters required to connect to the database.  It should take the form:
    * return array(
    *   'dsn' => 'DSN DETAILS GO HERE',
    *   'uid' => 'USER ID GOES HERE',
    *   'pwd' => 'PASSWORD GOES HERE'
    *   );
    * 
    * The actual concrete Data Objects will extend the abstract connection
    * class.  
    * 
    * @return array
    */
    
abstract public function getDbConnectionInfo();
    
    
    
/**
    * Define Data Objects linked in a Many-to-Many relationship.  
    * 
    * This method is used in concrete classes to define connections to other
    * data objects in a many-to-many relationship.  
    * 
    * It should take the following form:
    * return array(array('object' => 'DATAOBJECT', 'pkLink' => 'PRIMARY KEY'));
    * 
    * DATAOBJECT is the name of the connected data object (the "middle" table 
    * in database teminology), and PRIMARY KEY is field in this object that
    * connects to the Primary Key of the Data Object referenced by DATAOBJECT.  
    * 
    * The "middle" table object will link to the far side of the relationship.
    * 
    * If there are no many-to-many links involving this Data Object then
    * simply return false.  
    * 
    * @return array | boolean
    */
    
abstract protected function getMultiLinkedObjects();
    
    
    
/**
    * Data Object Class Constructor.  
    * 
    * Data Object Constructor - Connects to the database and creates a new 
    * empty collection of parameters.  
    * 
    * @return void
    */
    
public function __construct() {
        
$this->connect();
        
$this->_parameters = new Apeel_Framework_Model_DataObjects_Parameters_Collections_DataItems();    
    }
    
    
    
/**
    * Connect to Database.  
    * 
    * Connects to the database if not already connected, using the parameters 
    * supplied by abstract method getDbConnectionInfo().  
    * 
    * Turns error mode on to aid debugging and buffered queries.  Sets 
    * character set to utf8 to avoid potential problems with unicode
    * characters, hence binary objects (e.g. images, files etc) are dealt with
    * on a seperate connection as utf8 corrupts the values held in such fields.
    * 
    * @return void
    */
    
public function connect() {
        if (!isset(
$_pdo)) {
            
$dbInfo $this->getDbConnectionInfo();
            
// Create new PDO instance
            
$this->_pdo = new PDO($dbInfo['dsn'], $dbInfo['uid'], $dbInfo['pwd']);
            
// Set Attributes
            
$this->_pdo->setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION);
            
$this->_pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERYtrue); 
            
// Set characterset to utf8
            
$this->_pdo->exec('SET CHARACTER SET ' APEEL_MYSQL_CHARSET);            
            
        }
    }
    
    
    
/**
    * Apply Filter, Sort and Range criteria.  
    * 
    * Control method that takes collections of filters, sort objects and an 
    * optional range, calling the methods that process each of these in order
    * to retrieve the selected records in the correct order.  
    * 
    * @param boolean $doReset
    * @param Apeel_Framework_Model_DataObjects_Parameters_Collections_Filters $filters
    * @param Apeel_Framework_Model_DataObjects_Parameters_Collections_Sort $sortColumns
    * @param integer $from
    * @param integer $to
    * @return void
    */
    
public function applyComponents(
        
$doReset,
        
Apeel_Framework_Model_DataObjects_Parameters_Collections_Filters &$filters NULL,
        
Apeel_Framework_Model_DataObjects_Parameters_Collections_Sort &$sortColumns NULL,
        
integer $from NULL
        
integer $to NULL
    
) {
        if (
$doReset) {
            
$this->_parameters->clear();
            
$this->_where '';
        }
        
// Process filter items
        
$this->applyFilters($filters);
        
// Process sort columns
        
$this->applySort($sortColumns);
        
// Process range
        
$this->setRange($from$to);       
    }
        
    
    
/**
    * Apply Filter Collection.  
    * 
    * Loops through the filter collection and generates a corresponding SQL 
    * WHERE clause, and builds a collection of PDO bound parameters.  
    * 
    * @param Apeel_Framework_Model_DataObjects_Parameters_Collections_Filters $filters
    * @return void
    */
    
public function applyFilters(Apeel_Framework_Model_DataObjects_Parameters_Collections_Filters $filters NULL) {      

        if (
$filters) {
            foreach(
$filters as $filter) {
                if (
$filter->fieldname == '') {
                    
$filters->add();
                }
            }
         
            foreach(
$filters as $filter) {            
                
// Check for Primary Key special case (which may contain 1 or more fields)
                
if ($filter->fieldname == '[PRIMARYKEY]') {
                    
$primaryKey $this->getPrimarykey();
                    if (
is_array($primaryKey)) {
                        
$primaryKeyValues unserialize($filter->value);
                        foreach (
$primaryKey as $fieldname) {
                            
$filter->fieldname $fieldname;
                            
$filter->value $primaryKeyValues[$fieldname];
                            
$this->applyFilter($filter);
                        }
                    } else {
                        
$filter->fieldname $primaryKey;
                        
$this->applyFilter($filter);
                    }
                } else {
                    
$this->applyFilter($filter);
                }                
            }
            
            
// Generate complete WHERE clause.
            
if ($this->_where) {
                
$this->_where ' WHERE ' $this->_where;
            }            
            
        }
        
    }
    
    
    
/**
    * Process a single Filter item.  
    * 
    * applyFilters() loops through the filter collection and calls this method
    * for each one.  
    * 
    * It adds the filter condition to the WHERE clause and adds the bound 
    * parameter to the collection.  
    * 
    * @param Apeel_Framework_Model_DataObjects_Parameters_Filter $filter
    * @return void
    */
    
protected function applyFilter(Apeel_Framework_Model_DataObjects_Parameters_Filter $filter) {
        
// Add AND/OR as required (the first item in a SQL WHERE clause does not require it)         
        
if ($this->_where != '') {
            if (!
$filter->joinType) {
                
$this->_where .= ' AND ';
            } else {
                
$this->_where '(' $this->_where ')' ' OR ';
            }
        }
        
// Find out if computed
        
if ($filter->computation) {
            
$fieldname $filter->computation;
        } else {
            
$fieldname $filter->fieldname;
        }
        
// Check general type of _operator
        
if (!in_array($filter->_operator, array('IN''NOT-IN'))) {
            
// Add parameter to collection and return fieldname with unique index appended, unless a parameter less matching such as NULL or NOT NULL.  
            
if (($filter->_operator != 'NULL') && ($filter->_operator != 'NOTNULL')) {
                
$parameterName $this->_parameters->addParameter($filter->fieldname$this->getFieldDefinition($filter->fieldname), $filter->value);              
            }
            
// Add this item to SQL WHERE clause using appropriate syntax based on type of _operator.  
            
if (in_array($filter->_operator, array('>''<''=''!=''>=''<='))) {
                
$this->_where .= '(' $fieldname ' ' $filter->_operator ' :' $parameterName ')';
            } elseif (
$filter->_operator == 'BEGINS') {
                
$this->_where .= '(' $fieldname ' LIKE concat(' ' :' $parameterName ',\'%\'))';
            } elseif (
$filter->_operator == 'ENDS') {
                
$this->_where .= '(' $fieldname ' LIKE concat(\'%\',' ' :' $parameterName '))';
            } elseif (
$filter->_operator == 'CONTAINS') {
                
$this->_where .= '(' $fieldname ' LIKE concat(\'%\',' ' :' $parameterName ',\'%\'))';
            } elseif (
$filter->_operator == 'REGEX') {
                
$this->_where .= '(' $fieldname ' REGEXP :' $parameterName ')';
            } elseif (
$filter->_operator == 'SOUNDS-LIKE') {
                
$this->_where .= '(STRCMP(SOUNDEX('$fieldname .'), SOUNDEX(:' $parameterName ')) = 0)';
            } elseif (
$filter->_operator == 'NOT-SOUNDS-LIKE') {
                
$this->_where .= '(STRCMP(SOUNDEX('$fieldname .'), SOUNDEX(:' $parameterName ')) != 0)';
            } elseif (
$filter->_operator == 'NULL') {
                
$this->_where .= '('$fieldname .' IS NULL )';
            } elseif (
$filter->_operator == 'NOTNULL') {
                
$this->_where .= '('$fieldname .' IS NOT NULL )';
            }
        } else {
            
// IN / NOT-IN clauses require the comma seperated values to be added as individual parameters.  
            
$inList '';
            if (
$filter->value) {
                
// Explode comma-seperated list into an array
                
$values explode(',' $filter->value);
                if (
$values) {
                    foreach (
$values as $value) {
                        
// Add a parameter to the collection for each element in array.  
                        
$parameterName $this->_parameters->addParameter($filter->fieldname$this->getFieldDefinition($filter->fieldname), $value);
                        
// Add a comma to the list unless it is the first parameter
                        
if ($inList != '') {
                            
$inList .= ', ';
                        }
                        
// Add parameter to the list
                        
$inList .= ':' $parameterName;
                    }
                }
            }
            if (
$inList != '') {
                
// If one or more values are present then check the type of the requested _operator
                
if ($filter->_operator == 'IN') {
                    
$_operator ' IN ';
                } else {
                    
$_operator ' NOT IN ';
                }
                
// Add this condition to the SQL WHERE clause.  
                
$this->_where .= '(' $fieldname $_operator '(' $inList '))';
            }
        }        
    }

    
    
/**
    * Apply Sort Collection.  
    * 
    * Loops through Sort item collection and generates a matching SQL ORDER BY 
    * clause.  
    * 
    * @param Apeel_Framework_Model_DataObjects_Parameters_Collections_Sort $sortColumns
    * @return void
    */
    
public function applySort(Apeel_Framework_Model_DataObjects_Parameters_Collections_Sort $sortColumns NULL) {
        
// Clear SQL ORDER BY clause.  
        
$this->_orderBy '';
        
// Loop through filter collection to build SQL ORDER BY clause
        
if ($sortColumns) {
            foreach(
$sortColumns as $sortColumn) {
                
// No comma required before first item.  
                
if ($this->_orderBy != '') {
                    
$this->_orderBy .= ', ';
                }
                
// Add sort column to SQL ORDER BY clause.
                
$this->_orderBy .= '`' $sortColumn->fieldname '` ' $sortColumn->_direction;
            }
            
// Generate complete ORDER BY clause.  
            
$this->_orderBy ' ORDER BY ' $this->_orderBy;
        }
    }
    
    
    
/**
    * Create a MySQL LIMIT statement to restrict the number of records 
    * returned by the recordset (for example a single page of data for a grid).  
    * 
    * @param integer $from
    * @param integer $to
    * @return void
    */
    
public function setRange($from NULL$to NULL) {
        
$this->_limit '';
        if (
is_integer($from)) {
            
$this->_limit ' LIMIT ' $from;
            if (
is_integer($to)) {
                
$this->_limit .= ', ' $to;
            }
        }
    }
       
    
    
/**
    * Return internal SQL WHERE clause.  
    * 
    * @return string
    */
    
public function getWhere() {
        return 
$this->_where;
    }
    
    
    
/**
    * Return internal SQL ORDER BY clause.  
    * 
    * @return string
    */
    
public function getOrderBy() {
        return 
$this->_orderBy;
    }
    
    
    
/**
    * Return internal MySQL LIMIT clause.  
    * 
    * @return string
    */
    
public function getLimit() {
        return 
$this->_limit;
    }
    
    
    
/**
    * Generate SQL SELECT statement from component parts.  
    * 
    * Can be overridden if you prefer to write your SQL Statements in a 
    * single line for example 
    * 
    * @return string 
    */
    
public function getSql() {
        return  
$this->getSelect() . $this->getFrom() . $this->getWhere() . $this->getOrderBy() . $this->getLimit();
    }

    
    
/**
    * Generate SQL Statement for record count.  
    * 
    * Similar to getSql() but replaces the SELECT part with a COUNT(*) which is
    * used to ascertain the number of matching records - for example to 
    * calculate the total number of pages in a paged data grid.  
    * 
    * @return string 
    */
    
protected function getRecordCountSql() {
        return 
'SELECT COUNT(*) AS recordCount ' $this->getFrom() . $this->getWhere();
    }       
        
    
    
/**
    * Prepare the current SQL Select query.  
    * 
    * @return void
    */
    
protected function prepareSelectQuery() {
        
$this->statement $this->_pdo->prepare($this->getSql());
    }
    
    
    
/**
    * Binds parameter collection to prepared statement and executes it.    
    * 
    * @return void
    */
    
public function queryExecute() {
        if (
$this->_parameters) {
            
// Bind any parameters/values to the PDO Statement object
            
foreach($this->_parameters as $parameter) {
                
$this->statement->bindParam(':' $parameter->parameterName$parameter->value$parameter->_parameterType);
            }
        }
        
// Execute Query
        
$this->rebind();
    }
    
    
    
/**
    * Execute or re-execute prepared query with updated parameter values.
    * 
    * If APEEL_LOG_SQL is set then the query is logged to the PHP error log.  
    * 
    * @return void 
    */
    
public function rebind() {
        
// Execute Prepared Query
        
if (APEEL_LOG_SQL) {
            
$this->logQuery();
        }
        
$this->statement->execute();        
    }
    
    
    
/**
    * Log current SQL Statement to Error Log.  
    * 
    * Extracts current SQL statement and replaces parameters with actual bound
    * values, and writes entire statement to the PHP error log.  
    * 
    * To be clear, it logs them even if there is no error - however you would
    * typically turn on the APEEL_LOG_SQL flag when trying to get to the bottom
    * of a speed issue for example.  
    * 
    * For clarity, you may prefer to modify this method to write to a custom
    * log file.  
    * 
    * @return void 
    */
    
public function logQuery() { 
        
        
// Get SQL from PDO statement.  
        
$query $this->statement->queryString;
        
        
// Get Parameter Values
        
$params = array();        
        if (
$this->_parameters) {
            foreach(
$this->_parameters as $parameter) {
                
$params[$parameter->parameterName] = $parameter->value;
            }
        }        
        
        
$keys = array(); 
     
        
# build a regular expression for each parameter 
        
if ($params) {
            foreach (
$params as $key => $value) {
                if (
strlen($value) > 30) {
                    
$value 'LONG TEXT...';
                }
                
$params[$key] = "'" $value "'"
                if (
is_string($key)) { 
                    
$keys[] = '/:'.$key.'/'
                } else { 
                    
$keys[] = '/[?]/'
                } 
            }
        }
     
        
// Perform a regular expression to replace parameters with their values.
        
$query preg_replace($keys$params$query1); 
        
        
Error_log('EXECUTED QUERY: ' $query);
        
    }

    
    
/**
    * Store Record Count in $_recordCount.  
    * 
    * Perform a SELECT COUNT(*) Query for current filters to find out how many
    * records match, and store in $_recordCount.  
    * 
    * @return void
    */
    
public function setRecordCount() {
        
$this->statement $this->_pdo->prepare($this->getRecordCountSql());
        
$this->queryExecute();
        
$data $this->statement->fetch(PDO::FETCH_ASSOC);
        unset(
$this->statement);
        return 
$this->_recordCount $data['recordCount'];
    }
    
    
    
/**
    * Get ID of last inserted record (or NULL if none).  
    * 
    * @return integer
    */
    
public function getLastInsertId() {
        return 
$this->_pdo->lastInsertId(); 
    }   
    
    
    
/**
    * Return Recordset Collection.  
    * 
    * Prepares, Binds and Executes the current SQL Query and returns a 
    * recordset collection of matching records.  
    * 
    * @param mixed $getCount
    * @return Apeel_Framework_Model_DataObjects_Structures_Recordset
    */
    
public function getRecordset($getCount true) {
        if (
$getCount) {
            
$this->setRecordCount();
        } else {
            
$this->_recordCount = -1;
        }
        
$this->prepareSelectQuery();
        
$this->queryExecute();
        return new 
Apeel_Framework_Model_DataObjects_Structures_Recordset($this$this->_recordCount);
    }
    

    
/**
    * Returns internal record count value
    * 
    * @return integer
    */
    
public function getRecordCount(){
        return 
$this->_recordCount;
    }
    
    
    
/**
    * Get Primary Key Value(s) for selected data record.  
    * 
    * Takes an array representing a record, and looks up the field(s) that 
    * represent the primary key of the main table in this object.  
    * 
    * If the Primary Key is comprised of a single field, then a single value
    * from that field is returned.  
    * 
    * If multiple fields make up the Primary Key then each one is retrieved 
    * and serialized into a single string.  
    * 
    * @param array $record
    * @return string
    */
    
public function getPrimaryKeyValue($record) {
        
        
$primaryKey $this->getPrimarykey();
        
        if (
is_array($primaryKey)) {
            
$values = array();
            foreach (
$primaryKey as $fieldname) {
                
$values[$fieldname] = $record[$fieldname];
            }
            
$value htmlentities(serialize($values));
            unset(
$values);
        } else {
            
$value = (string)$record[$primaryKey];
        }
        
        return 
$value;
        
    }
    
  
    
/**
    * Retrieves a single record.  
    * 
    * Use when a query can only ever return a single record (e.g. when 
    * filtering a single table by its Identity value).  
    * 
    * @return mixed
    */
    
public function getRecord() {
        
$this->prepareSelectQuery();
        
$this->queryExecute();
        return 
$this->statement->fetch(PDO::FETCH_ASSOC);
    }
    
    
    
/**
    * Retrieves data formatted as HTML Select list options.  
    * 
    * Value represented by $selected will be highlighted in list if matched.   
    * 
    * @param mixed $selected
    * @param Apeel_Framework_Model_DataObjects_Parameters_Collections_Filters $filters
    * @param mixed $includeCommaSeperatedList
    * @return string
    */
    
public function getDataInDropdownFormat(
        
$selected
        
Apeel_Framework_Model_DataObjects_Parameters_Collections_Filters $filters NULL
        
$includeCommaSeperatedList false
    
) {     
        
$this->applyFilters($filters);        
        
$recordset $this->getRecordset();
        
$options '';
        if (
$includeCommaSeperatedList) {
            
$list '';
        }     

        if (
$recordset) {
            foreach(
$recordset as $record) {
                
                
$options .= '<option value="' $record['id'] . '"';
                if (
$record['id'] == $selected) {
                    
$options .= ' selected="selected"';
                }
                
$options .= '>' $record['desc'] . '</option>';
                if (
$includeCommaSeperatedList) {
                    if (
$list != '') {
                        
$list .= ',';
                    }
                    
$list .= $record['id'];
                }
            }
        }

        if (
$includeCommaSeperatedList) {
            return array(
'options' => $options'list' => $list);
        } else {
            return 
$options;    
        }
    }       
    
    
    
/**
    * Return matching data in JSON format.  
    * 
    * Used to populate Data Grid with data in JSON format.  
    * 
    * @param Apeel_Framework_Model_DataObjects_Parameters_Collections_Filters $filters
    * @return string
    */
    
public function getDataInJsonFormat(Apeel_Framework_Model_DataObjects_Parameters_Collections_Filters &$filters NULL) {
        
$this->applyFilters($filters);
        
$columns $this->getGridColumns();
        
$gridData NULL;
        
$recordset $this->getRecordset(false);

        if (
$recordset) {
            foreach(
$recordset as $record) {
                
                if (
$columns) {
                    foreach (
$columns as $column => $definition) {                
                        
$row[$definition['alias']] = htmlentities($record[$column]);
                    }
                }
                
                
$gridData[] = $row;             
            }
        }

        if (
$gridData) {
            
$json json_encode($gridData);
        } else {
            
$json '[{}]';
        }
        
        
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT" ); 
        
header("Last-Modified: " gmdate"D, d M Y H:i:s" ) . "GMT" ); 
        
header("Cache-Control: no-cache, must-revalidate" ); 
        
header("Pragma: no-cache" );
        
header("Content-type: text/x-json; charset=" APEEL_PAGE_CHARSET);
        
        return 
$json;
        
    }    
        
    
    
/**
    * Read/Write BLOB values
    * 
    * BLOB (Binary Large Object) fields become corrupted is using utf8 
    * character set, and they are often quite large so may be returned
    * by the database when not even required.  
    * 
    * For these reasons, a seperate connection is used to retrieve/write
    * BLOB fields seperately from other fields.  
    * 
    * The fieldname of the field being read/written is typically stored
    * in a varchar field so that the type of file can be identified from
    * it's file extension. 
    * 
    * This method connects to the database, generates/executes the 
    * appropriate SQL and (if mode == 'read') returns the BLOB
    * 
    * @param string $mode - 'read' or 'write'
    * @param string $dbField
    * @param string | array $primaryKeyValue
    * @param string $filename
    * @param string $filenameField
    * @param string $filenameValue
    * @return mixed
    */
    
public function manageBlob($mode$dbField$primaryKeyValue$filename ''$filenameField ''$filenameValue '') {
        
        
// Get Connection
        
$dbConnectionInfo $this->getDbConnectionInfo();
        
$pdo = new PDO($dbConnectionInfo['dsn'], $dbConnectionInfo['uid'], $dbConnectionInfo['pwd']);

        
// Set Attributes
        
$pdo->setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION);
        
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERYtrue); 
        
        
// Get Primary Key WHERE SQL
        
$where '';
        
$params = array();
        
        
$primaryKey $this->getPrimarykey();
        if (
is_array($primaryKey)) {
            
$primaryKeyValues unserialize($primaryKeyValue);
            foreach (
$primaryKey as $fieldname) {
                if (
$where != '') {
                    
$where .= ' AND ';
                }
                
$where .= $fieldname ' = :' $filenameField;
                
$params[$fieldname] = $primaryKeyValues[$fieldname];
            }
        } else {
            
$where $primaryKey ' = :' str_replace('.''_'$primaryKey);
            
$params[$primaryKey] = $primaryKeyValue;
        }
        
        
// Generate SQL
        
if ($mode == 'write') {
            
// Write file to database
            
$sql 'UPDATE `' $this->getMainTableName() . '` SET ' $dbField ' = :content';
            if (
$filenameField != '') {
                
$sql .= ', ' $filenameField ' = :filenameField';
            }
            
$sql .= ' WHERE ' $where;
        } else {
            
// Retrieve file from database
            
$sql 'SELECT `' $dbField '` FROM `' $this->getMainTableName() . '` WHERE ' $where;
        }
        
$statement $pdo->prepare($sql);
        
        if (
$params) {
            foreach(
$params as $index => $value) {
                
$definition $this->getFieldDefinition($index);
                
$index str_replace('.''_',$index);
                
$paramType Apeel_Framework_Model_Libraries_Data::getPdoParameterType($definition['type']); 
                
$statement->bindParam(':' $index$value$paramType);
            }
        }
        
        if (
$mode == 'write') {
            
$fp fopen($filename'r');  
            
$content fread($fpfilesize($filename));
            
$statement->bindParam(':content'$contentPDO::PARAM_LOB);
            if (
$filenameField) {
                
$statement->bindParam(':filenameField'$filenameValuePDO::PARAM_LOB);
            }
            
$statement->execute();
        } else {
            
$statement->execute();
            
$data $statement->fetch(PDO::FETCH_ASSOC);
            return 
$data[$dbField];
        }
        
        unset(
$statement);
        
    }    
           
        
    
/**
    * Generate and execute a SQL INSERT statement.  
    * 
    * Accepts an array of fieldname and values, used to generate and execute a
    * SQL INSERT statement.  
    * 
    * Supplied $values should be in name->value array, which will generate: 
    * INSERT INTO table_name (field1, field2, ...) VALUES (:param1, :param2, ...)
    * 
    * @param array $values (format: fieldname => value)
    * @return void
    */
    
public function generateInsert($values NULL) {
        
// Reset variables
        
$this->_insert '';
        
$fieldList '';
        
$valueList '';
        if (
$values) {            
            foreach(
$values as $fieldname => $value) {
                
// Add PDO Parameter definition to collection
                
$parameterName $this->_parameters->addParameter($fieldname$this->getFieldDefinition($fieldname), $value);
                if (
$fieldList != '') {
                    
// Add comma if this isn't the first field in the list.  
                    
$fieldList .= ', ';
                    
$valueList .= ', ';
                }
                
// Add field / parameter to the relevant parts of the SQL Statement
                
$fieldList .= $fieldname;
                
$valueList .= ':' $parameterName;
            }
            
// Finally, construct the INSERT statement from component parts.  
            
$this->_insert ' INSERT INTO ' $this->getMainTableName() . ' (' $fieldList ') VALUES (' $valueList ')';            
        }
    }
   
    
    
/**
    * Prepare current SQL INSERT statement.  
    * 
    * If Insert statement is empty an exception will be thrown.    
    * 
    * @return void
    */
    
public function prepareInsert() {
        if (
$this->_insert) {
            
$this->statement $this->_pdo->prepare($this->_insert);
        } else {
            throw new 
Exception('Unable to prepare empty INSERT statement');
        }
    }    
    
    
    
/**
    * Generate and execute a SQL UPDATE statement.  
    * 
    * Accepts an array of fieldname and values, and a collection of filters to 
    * generate and execute a SQL UPDATE statement.  
    * 
    * Supplied $values should be in name->value array, which will generate: 
    * UPDATE table_name SET field1 = :param1, field2 = :param2 ... WHERE field0 = :param0 AND ...
    * 
    * @param array $values (format: fieldname => value)
    * @param Apeel_Framework_Model_DataObjects_Parameters_Collections_Filters $filters - filter to decide record(s) to be updated
    * 
    * @return void
    */
    
public function generateUpdate($values NULLApeel_Framework_Model_DataObjects_Parameters_Collections_Filters $filters NULL) {
        
// Clear statement
        
$this->_update '';
        
// Only generate statement if there are values AND filters for security.  
        
if (($values) && ($filters)) {
            foreach(
$values as $fieldname => $value) {
                
// Add PDO Parameter definition to collection
                
$parameterName $this->_parameters->addParameter($fieldname$this->getFieldDefinition($fieldname), $value);
                
// Add comma if this isn't the first field in the list.  
                
if ($this->_update != '') {
                    
$this->_update .= ', ';
                }
                
// Add field / parameter to the SQL Statement
                
$this->_update .= $fieldname ' = :' $parameterName;
            }
            
// Construct main part of SQL statement without filters ...
            
$this->_update ' UPDATE ' $this->getMainTableName() . ' SET ' $this->_update;
            
// ... Add filters to SQL Statement
            
$this->applyFilters($filters);
            
$this->_update .= $this->_where;            
        }
    }
    
    
    
/**
    * Prepare current SQL UPDATE statement.  
    * 
    * If Update statement is empty an exception will be thrown.    
    * 
    * @return void
    */
    
public function prepareUpdate() {
        if (
$this->_update) {
            
$this->statement $this->_pdo->prepare($this->_update);
        } else {
            throw new 
Exception('Unable to prepare empty UPDATE statement');
        }
    }
    
    
    
/**
    * Generate SQL DELETE statememt.  
    * 
    * Uses filer collection to generate WHERE clause, in format: 
    * DELETE FROM table_name WHERE field1 = :param1 AND ...
    * 
    * @param Apeel_Framework_Model_DataObjects_Parameters_Collections_Filters $filters - filter to decide record(s) to be deleted
    * @return void
    */
    
public function generateDelete(Apeel_Framework_Model_DataObjects_Parameters_Collections_Filters $filters NULL) {
        
$this->_delete '';
        if (
$filters) {
            
$this->applyFilters($filters);
            
$this->_delete 'DELETE FROM ' $this->getMainTableName() . ' ' $this->_where;    
        }
    }         
    
    
    
/**
    * Prepare current SQL DELETE statement.  
    * 
    * If Delete statement is empty an exception will be thrown.    
    * 
    * @return void
    */
    
public function prepareDelete() {
        if (
$this->_delete) {
            
$this->statement $this->_pdo->prepare($this->_delete);    
        } else {
            throw new 
Exception('Unable to prepare empty DELETE statement');
        }
    }
    
    
    
/**
    * Update parameter in collection
    * 
    * Allows existing bound parameters for a query to be updated so that the 
    * prepared query can be rebound with the new parameter values without 
    * re-preparing the query.  
    * 
    * @param string $parameterName
    * @param mixed $value
    * @return void
    */
    
public function updateParameter($parameterName$value) {            
        
$this->_parameters->updateParameter($parameterName$value);
    } 
}

?>

PHP Demo Source Code Index