Welcome Guest, Not a member yet? Register   Sign In
ActiveRecord for CodeIgniter: Rails-style model interactions
#91

[eluser]webthink[/eluser]
Ok I've made another alteration to the class.
I wanted the ability to update a number of records without holding them as instances in my model and without knowing their primary keys. In other words do an UPDATE...WHERE... using an arbitrary where clause possibly updating a number of records at the same time.

I think if we were going to make use of all the additional clauses (WHERE, LIKE etc) going forward the architecture should probably change to use something similar to the _compile_select method. But this alteration will work to add custom where clauses to an update statement.

The first thing I did was to add an array to store our where clauses. Currently the where() method is used to build the actual where clause string rather than hold the conditions in a associative array. We need the associative array.

Code:
function ActiveRecord ()
{
    parent::Model();
    
    $this->_class_name = strtolower(get_class($this));
    $this->_table = $this->_class_name . 's';
    $this->_primary_keys = array('id');
    $this->_where_array = array();
//...

Then we need to alter the where method to store the field and value
Code:
function where ($key, $value = null)
{
    $this->_where_array[$key] = $value;
        $this->_add_clause($this->_where, $key, $value, 'AND', 'WHERE');
        
        return $this;
}

This sets us up to change the update method so that it now a)looks for these where clauses and b)accepts an array of values for the update.

Code:
/**
* update
*
* Similar to the save() method, except that it will update the row
* corresponding to the current object.
*
* or will now accept an array of new values and update rows corrosponding preset where conditions
*
* @access    public
* @param   array
* @return    void
*/
function update ($values=array())
{
    $data = new stdclass();
    
    // Cache the list of fields
    if ( $this->_cache_structure ) $this->db->cache_on();
    
    if (count($values) == 0)
    {
        foreach ( $this->db->list_fields($this->_table) as $field )
        {
        if ( !in_array($field,$this->_primary_keys)  &&property;_exists($this,$field) )
        {
                $data->$field = $this->$field;
            }
        }
        $values = get_object_vars($data);
    }
    // Stop caching
    if ( $this->_cache_structure ) $this->db->cache_off();
    
    // Serialize the data
    if ( method_exists($this,'serialize') )
        $this->serialize($data);
        if ( count($this->_where_array) > 0 )
    {
        $where = $this->_where_array;
    }
    else
    {
        foreach( $this->_primary_keys as $key )
        {
            if ( property_exists($this,$key) )
                $where[$key] = $this->$key;
            else
                log_message('error', 'Cannot update ' . $this->_table . ' : $this->' . $key . ' is not set!');            
        }
    }        

    $sql = $this->db->update_string($this->_table, $values, $where);
    if ( !$this->db->query($sql) )
    {
        log_message('error', $this->db->last_query());
    }
    $this->_clean();
}

The only other change to make is that we need to make sure we release the stored where array after each query.
Code:
function _clean ()
{
    $this->_select = array();    // all columns
    $this->_fields = array();    // columns to be returned
    $this->_join = array();
    $this->_where = '';
    $this->_where_array = array();
//...

Now we can update multiple records by making a call like
Code:
$this->user->where('user_type',5)->update(array ('confirmed'=>1) );

But as I stated in the post above I prefer calling it with dynamic methods so I added the ability to call
Code:
$this->user->update_all_by_user_type(5, array ('confirmed'=>1) );

So I added the following
Code:
function __call ($method, $args)
{
    $watch = array(
        'find_by_',
        'find_all_by_',
        'update_all_by_',
//...

And then added the function just below _find_all_by()

Code:
/**
* _update_all_by
*
* Updates all records using fieldname as where clause when called as update_all_by_[fieldname]
*
* @access    private
* @param    string
* @param    array
* @return    array
*/
function _update_all_by ($field, $args)
{
    $field = $this->_table . '.' . $field;
        switch ( $args[0] )
    {
        case IS_NULL:
            $this->where($field . IS_NULL);
            break;
        case NOT_NULL:
            $this->where($field . NOT_NULL);
            break;
        default:
            $this->where($field, $args[0]);
    }
        return $this->update(( isset($args[1]) ) ? $args[1] : null );
}

I hope this helps someone.

Cheers


Messages In This Thread
ActiveRecord for CodeIgniter: Rails-style model interactions - by El Forum - 02-28-2008, 05:22 AM



Theme © iAndrew 2016 - Forum software by © MyBB