1<?php 2/** 3 * @package Habari 4 * 5 */ 6 7/** 8 * Habari InfoRecords Class 9 * 10 * Base class for managing metadata about various Habari objects 11 * 12 */ 13abstract class InfoRecords implements URLProperties 14{ 15 // the info array 16 protected $__inforecord_array = array(); 17 // table which contains the info records 18 protected $_table_name; 19 // name of the primary key in the info record table 20 protected $_key_name; 21 // value of the primary key - the master record 22 protected $_key_value; 23 // set to true only when the inforecords have been loaded 24 protected $_loaded = false; 25 26 protected $url_args; 27 28 /** 29 * Takes three parameters. The table of the options table, the name of the master key and the record_id for which options are managed. 30 * posts take a slug as a record_id, comments take a comment_id and users take a user_id (user_name) 31 * 32 * <b>IMPORTANT:</b> if <tt>$primary_key_value</tt> is not set in the constructor, set_key MUST be called before inforecords can be set. Or bad things 33 * (think swarms of locusts o'er the land) will happen 34 * 35 * @param string $table_name name of the table to insert info (use the DB::o()->table_name syntax) 36 * @param string $key_name name of the primary key (for example "post_id") 37 * @param mixed $key_value (optional) the master record key value (for example, info for post_id = 1 managed by setting this param to 1). Use 38 * set_key method if not set here. 39 **/ 40 public function __construct( $table_name, $key_name, $key_value = null ) 41 { 42 $this->_table_name = $table_name; 43 $this->_key_name = $key_name; 44 $this->_key_value = $key_value; 45 $this->_loaded = false; 46 } 47 48 /** 49 * Test if the master record value has been set (and thus, safe to set info records). 50 * 51 * @return boolean true if master record value has been set already, false otherwise 52 **/ 53 public function is_key_set() 54 { 55 return isset( $this->_key_value ); 56 } 57 58 /** 59 * function set_key 60 * For use in cases where the master record key is not known at the time of object instantiation (ie: a new post) 61 * 62 * @param mixed $metadata_key the id of the master record (could be int or string, most likely int) 63 * 64 **/ 65 public function set_key( $metadata_key ) 66 { 67 $this->_key_value = $metadata_key; 68 } 69 70 /** 71 * Populate the internal hashmap with the values from the DB. 72 */ 73 protected function _load() 74 { 75 if ( $this->_loaded == true ) { 76 return; 77 } 78 if ( empty($this->_key_value) ) { 79 $this->_loaded == true; 80 return; 81 } 82 83 // This InfoRecord is read-only? 84 if ( empty($this->_table_name) ) { 85 $this->_loaded == true; 86 return; 87 } 88 89 $result = DB::get_results( ' 90 SELECT name, value, type 91 FROM ' . $this->_table_name . ' 92 WHERE ' . $this->_key_name . ' = ?', 93 array( $this->_key_value ) 94 ); 95 96 foreach ( $result as $result_element ) { 97 // XXX is this logic right? 98 if ( $result_element->type == 1 ) { 99 $this->__inforecord_array[$result_element->name] = array( 'value' => unserialize( $result_element->value ) ); 100 } 101 else { 102 $this->__inforecord_array[$result_element->name] = array( 'value' => $result_element->value ); 103 } 104 } 105 106 $this->_loaded = true; 107 } 108 109 /** 110 * Fetch info record value. 111 * @param string $name Name of the key to get 112 * @return mixed Stored value for specified key 113 **/ 114 public function __get ( $name ) 115 { 116 $this->_load(); 117 if ( ! isset( $this->__inforecord_array[$name] ) ) { 118 return false; 119 } 120 return $this->__inforecord_array[$name]['value']; 121 } 122 123 /** 124 * Update the info record. 125 * The value will not be stored in the database until calling $this->commit(); 126 * 127 * @param string $name Name of the key to set 128 * @param mixed $value Value to set 129 **/ 130 public function __set( $name, $value ) 131 { 132 $this->_load(); 133 $this->__inforecord_array[$name] = array('changed'=>true, 'value'=>$value); 134 } 135 136 /** 137 * Test for the existence of specified info value 138 * 139 * @param string $name Name of the option to set 140 * @return boolean true if the info option exists, false in all other cases 141 **/ 142 public function __isset ( $name ) 143 { 144 $this->_load(); 145 return isset( $this->__inforecord_array[$name] ); 146 } 147 148 /** 149 * Remove an info option; immediately unsets from the storage AND removes from database. Use with caution. 150 * 151 * @param string $name Name of the option to unset 152 * @return boolean true if the option is successfully unset, false otherwise 153 **/ 154 public function __unset( $name ) 155 { 156 $this->_load(); 157 if ( isset( $this->__inforecord_array[$name] ) ) { 158 DB::delete( $this->_table_name, array ( $this->_key_name => $this->_key_value, "name" => $name ) ); 159 unset( $this->__inforecord_array[$name] ); 160 return true; 161 } 162 return false; 163 } 164 165 /** 166 * Returns a set of properties used by URL::get to create URLs 167 * @return array Properties of this post used to build a URL 168 **/ 169 public function get_url_args() 170 { 171 if ( !$this->url_args ) { 172 $this->_load(); 173 $this->url_args = array_map( create_function( '$a', 'return $a["value"];' ), $this->__inforecord_array ); 174 } 175 return $this->url_args; 176 } 177 178 /** 179 * Remove all info options. Primarily used when deleting the parent object. 180 * I.E. when deleting a user, the delete method would call this. 181 * 182 * @return boolean true if the options were successfully unset, false otherwise 183 **/ 184 public function delete_all() 185 { 186 // This InfoRecord is read-only? 187 if ( empty($this->_table_name) ) { 188 return; 189 } 190 $result = DB::query( ' 191 DELETE FROM ' . $this->_table_name . ' 192 WHERE ' . $this->_key_name . ' = ?', 193 array( $this->_key_value ) 194 ); 195 if ( Error::is_error( $result ) ) { 196 $result->out(); 197 return false; 198 } 199 $this->__inforecord_array = array(); 200 return true; 201 } 202 203 /** 204 * Commit all of the changed info options to the database. 205 * If this function is not called, then the options will not be written. 206 * 207 * @param mixed $metadata_key (optional) Key to use when writing info data. 208 */ 209 public function commit( $metadata_key = null ) 210 { 211 if ( isset( $metadata_key ) ) { 212 $this->_key_value = $metadata_key; 213 } 214 // If the info is not already loaded, and the key value is empty, 215 // then we don't have enough info to do the commit 216 if ( !$this->_loaded && empty($this->_key_value) ) { 217 return true; 218 } 219 220 foreach ( (array)$this->__inforecord_array as $name=>$record ) { 221 if ( isset( $record['changed'] ) && $record['changed'] ) { 222 $value = $record['value']; 223 if ( is_array( $value ) || is_object( $value ) ) { 224 $result = DB::update( 225 $this->_table_name, 226 array( 227 $this->_key_name=>$this->_key_value, 228 'name'=>$name, 229 'value'=>serialize( $value ), 230 'type'=>1 231 ), 232 array( 'name'=>$name, $this->_key_name=>$this->_key_value ) 233 ); 234 } 235 else { 236 $result = DB::update( 237 $this->_table_name, 238 array( 239 $this->_key_name=>$this->_key_value, 240 'name'=>$name, 241 'value'=>$value, 242 'type'=>0 243 ), 244 array('name'=>$name, $this->_key_name=> $this->_key_value) 245 ); 246 } 247 248 if ( Error::is_error( $result ) ) { 249 $result->out(); 250 } 251 $this->__inforecord_array[$name] = array('value'=>$value); 252 } 253 } 254 } 255 256 public function count() 257 { 258 $this->_load(); 259 return count( $this->__inforecord_array ); 260 261 } 262 263} 264 265?> 266