Author Topic: CBL ActiveRecord  (Read 4607 times)

Girvo

  • Guest
CBL ActiveRecord
« on: January 09, 2008, 10:21:28 pm »
I've created a simple plugin (which was really just a modification of the PDO plugin) that tied the CBL ActiveRecord library into TinyMVC, which I found rather handy ;)

It's nasty though, and I had to edit the index.php file to include the file so that the class definition could be access by the model. Where else could it be placed? It didn't work in the constructor function for the plugin class, as the model couldn't access the class definition. Any ideas? I can release the work once I'm done if you'd like, if anyone would like an ActiveRecord setup.

http://31tools.com/cbl_activerecord/

Thats what I used.

mohrt

  • Administrator
  • Sr. Member
  • *****
  • Posts: 275
    • View Profile
Re: CBL ActiveRecord
« Reply #1 on: January 10, 2008, 02:36:34 am »
Make the class definition a property of the PDO class?

Girvo

  • Guest
Re: CBL ActiveRecord
« Reply #2 on: January 14, 2008, 11:04:07 pm »
I ended up putting the cbl_activerecord stuff in as it's own library, and I've referenced it in a modified PDO database class. Works a treat.

mohrt

  • Administrator
  • Sr. Member
  • *****
  • Posts: 275
    • View Profile
Re: CBL ActiveRecord
« Reply #3 on: January 15, 2008, 08:11:01 am »
Can you post the library/code for others to see?

Girvo

  • Guest
Re: CBL ActiveRecord
« Reply #4 on: January 16, 2008, 07:07:18 pm »
Of course! :)

library.CBL_ActiveRecord.php:
Code: [Select]
<?php

/*
 * 
 * CBL ActiveRecord - an O/R mapping library for PHP5
 * Copyright (C) 2005 Cybozu Labs, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 * 
 * For more information, see:
 *  http://31tools.com/cbl_activerecord/
 */

/**
 *  exception class for CBL_ActiveRecord
 */
class CBL_ActiveRecordException extends Exception
{
    function 
__construct$message$code )
    {
        return 
parent::__construct$message$code );
    }
}

// exception code
define'ar_construct_by_id',           );
define'ar_construct_by_constraints',  );

//if( ! is_numeric( @PDO_FETCH_ASSOC ) )
//{
    
define'PDO_FETCH_ASSOC'PDO::FETCH_ASSOC );
    
define'PDO_PARAM_INT'PDO::PARAM_INT );
    
define'PDO_PARAM_STR'PDO::PARAM_STR );
//}

/**
 *  active record
 *  @author HATA,Shinya
 */
class CBL_ActiveRecord
{
    protected static 
$default_pdo null;

    
/**
     *  set default PDO instnace
     *  @param  object  pdo     PDO instance
     */
    
static function setDefaultPDO$pdo )
    {
        
self::$default_pdo $pdo;
    }

    
/**
     *  get default PDO instance
     *  @return object      PDO instance
     */
    
static function &getDefaultPDO()
    {
        return 
self::$default_pdo;
    }

    protected 
$pdo null;
    protected 
$table null;
    protected 
$row = array();
    protected 
$constraints = array();
    protected 
$children = array();

    
/**
     *  constructor
     *  @param  mixed   param   PDO instance,
     *                          or record id (if integer),
     *                          or constraints (if array) but param['pdo'] is PDO instance
     */
    
function __construct$param null )
    {
        
$this->pdo self::$default_pdo;
        
$class_name strtolowerget_class($this) );
        if( 
$class_name != 'cbl_activerecord' )
        {
            
$this->table $class_name;
        }

        if( ! 
$param ) return;

        if( 
strtolowerget_class$param ) ) == 'pdo' )
        {
            
// parameter is PDO instance
            
$this->pdo $param;
        }
        else if( 
is_numeric$param ) || is_string$param ) )
        {
            
// parameter is numeric, then treat as 'id'
            
if( ! $this->_find$param ) )
            {
                throw new 
CBL_ActiveRecordException(
                    
'Fail to construct by record id.',
                    
ar_construct_by_id );
            }
        }
        else if( 
is_array$param ) )
        {
            
// parameter is array

            
if( @$param['pdo'] &&
                
strtolowerget_class$param['pdo'] ) ) == 'pdo' )
            {
                
$this->pdo $param['pdo'];
                unset( 
$param['pdo'] );
            }

            if( 
count$param ) )
            {
                
$this->constraints $param;
                if( ! 
$this->_find() )
                {
                    throw new 
CBL_ActiveRecordException(
                        
'Fail to construct by constraints.',
                        
ar_construct_by_constraints );
                }
            }
        }
    }

    
/**
     * get PDO instance
     */
    
function getPDO()
    {
        return 
$this->pdo;
    }

    
/**
     *  get property
     *  @param  string  name    property name
     *  @return mixed           property value
     */
    
public function __get$name )
    {
        
assertis_array$this->row ) );
        if( 
array_key_exists$name$this->row ) )
        {
            
// record column value
            
return $this->row[$name];
        }

        
// get child object
        //$id = intval( $this->row['id'] );
        
$id = @$this->row['id']; // modify at 2005/12/14 for string id
        
if( $id )
        {
            
$foreign_key $this->table '_id';

            
assertis_array$this->children ) );
            if( 
array_key_exists$name$this->children ) &&
                
$this->children[$name]->getConstraint$foreign_key ) == $id )
            {
                
// return cashed instance
                
return $this->children[$name];
            }

            
$class_name ucfirst$name );
            if( 
class_exists$class_nameFALSE ) )
            {
                
// create instance
                
$child = new $class_name$this->pdo );
                
$child->setConstraint$foreign_key$id );
                
$this->children[$name] = $child;
                return 
$child;
            }
        }

        return 
null;
    }

    
/**
     *  set property
     *  @param  string  name    property name
     *  @param  mixed   value   property value
     */
    
public function __set$name$value )
    {
        if( ! 
is_array$this->row ) )
        {
            
$this->row = array();
        }
        
$this->row[$name] = $value;
    }

    
/**
     *  set constraints
     *  @param  string  name    column name
     *  @param  mixed   value   column value
     */
    
function setConstraint$name$value )
    {
        
$this->constraints[$name] = $value;
    }

    
/**
     *  get constraints
     *  @param  string  name    column name
     *  @return mixed           column value
     */
    
function getConstraint$name )
    {
        return 
array_key_exists$name$this->constraints) ? $this->constraints[$name] : null;
    }

    
/**
     *  get one record
     *  @param  mixed id            record id
     *  @return CBL_ActiveRecord    this instance, or null if failed
     */
    
function find$id null$params null )
    {
        
$record = clone( $this );
        return 
$record->_find$id$params ) ? $record null;
    }

    
/**
     *  get one record helper
     *  @param  mixed id            record id
     *  @return boolean
     */
    
protected function _find$id null$params null )
    {
        if( 
is_null$params ) )
        {
            
$params = array();
        }

        if( 
$id )
        {
            if( 
is_numeric$id ) && ! isset( $this->has_string_id ) )
            {
                
$id intval$id );
            }

            
$this->constraints['id'] = $id;
        }

        if( @
$params['columns'] )
        {
            
$sql "SELECT {$params['columns']} FROM `{$this->table}`";
        }
        else
        {
            
$sql "SELECT * FROM `{$this->table}`";
        }

        if( 
count$this->constraints ) )
        {
            
$sql .= ' WHERE ' $this->_makeANDConstraints$this->constraints );
            
$binding_params $this->_makeBindingParams$this->constraints );
        }
        
$sql .= ';';

        
$sth $this->pdo->prepare$sql );
        if( ! 
$sth )
        {
            
$err $this->pdo->errorInfo();
            
trigger_error"{$err[2]}:{$sql}"E_USER_ERROR );
        }
        if( ! 
$sth->execute( @$binding_params ) )
        {
            
$err $sth->errorInfo();
            
trigger_error"{$err[2]}:{$sql}"E_USER_ERROR );
        }

        
$row $sth->fetchPDO_FETCH_ASSOC );
        
$sth->closeCursor();
        if( ! 
$row ) return FALSE;

        
$this->row $row;
        return 
TRUE;
    }

    
/**
     *  get record list
     *  @param  array   params  option array
     *                          params['conditions'] : WHERE phrase in SQL
     *                          params['order'] : ORDER phrase in SQL
     *  @return array           array of CBL_ActiveRecord
     */
    
function find_all$params null$join null )
    {
        if (! 
is_array($params)) $params = array();
        if (! 
is_array($join)) $join = array();

        if( @
$params['columns'] )
        {
            
$sql "SELECT {$params['columns']} FROM `{$this->table}`";
        }
        else
        {
            
$sql "SELECT * FROM `{$this->table}`";
        }

        if (
count($join) && @$join['table'] && @$join['lhs'] && @$join['rhs']) {
            
$sql .= " INNER JOIN `{$join['table']}`".
                
" ON `{$this->table}`.{$join['lhs']}=`{$join['table']}`.{$join['rhs']}";
        }

        
$where FALSE;
        if( 
count$this->constraints ) )
        {
            
$sql .= ' WHERE ' $this->_makeANDConstraints$this->constraints );
            
$where TRUE;
        }

        if( @
$params['conditions'] )
        {
            if( 
$where )
            {
                
$sql .= " AND ({$params['conditions']})";
            }
            else
            {
                
$sql .= " WHERE {$params['conditions']}";
                
$where TRUE;
            }
        }

        if( @
$params['order'] )
        {
            
$sql .= " ORDER BY {$params['order']}";
        }

        if( 
array_key_exists'limit'$params ) )
        {
            
$limit intval$params['limit'] );
            if( 
array_key_exists'offset'$params ) )
            {
                
$offset intval$params['offset'] );
                
$sql .= " LIMIT {$limit} OFFSET {$offset}";
            }
            else
            {
                
$sql .= " LIMIT {$limit}";
            }
        }

        
$sql .= ';';
        
$binding_params $this->_makeBindingParams$this->constraints );
        
$sth $this->pdo->prepare$sql );
        if( ! 
$sth )
        {
            
$err $this->pdo->errorInfo();
            
trigger_error"{$err[2]}:{$sql}"E_USER_ERROR );
        }
        if( ! 
$sth->execute$binding_params ) )
        {
            
$err $sth->errorInfo();
            
trigger_error"{$err[2]}:{$sql}"E_USER_ERROR );
        }

        
$row_list $sth->fetchAllPDO_FETCH_ASSOC );
        
$item_list = array();
        foreach( 
$row_list as $row )
        {
            
$item = new $this->table$this->pdo );
            
$item->row $row;
            
$item->constraints $this->constraints;
            if (isset(
$row['id'])) {
                
$item_list[$row['id']] = $item;
            } else {
                
$item_list[] = $item;
            }
        }

        return 
$item_list;
    }

    
/**
     *  insert record to table, or update record data
     */
    
function save()
    {
        if( @
$this->row['id'] )
        {
            
$this->update();
        }
        else
        {
            unset( 
$this->row['id'] );
            
$this->insert();
        }
    }

    
/**
     *  delete record from table
     *  @param  mixed id    record id
     *  @return boolean
     */
    
function delete$id )
    {
        if( 
is_numeric$id ) && ! isset( $this->has_string_id ) )
        {
            
$id intval$id );
        }
        
$this->constraints['id'] = $id;
        
$sql "DELETE FROM `{$this->table}` WHERE " .
            
$this->_makeANDConstraints$this->constraints ) . ';';
        
$binding_params $this->_makeBindingParams$this->constraints );

        
$sth $this->pdo->prepare$sql );
        if( ! 
$sth )
        {
            
$err $this->pdo->errorInfo();
            
trigger_error"{$err[2]}:{$sql}"E_USER_ERROR );
        }
        if( ! 
$sth->execute$binding_params ) )
        {
            
$err $sth->errorInfo();
            
trigger_error"{$err[2]}:{$sql}"E_USER_ERROR );
        }

        
$this->row = array();
        return 
$sth->rowCount() > 0;
    }

    function 
count($params null)
    {
        
$sql "SELECT COUNT(*) FROM `{$this->table}`";
        if (isset(
$params['conditions']) && $params['conditions'] != '')
        {
            
$sql .= " WHERE {$params['conditions']}";
        }
        
$sql .= ';';
        
$sth $this->pdo->query$sql );
        return 
intval$sth->fetchColumn() );
    }
/*
    function _update()
    {
        $values = $this->row;
        unset( $values['id'] );
        if( ! count( $values ) )
        {
            trigger_error( 'No record value.', E_USER_ERROR );
        }
        $sql = "UPDATE `{$this->table}` SET " .
            $this->_makeUPDATEValues( $values ) .
            " WHERE `{$this->table}`.id=:id;";
        $binding_params = $this->_makeBindingParams( $this->row );

        $sth = $this->pdo->prepare( $sql );
        if( ! $sth )
        {
            $err = $this->pdo->errorInfo();
            trigger_error( "{$err[2]}:{$sql}", E_USER_ERROR );
        }
        if( ! $sth->execute( $binding_params ) )
        {
            $err = $sth->errorInfo();
            trigger_error( "{$err[2]}:{$sql}", E_USER_ERROR );
        }

        return $sth->rowCount() > 0;
    }
*/
    
function update$id_list = array() )
    {
        
$values $this->row;
        unset(
$values['id']);
        if (! 
count$values)) {
            
trigger_error'No record value.'E_USER_ERROR );
        }

        
$sql "UPDATE `{$this->table}` SET ".
            
$this->_makeUPDATEValues($values);

        if (isset(
$this->row['id']) && $this->row['id']) {
            
$sql .= " WHERE `{$this->table}`.id=:id;";
        } else if (
count($id_list)) {
            
$sql .= ' WHERE '.$this->_makeIDList($id_list).';';
        } else {
            
trigger_error('ID is not specified.'E_USER_ERROR);
        }
        
$binding_params $this->_makeBindingParams($this->row);

        
$sth $this->pdo->prepare($sql);
        if (! 
$sth) {
            
$err $this->pdo->errorInfo();
            
trigger_error("{$err[2]}:{$sql}"E_USER_ERROR);
        }
        if (! 
$sth->execute($binding_params)) {
            
$err $sth->errorInfo();
            
trigger_error("{$err[2]}:{$sql}"E_USER_ERROR);
        }

        return 
$sth->rowCount();
    }

    function 
insert()
    {
        
$this->row array_merge$this->constraints$this->row );
        
$binding_params $this->_makeBindingParams$this->row );
        
$sql "INSERT INTO `{$this->table}` (" .
            
implode', 'array_keys($this->row) ) . ') VALUES(' .
            
implode', 'array_keys($binding_params) ) . ');';

        
$sth $this->pdo->prepare$sql );
        if( ! 
$sth )
        {
            
$err $this->pdo->errorInfo();
            
trigger_error"{$err[2]}:{$sql}"E_USER_ERROR );
        }
        if( ! 
$sth->execute$binding_params ) )
        {
            
$err $sth->errorInfo();
            
trigger_error"{$err[2]}:{$sql}"E_USER_ERROR );
        }

        if( ! @
$this->row['id'] && ! isset( $this->has_string_id ) )
        {
            
$this->row['id'] = $this->pdo->lastInsertId();
            return 
intval$this->row['id'] );
        }

        return @
$this->row['id'];
    }

    function 
uniqid($len 8$set TRUE)
    {
        if (
$len 8) {
            
trigger_error('ID length is short.'E_USER_ERROR);
        }
        
$sql "SELECT id FROM `{$this->table}` WHERE id=:id;";
        
$sth $this->pdo->prepare($sql);
        do {
            
$id substr(md5(uniqid()), 0$len);
            
$sth->execute(array('id'=>$id));
            
$row $sth->fetch();
            
$sth->closeCursor();
        } while (
$row);
        if (
$set) {
            
$this->id $id;
        }
        return 
$id;
    }

    function 
_makeANDConstraints$array )
    {
        foreach( 
$array as $key=>$value )
        {
            if( 
is_null$value ) )
            {
                
$expressions[] = "`{$this->table}`.{$key} IS NULL";
            }
            else
            {
                
$expressions[] = "`{$this->table}`.{$key}=:{$key}";
            }
        }
        return 
implode' AND '$expressions );
    }

    function 
_makeUPDATEValues$array )
    {
        foreach( 
$array as $key=>$value )
        {
            
$expressions[] ="{$key}=:{$key}";
        }
        return 
implode', '$expressions );
    }

    function 
_makeBindingParams$array )
    {
        
$params = array();
        foreach( 
$array as $key=>$value )
        {
            
$params[":{$key}"] = $value;
        }
        return 
$params;
    }

    function 
_makeIDList$array )
    {
        
$expressions = array();
        foreach (
$array as $id) {
            
$expressions[] = "`{$this->table}`.id=".
                
$this->pdo->quote($id, isset($this->has_string_id) ? PDO_PARAM_INT PDO_PARAM_STR);
        }
        return 
'('.implode(' OR '$expressions).')';
    }
}

class 
CBL_ActiveRoot extends CBL_ActiveRecord
{
    public function 
__get$name )
    {
        
assertis_array$this->children ) );
        if( 
array_key_exists$name$this->children ) )
        {
            return 
$this->children[$name];
        }

        
$class_name ucfirst$name );
        if( 
class_exists$class_nameFALSE ) )
        {
            
// create instance
            
$child = new $class_name$this->pdo );
            
$this->children[$name] = $child;
            return 
$child;
        }

        return 
null;
    }
}
?>


Girvo

  • Guest
Re: CBL ActiveRecord
« Reply #5 on: January 16, 2008, 07:07:39 pm »
db.TMVC_AR.php:
Code: [Select]
<?php
/***
 * Name:       TinyMVC
 * About:      An MVC application framework for PHP
 * Copyright:  (C) 2007, New Digital Group Inc.
 * Author:     Monte Ohrt, monte [at] ohrt [dot] com
 * License:    LGPL, see included license file  
 ***/

// ------------------------------------------------------------------------

/* define SQL actions */
if(!defined('TMVC_SQL_NONE'))
  
define('TMVC_SQL_NONE'0);
if(!
defined('TMVC_SQL_INIT'))
  
define('TMVC_SQL_INIT'1);
if(!
defined('TMVC_SQL_ALL'))
  
define('TMVC_SQL_ALL'2);

/**
 * TMVC_PDO
 * 
 * ActiveRecord using PDO database access
 * compile PHP with --enable-pdo (default with PHP 5.1+)
 *
 * @package TinyMVC
 * @author Josh Girvin
 */

class TMVC_AR
{
 
/**
 * $pdo
 *
 * the PDO object handle
 *
 * @access public
 */
  
var $pdo null;
  
 
/**
 * $result
 *
 * the query result handle
 *
 * @access public
 */
  
var $result null;
  
 
/**
 * $fetch_mode
 *
 * the results fetch mode
 *
 * @access public
 */
  
var $fetch_mode PDO::FETCH_ASSOC;
  
 
/**
 * class constructor
 *
 * @access public
 */
  
function __construct() {

   include(
TMVC_MYAPPDIR 'configs' DS 'database.php');
   if(!
class_exists('PDO'))
     
trigger_error("PHP PDO package is required.",E_USER_ERROR);
     
   if(empty(
$config))
     
trigger_error("database definitions required.",E_USER_ERROR);

    
/* create link */
    
try {    
      
$this->pdo = new PDO(
        
"{$config['type']}:host={$config['host']};dbname={$config['name']}",
        
$config['user'],
        
$config['pass'],
        array(
PDO::ATTR_PERSISTENT => !empty($config['persistent']) ? true false)
        );
        
CBL_ActiveRecord::setDefaultPDO$this->pdo );
    } catch (
PDOException $e) {
        
trigger_error(sprintf("Can't connect to PDO database '{$config['type']}'. Error: %s",$e->getMessage()),E_USER_ERROR);
    }
    
  }

/**
 * query
 *
 * execute a database query
 *
 * @access public
 * @param   array $params an array of query params
 * @param   int $fetch_mode the fetch formatting mode
 */    
  
function query($query,$params=null,$fetch_mode=null)
  {
    return 
$this->_query($query,$params,TMVC_SQL_NONE,$fetch_mode);
  }  

/**
 * query_all
 *
 * execute a database query, return all records
 *
 * @access public
 * @param   array $params an array of query params
 * @param   int $fetch_mode the fetch formatting mode
 */    
  
function query_all($query,$params=null,$fetch_mode=null)
  {
    return 
$this->_query($query,$params,TMVC_SQL_ALL,$fetch_mode);
  }  

/**
 * query_init
 *
 * execute a database query, return one record
 *
 * @access public
 * @param   array $params an array of query params
 * @param   int $fetch_mode the fetch formatting mode
 */    
  
function query_init($query,$params=null,$fetch_mode=null)
  {
    return 
$this->_query($query,$params,TMVC_SQL_INIT,$fetch_mode);
  }  
  
/**
 * _query
 *
 * internal query method
 *
 * @access private
 * @param   string $query the query string
 * @param   array $params an array of query params
 * @param   int $return_type none/all/init
 * @param   int $fetch_mode the fetch formatting mode
 */    
  
function _query($query,$params=null,$return_type TMVC_SQL_NONE,$fetch_mode=null)
  {
  
    
/* if no fetch mode, use default */
    
if(!isset($fetch_mode))
      
$fetch_mode PDO::FETCH_ASSOC;  
  
    
/* prepare the query */
    
$this->result $this->pdo->prepare($query);
    
    
/* execute with params */
    
$this->result->execute($params);  
  
    
/* get result with fetch mode */
    
$this->result->setFetchMode($fetch_mode);  
  
    switch(
$return_type)
    {
      case 
TMVC_SQL_INIT:
        return 
$this->result->fetch();
        break;
      case 
TMVC_SQL_ALL:
        return 
$this->result->fetchAll();
        break;
      case 
TMVC_SQL_NONE:
      default:
        break;
    }  
    
  }

/**
 * next
 *
 * go to next record in result set
 *
 * @access public
 * @param   int $fetch_mode the fetch formatting mode
 */    
  
function next($fetch_mode=null)
  {
    if(isset(
$fetch_mode))
      
$this->result->setFetchMode($fetch_mode);
    return 
$this->result->fetch();
  }

/**
 * last_insert_id
 *
 * get last insert id from previous query
 *
 * @access public
 * @return int $id
 */    
  
function last_insert_id()
  {
    return 
$this->pdo->lastInsertId();
  }

/**
 * num_rows
 *
 * get number of returned rows from previous select
 *
 * @access public
 * @return int $id
 */    
  
function num_rows()
  {
    return 
count($this->result->fetchAll());
  }


 
/**
 * class destructor
 *
 * @access public
 */
  
function __destruct()
  {
    
$this->pdo null;  
  }
  
}

?>



Very simple modification. All you need to do is change the DB plugin to point to db.TMVC_AR.php, and load the library.CBL_ActiveRecord.php library and you're all set. :)