'date_orig','format'=>TRUE); protected $_updated_column = array('column'=>'date_last','format'=>TRUE); // Our filters used to display values in a friendly format protected $_display_filters = array(); // Our attributes used in forms. protected $_form = array(); // Our attribute blobs that should be compressed protected $_compress_column = array(); // Our attributes that should be converted to NULL when empty protected $_nullifempty = array(); // Our attribute values that need to be stored as serialized protected $_serialize_column = array(); // If we need to load any sub items on loading this model protected $_sub_items = array(); protected $_sub_items_load = array(); protected $_sub_items_sorted = FALSE; // Whether to show a SystemMessage when a record is saved. protected $_save_message = FALSE; /** * Auto process some data as it comes from the database * @see parent::__get() */ public function __get($column) { if (array_key_exists($column,$this->_table_columns)) { // If the column is a blob, we'll decode it automatically if ( $this->_table_columns[$column]['data_type'] == 'blob' AND in_array($column,$this->_compress_column) AND ! is_null($this->_object[$column]) AND ! isset($this->_changed[$column]) AND (! isset($this->_table_columns[$column]['auto_convert']) OR ! $this->_table_columns[$column]['auto_convert']) ) { // In case our blob hasnt been saved as one. try { $this->_object[$column] = $this->_blob($this->_object[$column]); } catch(Exception $e) { HTTP_Exception::factory(501,Kohana_Exception::text($e)); } $this->_table_columns[$column]['auto_convert'] = TRUE; } // If the column is a serialized object, we'll unserialize it. if ( in_array($column,$this->_serialize_column) AND is_string($this->_object[$column]) AND ! is_null($this->_object[$column]) AND ! isset($this->_changed[$column]) AND (! isset($this->_table_columns[$column]['unserialized']) OR ! $this->_table_columns[$column]['unserialized']) ) { // In case our object hasnt been saved as serialized. try { $this->_object[$column] = unserialize($this->_object[$column]); } catch(Exception $e) { HTTP_Exception::factory(501,Kohana_Exception::text($e)); } $this->_table_columns[$column]['unserialized'] = TRUE; } } return parent::__get($column); } /** * Retrieve and Store DB BLOB data in compressed format. */ private function _blob($data,$set=FALSE) { try { return $set ? gzcompress($this->_serialize($data,$set)) : $this->_serialize(gzuncompress($data)); // Maybe the data isnt compressed? } catch (Exception $e) { return $this->_serialize($data,$set); } } /** * Format fields for display purposes * * @param string column name * @return mixed */ private function _format() { foreach ($this->_display_filters as $column => $formats) $this->_object_formated[$column] = $this->run_filter($column,$this->__get($column),array($column=>$formats)); $this->_formated = TRUE; } /** * Intercept our object load, so that we can load our subitems */ protected function _load_values(array $values) { parent::_load_values($values); $sort = FALSE; if ($this->_loaded AND $this->_sub_items_load AND count($this->_sub_items_load) == 1) foreach ($this->_sub_items_load as $item => $sort) $this->_sub_items = $this->$item->find_all()->as_array(); if ($sort) { Sort::MAsort($this->_sub_items,$sort); $this->_sub_items_sorted = TRUE; } return $this; } /** * If a column is marked to be nullified if it is empty, this is where it is done. */ private function _nullifempty(array $array) { foreach ($array as $k=>$v) { if (is_array($v)) { if (is_null($x=$this->_nullifempty($v))) unset($array[$k]); else $array[$k] = $x; } elseif (! $v AND $v !== 0 AND $v !== '0') unset($array[$k]); } return count($array) ? $array : NULL; } /** * Try and (un)serialize our data, and if it fails, just return it. */ private function _serialize($data,$set=FALSE) { try { return $set ? serialize($data) : unserialize($data); // Maybe the data serialized? } catch (Exception $e) { return $data; } } /** * Overrides Kohana cache so that it can be globally disabled. */ public function cached($lifetime=NULL) { return $this->_db->caching($this->_table_name) ? parent::cached($lifetime) : $this; } public function clear() { $this->_formated = FALSE; $this->_object_formated = array(); return parent::clear(); } /** * Return a formated columns, as per the model definition */ public function display($column) { // Trigger a load of the record. $value = $this->__get($column); // If some of our fields need to be formated for display purposes. if (! $this->_formated AND $this->_display_filters) $this->_format(); if (isset($this->_object_formated[$column])) return $this->_object_formated[$column]; else return is_array($value) ? join(', ',$value) : $value; } public function display_filters(array $filters) { $this->_display_filters = Arr::merge($this->_display_filters,$filters); } public function dump() { $result = array(); $result['this'] = $this->object(); if (isset($this->_sub_items)) foreach ($this->_sub_items as $o) $result['sub'][] = $o->dump(); return $result; } /** * This function is our AJAX helper, used by module list_autocomplete() */ public function list_autocomplete($term,$index,$value,array $label,array $limit=array(),array $options=NULL) { $result = array(); $query = empty($options['object']) ? $this : $options['object']; foreach ($limit as $w) { list($k,$s,$v) = $w; $query->and_where($k,$s,$v); } $c = 0; foreach ((empty($options['object']) ? $query->find_all() : $query->execute()) as $o) { // If we got here via a DB query, we need to reload our ORM object from the result. if (! is_object($o)) { if (empty($options['key'])) throw new Kohana_Exception('Missing key for non object'); $o = $this->clear()->where($options['key'],'=',$o[$options['key']])->find(); } switch ($index) { case 'url': if (empty($options['urlprefix'])) throw new Kohana_Exception('Missing URL Prefix'); $v = $options['urlprefix'].$o->resolve($value); break; default: $v = $o->resolve($value); } $k = ''; foreach ($label as $k => $details) foreach ($details as $lvalue) $k = preg_replace('/%s/',$o->resolve($lvalue),$k,1); $result[$c++] = array( 'value'=>$v, 'label'=>$k, ); } return $result; } /** * Return an array of data that can be used in a SELECT statement. * The ID and VALUE is defined in the model for the select. */ public function list_select($blank=FALSE,$object=NULL) { $result = array(); if (is_null($object)) $object = $this->find_all(); if ($blank) $result[NULL] = ''; if ($this->_form AND array_intersect(array('id','value'),$this->_form)) foreach ($object as $o) $result[$o->{$this->_form['id']}] = $o->resolve($this->_form['value']); return $result; } /** * This function is used so that methods can be called via variables */ public function resolve($key) { eval("\$x = \$this->$key;"); return $x; } public function save(Validation $validation=NULL) { // Find any fields that have changed, and process them. if ($this->_changed) foreach ($this->_changed as $c) { // Any fields that are blobs, and encode them. if (! is_null($this->_object[$c]) AND $this->_table_columns[$c]['data_type'] == 'blob' AND in_array($c,$this->_compress_column)) { $this->_object[$c] = $this->_blob($this->_object[$c],TRUE); // We need to reset our auto_convert flag if (isset($this->_table_columns[$c]['auto_convert'])) $this->_table_columns[$c]['auto_convert'] = FALSE; // Any fields that should be seriailzed, we'll do that. } elseif (is_array($this->_object[$c]) AND in_array($c,$this->_serialize_column)) { $this->_object[$c] = serialize($this->_object[$c]); } // Test if the value has still changed if ($this->_original_values AND $this->_object[$c] == $this->_original_values[$c]) unset($this->_changed[$c]); } parent::save(); if ($this->saved() AND $this->_save_message AND (PHP_SAPI !== 'cli')) SystemMessage::factory() ->title('Record Updated') ->type('success') ->body(sprintf('Record %s:%s Updated',$this->_table_name,$this->id)); return $this; } public function subitems() { return $this->_sub_items; } /** * Override the Kohana processing so we can null values if required. * We override this function, because we do set our own primary key value */ public function values(array $values, array $expected = NULL) { foreach ($values as $k=>$v) { // Convert to NULL if (in_array($k,$this->_nullifempty)) { if (is_array($v)) $values[$k] = $this->_nullifempty($v); elseif (! $v AND $v !== 0 AND $v !== '0') $values[$k] = NULL; } } parent::values($values,$expected); if (isset($values[$this->_primary_key])) $this->{$this->_primary_key} = $values[$this->_primary_key]; return $this; } public function what_changed() { $result = array(); foreach ($this->changed() as $k) { $result[$k]['old'] = ($x=Arr::get($this->_original_values,$k)) ? $x : serialize($x); $result[$k]['new'] = ($x=Arr::get($this->_object,$k)) ? $x : serialize($x); } return $result; } } ?>