[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