Welcome Guest, Not a member yet? Register   Sign In
Auto_Model PHP5
#1

[eluser]wiredesignz[/eluser]
Contributions in this thread are based on AutoModel by Developer13 and modified with permission.

Quote:Code is removed from this post, please look at the updates below
#2

[eluser]wiredesignz[/eluser]
An example table model

Quote:Code is removed from this post, please look at the updates below
#3

[eluser]Developer13[/eluser]
Hey, that looks vaguely familiar... now where have I seen this before...
#4

[eluser]Sam Dark[/eluser]
Another one based on Developer13's AutoModel:
Code:
<?php
/**
* AutoModel PHP5
* @version 0.1
* @author Initial idea and code by Developer13 (http://ellislab.com/forums/member/41286/)
* @author Sam Dark
*/
class AutoModel extends Model {
    public $return_method = 'object';
    
    protected $table = null;
    
    //id is most commonly used for primary key
    protected $primary_key = 'id';
    
    //if array - define alias
    //if no . in name - use current table name
    protected $fields = array();
    
    /**
     * Behaviors could automate your models even more. Currently there is only one supported.
     * TimestampableBehavior. Updates created_on and updated_on in model table with
     * current unix timestamp.
     *
     * Usage:
     * $this->addBehavior(new TimestampableBehavior());
     */
    private $behaviors = array();
    
    /**
     * $joins = array(
     *     'table_name1' => 'table_name1.id = id',
     *  'table_name2' => array('table_name2.id = id', 'left'),
     * )
     *
     * @see $this->db->join(); in Active Record section in user guide for join types
     */
    protected $joins = array();

    function __construct() {
        parent::__construct();
    }
    
    function addBehavior(AutomodelBehavior $behavior){
      $this->behaviors[] = $behavior;
    }
    
    /**
     * If there is no table name add this model table name.
     */
    private function update_fields(){
      foreach ($this->fields as &$field){
        if(!stristr($field, '.')){
          $field = $this->table.'.'.$field;
        }
      }
    }

    /**
     * Get records from model.
     *
     * @param array|string $where
     * @param int|array $limit
     * @return array
     *
     * @see /database/active_record.html
     * You can use methods 3 and 4 from User Guide on $this->db->where().
     *
     * For $limit you can use int to produce LIMIT n
     * or array(limit, offset) to produce LIMIT limit, offset
     */
    function get($where = null, $limit = null, $protect = true) {
        $this->update_fields();
        
        $this->db->select($this->fields);
        
        if (!empty($where)){
            $this->db->where($where, null, $protect);
        }

        $this->perform_join();

        if(is_array($limit)){
          $query = $this->db->get($this->table, $limit[0], $limit[1]);
        }
        else {
          $query = $this->db->get($this->table, $limit);
        }

        if ($this->return_method == 'object') {
            if ($limit == 1) {
                return $query->row();
            }
            else {
                return $query->result();
            }
        }
        elseif ($this->return_method == 'array') {
            if ($limit == 1) {
                return $query->row_array();
            }
            else {
                return $query->result_array();
            }
        }
    }

    /**
     * Saves data to the model.
     *
     * @param array|string $where if specified, update query is generated, else insert query
     * @see also $this->get description
     * @param array $db_array
     * //TODO: save data to joined models?
     * You can specify data to save manually instead of getting it from POST. To do it use
     * second parameter.
     */
    function save($where = null, $data = null) {
        if(empty($data)) $data = $this->db_array();
        $this->db->set($data);
        
        if (!empty($where)) {
            if(!empty($this->behaviors)){
              foreach ($this->behaviors as $behavior){
                $behavior->on_update($this);
              }
            }
            $this->db->where($where);
            $this->db->update($this->table);
        }
        else {
            if(!empty($this->behaviors)){
              foreach ($this->behaviors as $behavior){
                $behavior->on_insert($this);
              }
            }
            $this->db->insert($this->table);
        }
    }

    /**
     * Deletes model record based on condition.
     * //TODO: delete data from joined models?
     *
     * @param array|string $where
     */
    function delete($where) {
        if(!empty($this->behaviors)){
            foreach ($this->behaviors as $behavior){
              $behavior->on_delete($this);
            }
        }
        $this->db->where($where);
        $this->db->delete($this->table);
    }
    
    /**
     * Adds joins to the query based on $this->join.
     */
    private function perform_join() {
        if (!empty($this->joins)) {
            foreach ($this->joins as $table => $condition) {
                if(is_array($condition)){
                  $this->db->join($table, $condition[0], $condition[1]);
                }
                else {
                  $this->db->join($table, $condition);
                }
            }
        }
    }

    /**
     * Fills array for save from POST.
     * Form must have the same names as specified in the model definition.
     *
     * @return array
     */
    private function db_array() {        
        $db_array = array();        
        foreach ($this->fields as $field) {            
            $field = substr($field, strpos($field, '.') + 1);        
            if (isset($_POST[$field])) {
                $db_array[$field] = $this->input->post($field);
            }            
        }
        return ($db_array);
    }
}
#5

[eluser]Sam Dark[/eluser]
Code:
abstract class AutomodelBehavior {
  /**
   * Enter description here...
   *
   * @param AutoModel $model
   */
  function on_insert($model){}
  
  /**
   * Enter description here...
   *
   * @param AutoModel $model
   */
  function on_update($model){}
  
  /**
   * Enter description here...
   *
   * @param AutoModel $model
   */
  function on_delete($model){}
}

/**
* Automatically fills updated_on and created_on with current unix timestamps
* //TODO: timezones support
*/
class TimestampableBehavior extends AutomodelBehavior {
  function on_insert($model){
    $model->db->set($model->table.'.created_on', time());
  }
  
  function on_update($model){
    $model->db->set($model->table.'.updated_on', time());
  }
}
#6

[eluser]Sam Dark[/eluser]
Sample model:
Code:
<?php
class User extends AutoModel {
  function __construct(){
    parent::__construct();
    
    $this->table = 'users';
    $this->fields = array(
      'login',
      'password',
      'email',
      'created_on',
      'updated_on'
    );
    
    $this->addBehavior(new TimestampableBehavior());    
  }
}

I think we need to combine our approaches to get maximum out of this.
#7

[eluser]wiredesignz[/eluser]
Great contribution Sam, let me look at this and post back. Wink

In the meantime take a look at this, I am now using this updated AutoModel class to replace the CI Model entirely.
Code:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
*  AutoModel PHP5
*  Based on AutoModel by Developer13
*  http://ellislab.com/forums/viewthread/88769/
*  
*  Install this file as application/libraries/Model.php
*  
*  @version: 0.7 (c) Wiredesignz 2008-08-22
*/
class Model
{
    protected $table, $joins, $pk, $fields, $order_by;

    protected $resultset;
    
    public function __construct()
    {
        log_message('debug', get_class($this)." Model initialised");
        
        $this->_assign_libraries();
    }

    public function get($pk = NULL)
    {
        /* set fields for select */
        $this->db->select($this->fields[$this->table]);
        
        $this->perform_joins();

        /* set order by */
        if (isset($this->order_by))
        
            $this->db->order_by($this->order_by);        
        
        /* set primary key? */
        if (is_numeric($pk))

            $this->db->where($this->pk, $pk);
        
        /* return the query resource */
        return $this->db->get($this->table);
    }

    public function save($data)
    {            
        $this->prep_dataset($data);
        
        /* valid data and pk type? */
        if (is_numeric($data[$this->pk]))
        {            
            $this->db->where($this->pk, $data[$this->pk]);
            
            /* do update */
            if($this->db->update($this->table, $data))
            
                return $data[$this->pk];
        }
        /* do insert */
        elseif($this->db->insert($this->table, $data))
        
            return $this->db->insert_id();
    }

    public function delete($pk = NULL)
    {
        /* valid pk type? */
        if (is_numeric($pk))
        {
            $this->db->where($this->pk, $pk);
            
            /* do delete */
            return $this->db->delete($this->table);
        }    
    }

    private function perform_joins()
    {
        /* valid joins array? */
        if (is_array($this->joins))
        {
            foreach (array_keys($this->joins) as $key)
            {
                /* build the join keys array */
                $this->db->join($key, $key.'.'.$this->joins[$key]);
                
                /* add the join fields to select */
                $this->db->select($this->fields[$key]);
            }
        }
    }

    private function prep_dataset($data)
    {    
        /* prepare the data */
        foreach ($this->fields[$this->table] as $field)
        {            
            /* match data keys to fields */
            if (isset($data[$field]))
            {
                /* set the fields */
                $this->db->set($field, $data[$field]);    
            }        
        }
    }
    
    public function _assign_libraries()
    {        
        if ($db = controller::instance()->db)    // Modular Extensions PHP5 -  controller::instance()
        {
            (isset($this->db)) OR $this->db = $db;
        }    
    }
}
#8

[eluser]wiredesignz[/eluser]
Example table model
Code:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* Site Model
*
**/
class Site_model extends Model
{
    public function __construct()
    {
        parent::__construct();
        
        $this->table = 'site';
        
        $this->pk = 'site_id';

        $this->joins = array(
            'language' => 'language_id = site.language_id',
            'theme'   => 'theme_id = site.theme_id',        
            );
        
        /* site table fields */
        $this->fields['site'] = array(            
            'site_id',
            'site',
            'title',
            'description',
            'n',
            'enabled',
            'protected',
            'site.theme_id',
            'site.language_id',
            );
            
        /* language table fields */
        $this->fields['language'] = array(                
            'option',
            'language',    
            );
                
            /* theme table fields */
        $this->fields['theme'] = array(
            'source',
            'theme',
            'partial',
            );
            
        $this->order_by = "n";
    }

    public function sites()
    {
        return parent::get()->result();
    }
    
    public function site($site, $pk = NULL)
    {
        (is_numeric($site)) ? $pk = $site : $this->db->where('site.site', $site);
        
        return parent::get($pk)->row();
    }
}
#9

[eluser]Developer13[/eluser]
BATTLE OF THE AUTOMODELS!!!

*insert dramatic music here*
#10

[eluser]Thorpe Obazee[/eluser]
This has been posted a long while ago but I wonder if anyone did continue on building this?




Theme © iAndrew 2016 - Forum software by © MyBB