[ Index ] |
|
Code source de LifeType 1.2.4 |
1 <?php 2 3 /** 4 * \defgroup DAO 5 * 6 * DAO stands for "Data Access Object" and represents a data model 7 * according to the MVC architecture. 8 * 9 * DAO classes isolate developers of all the intricacies of the 10 * database structure, so that for example loading a post from the 11 * dabase is as easy as: 12 * 13 * <pre> 14 * $articles = new Articles(); 15 * $userPost = $arcticles->getBlogArticle( 15 ); 16 * </pre> 17 * 18 * Otherwise, developers would need to write an SQL query every time we 19 * need to load an article from the database. In general, DAO classes 20 * provide access to reading, updating and removing data from the database. 21 * In pLog, we usually have two classes per entity: a smaller one that 22 * contains no database access logic and that only contains the information 23 * necessary (usually, it represents a row from the database), and the 24 * second will be a bigger class that includes SQL code and database logic 25 * and that provides all the methods outlined above (read, update and 26 * remove from the database) Examples of this are Articles and Article, 27 * or Users and UserInfo. 28 * 29 * Other relevant DAO classes are ArticleComments and UserComment, 30 * MyLink and MyLinks, etc. 31 * 32 * All classes that extend the base Model class, automatically inherit 33 * an open connection to the database * (via the private attribute 34 * Model::_db) and several other database-related methods. 35 * 36 * Furthermore all classes that extend the base Model class gets a 37 * reference to the global disk-based cache. More information on how 38 * to use the cache can be found in the Cache Group 39 * 40 * If you need to implement some kind of data access, please extend 41 * from Model. 42 * 43 */ 44 45 /** 46 * default database prefix, if none other specified 47 */ 48 define( "DEFAULT_DB_PREFIX", "plog_" ); 49 50 /** 51 * whether database-level debugging is enabled 52 */ 53 define( "DAO_DEBUG_ENABLED", false ); 54 55 /** 56 * how many items per page by default, when paging is enabled 57 */ 58 define( "DEFAULT_ITEMS_PER_PAGE", 15 ); 59 60 /** 61 * whether we're going to use paging or not. 62 */ 63 define( "DEFAULT_PAGING_ENABLED", -1 ); 64 65 /** 66 * enable or disable the data cache 67 */ 68 define( "DATA_CACHE_ENABLED", true ); 69 70 /** 71 * the names of the tables used in pLog 72 */ 73 define( 'BLOGS_TABLENAME', 'blogs' ); 74 define( 'ARTICLES_TABLENAME', 'articles' ); 75 define( 'ARTICLETEXTS_TABLENAME', 'articles_text' ); 76 define( 'ARTICLE_CATEGORIES_RELATIONSHIP_TABLENAME', 77 'article_categories_link' ); 78 define( 'CUSTOMFIELD_VALUES', 'custom_fields_values' ); 79 80 81 /** 82 * \ingroup DAO 83 * 84 * This class provides all the classes extending it with a database 85 * connection so that classes don't have to 86 * worry about that. Later on, the Model classes will be used by 87 * the corresponding action object. 88 */ 89 class Model 90 { 91 92 var $_db; 93 var $_prefix = null; 94 var $_cache; 95 var $_dbInitialized = false; 96 var $_lastError = ""; 97 98 /** 99 * Basic constructor, setting up a cache for all classes extending Model 100 * 101 * @param useCache Some object might not need a cache and can disable it by passing false 102 */ 103 function Model( $cacheEnabled = DATA_CACHE_ENABLED ) 104 { 105 // allow a cache for all dao objects 106 lt_include( PLOG_CLASS_PATH . "class/cache/cachemanager.class.php" ); 107 $this->_cache =& CacheManager::getCache( $cacheEnabled ); 108 } 109 110 /** 111 * executes a query with certain limits (for paging, for ex.) 112 * 113 * @param query The query to be executed 114 * @param page enable paging, pass page number or -1 to disable paging 115 * @param itemsPerPage number of items on a page 116 * @see Execute 117 * @return A ResultSet or false if errors 118 */ 119 function Execute( $query, 120 $page = DEFAULT_PAGING_ENABLED, 121 $itemsPerPage = DEFAULT_ITEMS_PER_PAGE ) 122 { 123 // initialize the db when we have to execute the first query, 124 // not earlier. 125 $this->_initializeDb(); 126 127 // see PDbDriverBase (or one of its drivers like PDbMySQLDriver 128 // for details) 129 $result = $this->_db->Execute( $query, $page, $itemsPerPage ); 130 131 // if the query generated an error, write a message to the sql 132 // error log file 133 if( !$result ) { 134 $this->_lastError = $this->_db->ErrorMsg(); 135 lt_include( PLOG_CLASS_PATH . "class/logger/loggermanager.class.php" ); 136 137 $log =& LoggerManager::getLogger( "sqlerr" ); 138 $error = $this->DbError(); 139 $log->error( "The following query = \n" . 140 $query . 141 "generated the following error message = \n" . 142 $error ); 143 } 144 145 return( $result ); 146 } 147 148 /** 149 * Returns the last error message from the database. 150 * 151 * @param driverError Set this field to true if interested in getting the error message as reported by 152 * the driver. Keep in mind that the error message might be gone after we've closed the connection 153 * (by calling the Close() method at the driver level) The only way to get the error message in 154 * that case (if any at all) is by setting this parameter to 'false'. If done so, this class will save 155 * the last error message and make it available via this method. This parameter defaults to false. 156 * @return A string containing the error message 157 */ 158 function DbError( $driverError = false ) 159 { 160 if( $driverError ) 161 return( $this->_db->ErrorMsg()); 162 else 163 return( $this->_lastError ); 164 } 165 166 /** 167 * Retrieves one single row/object from the database 168 * 169 * @param field 170 * @param value 171 * @param cacheId 172 * @param caches 173 * @return 174 */ 175 function get( $field, $value, $cacheId, $caches = null ) 176 { 177 $dbObject = $this->_cache->getData( $value, $cacheId ); 178 179 if( !$dbObject ) { 180 $query = "SELECT * FROM ".$this->table." WHERE {$field} = '".Db::qstr( $value )."'"; 181 182 $result = $this->Execute( $query ); 183 184 if( !$result ) 185 return false; 186 187 if( $result->RowCount() == 0 ){ 188 $result->Close(); 189 return false; 190 } 191 192 $row = $result->FetchRow(); 193 $result->Close(); 194 195 $dbObject = $this->mapRow( $row ); 196 197 $this->_cache->setData( $value, $cacheId, $dbObject ); 198 if( $caches ) { 199 foreach( $caches as $cache => $getter ) { 200 $this->_cache->setData( $dbObject->$getter(), $cache, $dbObject ); 201 } 202 } 203 } 204 205 return( $dbObject ); 206 207 } 208 209 /** 210 * Retrieves all the rows from the given table 211 * 212 * @param key 213 * @param cacheId 214 * @param itemCaches 215 * @param sorting 216 * @param searchTerms 217 * @param page 218 * @param itemsPerPage 219 * @return 220 */ 221 function getAll( $key, $cacheId, $itemCaches = null, $sorting = Array(), $searchTerms ="", $page = -1, $itemsPerPage = DEFAULT_ITEMS_PER_PAGE ) 222 { 223 return( $this->getMany( $key, "_all_", $cacheId, $itemCaches, $sorting, $searchTerms, $page, $itemsPerPage )); 224 } 225 226 /** 227 * This method must be reimplemented by child classes wishing to provide 228 * search functionalities 229 * 230 * @param searchTerms 231 * @return search string to be used in an SQL query 232 */ 233 function getSearchConditions( $searchTerms ) 234 { 235 return( "" ); 236 } 237 238 /** 239 * Retrieves a set of rows of the given table using the given (simple) conditions. 240 * 241 * @param key 242 * @param value 243 * @param cacheId 244 * @param itemCaches 245 * @param sorting 246 * @param searchTerms 247 * @param page 248 * @param itemsPerPage 249 * @return 250 */ 251 function getMany( $key, $value, $cacheId, $itemCaches = null, $sorting = Array(), $searchTerms = "", $page = -1, $itemsPerPage = DEFAULT_ITEMS_PER_PAGE ) 252 { 253 // if we previously used the search terms, then we did not cache the data 254 if( $searchTerms == "" ) 255 $dbObjects = $this->_cache->getData( $value, $cacheId ); 256 else 257 $dbObjects = null; 258 259 if( !$dbObjects ) { 260 $query = "SELECT * FROM ".$this->table; 261 $where = ""; 262 // if $value is 'all' or null, then we are going to cache the whole thing so let's not 263 // include these as parameters. 264 if( $value != "_all_" && $value != null ) { 265 $where .= " WHERE {$key} = '".Db::qstr($value)."'"; 266 } 267 if( $searchTerms != "" ) { 268 // get the table-dependent search string 269 $search = $this->getSearchConditions( $searchTerms ); 270 // add the search terms, if any 271 if( $where ) $where .= " AND $search"; 272 else 273 if( $search) $where = " WHERE ".$search; 274 // remove the last 'AND' in case it's the last thing in the string 275 if( substr($where, strlen( $where ) - 3 , 3) == 'AND' ) 276 $where = substr( $where, 0, strlen( $where ) - 3 ); 277 } 278 $orderBy = ""; 279 if( count( $sorting ) > 0 ) { 280 // check the sorting... 281 $orderBy = " ORDER BY "; 282 foreach( $sorting as $field => $dir ) { 283 $orderBy .= "$field $dir"; 284 } 285 } 286 287 // build the query including all parts 288 $query = $query.$where.$orderBy; 289 290 $result = $this->Execute( $query ); 291 292 if( !$result ) 293 return false; 294 295 if( $result->RowCount() == 0 ){ 296 $result->Close(); 297 return false; 298 } 299 300 $dbObjects = Array(); 301 while( $row = $result->FetchRow()) { 302 $dbObject = $this->mapRow( $row ); 303 $dbObjects[] = $dbObject; 304 if( $itemCaches ) { 305 foreach( $itemCaches as $cache => $getter ) { 306 $this->_cache->setData( $dbObject->$getter(), $cache, $dbObject ); 307 } 308 } 309 } 310 $result->Close(); 311 312 // do not cache data if using search terms! 313 if( $searchTerms == "" ) 314 $this->_cache->setData( $value, $cacheId, $dbObjects ); 315 } 316 317 if( $page > -1 ) { 318 // return only a subset of the items 319 $start = (($page - 1) * $itemsPerPage ); 320 $dbObjects = array_slice( $dbObjects, $start, $itemsPerPage ); 321 } 322 323 return( $dbObjects ); 324 } 325 326 /** 327 * Adds a row to the current table 328 * 329 * @param dbObject 330 * @param cacheId 331 * @return True if successful or false if error 332 */ 333 function add( &$dbObject, $cacheId = null ) 334 { 335 $fields = $dbObject->getFieldGetters(); 336 $fieldsString = ''; 337 $fieldsValuesString = ''; 338 339 $sql = "INSERT INTO `".$this->table."` ("; 340 341 foreach ($fields as $field => $getter) 342 { 343 if( $field != "id" ) { 344 // let's ignore the primary key! 345 $fieldsString .= $field.", "; 346 347 $value = $dbObject->$getter(); 348 349 if( is_array( $value )) $value = serialize( $value ); 350 elseif( is_bool( $value )) $value = (int)$value; // convert the bool to '1' or '0' 351 elseif( is_object( $value )) { 352 if( strtolower(get_class( $value )) == "timestamp" ) 353 $value = $value->getTimestamp(); 354 else 355 $value = serialize( $value ); 356 } 357 $value = Db::qstr($value); 358 $fieldsValuesString .= "'" . $value . "', "; 359 } 360 } 361 362 $sql .= substr($fieldsString, 0, -2) . ") VALUES (".substr($fieldsValuesString, 0, -2).")"; 363 364 $result = $this->Execute( $sql ); 365 if( !$result ) 366 return false; 367 368 $dbObject->setId( $this->_db->Insert_ID()); 369 370 if( $cacheId ) { 371 foreach( $cacheId as $cache => $getter ) { 372 $this->_cache->setData( $dbObject->{$getter}(), $cache, $dbObject ); 373 } 374 } 375 376 return( $dbObject->getId()); 377 } 378 379 /** 380 * Updates an object/row in the database 381 * 382 * @param dbObject 383 * @return True if successful or false if error 384 */ 385 function update( &$dbObject ) 386 { 387 lt_include( PLOG_CLASS_PATH."class/database/db.class.php" ); 388 389 $fields = $dbObject->getFieldGetters(); 390 $sql = "UPDATE `".$this->table."` SET "; 391 392 foreach ($fields as $field => $getter) 393 { 394 $value = $dbObject->$getter(); 395 if( is_array( $value )) $value = serialize( $value ); 396 elseif( strtolower(get_class( $value )) == "timestamp" ) 397 $value = $value->getTimestamp(); 398 elseif( is_object( $value )) $value = serialize( $value ); 399 400 $value = Db::qstr($value); 401 $sql .= "`" . $field . "`='" . $value . "', "; 402 } 403 404 $sql = substr($sql, 0, -2) . " WHERE id = '".Db::qstr($dbObject->getId())."'"; 405 406 $result = $this->Execute( $sql ); 407 408 if( !$result ) 409 return false; 410 411 return true; 412 } 413 414 /** 415 * Deletes a row from the database, using the field and value parameters as the condition 416 * 417 * @param field 418 * @param value 419 * @return True if successful or false otherwise 420 */ 421 function delete( $field, $value ) 422 { 423 $query = "DELETE FROM ".$this->table." WHERE {$field} = '{$value}'"; 424 $result = $this->Execute( $query ); 425 return( $result ); 426 } 427 428 /** 429 * returns the current database prefix 430 * 431 * @deprecated the prefix should be set/added by the Db Classes, not by the model 432 * @return the current database prefix 433 */ 434 function getPrefix() 435 { 436 if ( $this->_prefix === null ) { 437 lt_include( PLOG_CLASS_PATH."class/database/db.class.php" ); 438 439 $this->_prefix = Db::getPrefix(); 440 } 441 442 return $this->_prefix; 443 } 444 445 /** 446 * retrieves the number of records in a table given an optional condition 447 * 448 * @param table 449 * @param cond 450 * @return the number of items or 0 if none or error 451 */ 452 function getNumItems( $table, $cond = "", $pk = "id" ) 453 { 454 // build up the query 455 if( $cond != "" ) $cond = "WHERE $cond"; 456 $query = "SELECT COUNT($pk) AS total FROM $table $cond"; 457 458 // execute it 459 $result = $this->Execute( $query ); 460 461 if( !$result ) 462 return 0; 463 464 // if no error, get the result 465 $row = $result->FetchRow(); 466 $result->Close(); 467 468 $total = $row["total"]; 469 if( $total == "" ) $total = 0; 470 471 return $total; 472 } 473 474 /** 475 * Initialize the Db and set the table-prefix. 476 * 477 * @private 478 */ 479 function _initializeDb() 480 { 481 if ( !$this->_dbInitialized ) { 482 lt_include( PLOG_CLASS_PATH."class/database/db.class.php" ); 483 484 $this->_db =& Db::getDb(); 485 486 $this->_dbInitialized = true; 487 } 488 } 489 } 490 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Mon Nov 26 21:04:15 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |