[ Index ] |
|
Code source de b2evolution 2.1.0-beta |
1 <?php 2 /** 3 * This file implements the AbstractSettings class designed to handle any kind of settings. 4 * 5 * This file is part of the evoCore framework - {@link http://evocore.net/} 6 * See also {@link http://sourceforge.net/projects/evocms/}. 7 * 8 * @copyright (c)2003-2007 by Francois PLANQUE - {@link http://fplanque.net/} 9 * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}. 10 * 11 * {@internal License choice 12 * - If you have received this file as part of a package, please find the license.txt file in 13 * the same folder or the closest folder above for complete license terms. 14 * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/) 15 * then you must choose one of the following licenses before using the file: 16 * - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php 17 * - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php 18 * }} 19 * 20 * {@internal Open Source relicensing agreement: 21 * Daniel HAHLER grants Francois PLANQUE the right to license 22 * Daniel HAHLER's contributions to this file and the b2evolution project 23 * under any OSI approved OSS license (http://www.opensource.org/licenses/). 24 * }} 25 * 26 * @package evocore 27 * 28 * {@internal Below is a list of authors who have contributed to design/coding of this file: }} 29 * @author blueyed: Daniel HAHLER 30 * @author fplanque: Francois PLANQUE 31 * 32 * @version $Id: _abstractsettings.class.php,v 1.1 2007/06/25 11:01:20 fplanque Exp $ 33 */ 34 if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' ); 35 36 /** 37 * Class to handle settings in an abstract manner (to get used with either 1, 2 or 3 DB column keys). 38 * 39 * Arrays and Objects automatically get serialized and unserialized 40 * (in {@link AbstractSettings::get()} and {@link AbstractSettings::dbupdate()}). 41 * 42 * Note: I've evaluated splitting this into single classes for performance reasons, but only 43 * get() is relevant performance-wise and we could now only get rid of the switch() therein, 44 * which is not sufficient to split it into *_base + _X classes. (blueyed, 2006-08) 45 * 46 * @package evocore 47 * @abstract 48 * @see UserSettings, GeneralSettings, PluginSettings, CollectionSettings 49 */ 50 class AbstractSettings 51 { 52 /** 53 * The DB table which stores the settings. 54 * 55 * @var string 56 * @access protected 57 */ 58 var $db_table_name; 59 60 /** 61 * Array with DB column key names. 62 * 63 * @var array 64 * @access protected 65 */ 66 var $col_key_names = array(); 67 68 /** 69 * DB column name for the value. 70 * 71 * @var string 72 * @access protected 73 */ 74 var $col_value_name; 75 76 77 /** 78 * The number of column keys to cache by. This are the first x keys of 79 * {@link $col_key_names}. 0 means 'load all'. 80 * 81 * @var integer 82 */ 83 var $cache_by_col_keys; 84 85 86 /** 87 * The internal cache. 88 * 89 * false, if settings could not be loaded or NULL if not initialized. 90 * 91 * @access protected 92 * @var array 93 */ 94 var $cache = NULL; 95 96 97 /** 98 * Do we have loaded everything? 99 * 100 * @var boolean 101 */ 102 var $all_loaded = false; 103 104 105 /** 106 * Default settings. 107 * 108 * Maps last colkeyname to some default setting that will be used by 109 * {@link get()} if no value was defined (and it is set as a default). 110 * 111 * @var array 112 */ 113 var $_defaults = array(); 114 115 116 /** 117 * Constructor. 118 * @param string The name of the DB table with the settings stored. 119 * @param array List of names for the DB columns keys that reference a value. 120 * @param string The name of the DB column that holds the value. 121 * @param integer The number of column keys to cache by. This are the first x keys of {@link $col_key_names}. 0 means 'load all'. 122 */ 123 function AbstractSettings( $db_table_name, $col_key_names, $col_value_name, $cache_by_col_keys = 0 ) 124 { 125 $this->db_table_name = $db_table_name; 126 $this->col_key_names = $col_key_names; 127 $this->col_value_name = $col_value_name; 128 $this->cache_by_col_keys = $cache_by_col_keys; 129 130 131 /** 132 * internal counter for the number of column keys 133 * @var integer 134 */ 135 $this->count_col_key_names = count( $this->col_key_names ); 136 137 if( $this->count_col_key_names > 3 || $this->count_col_key_names < 1 ) 138 { 139 debug_die( 'Settings keycount not supported for class '.get_class() ); 140 } 141 } 142 143 144 /** 145 * Load all settings, disregarding the derived classes setting of 146 * {@link $cache_by_col_keys} - useful if you know that you want to get 147 * all user settings for example. 148 */ 149 function load_all() 150 { 151 return $this->_load(); 152 } 153 154 155 /** 156 * Loads the settings. Not meant to be called directly, but gets called 157 * when needed. 158 * 159 * @access protected 160 * @param string First column key 161 * @param string Second column key 162 * @param string Third column key 163 * @return boolean always true 164 */ 165 function _load( $arg1 = NULL, $arg2 = NULL, $arg3 = NULL ) 166 { 167 if( $this->all_loaded ) 168 { // already all loaded 169 return true; 170 } 171 global $DB; 172 173 /** 174 * The where clause - gets filled when {@link $cache_by_col_keys} is used. 175 */ 176 $whereList = array(); 177 178 if( $this->cache_by_col_keys && isset($arg1) ) 179 { 180 $testCache = $this->cache; 181 $args = array( $arg1, $arg2, $arg3 ); 182 183 for( $i = 0; $i < $this->cache_by_col_keys; $i++ ) 184 { 185 $whereList[] = $this->col_key_names[$i]." = '".$args[$i]."'"; 186 187 if( ! is_array( $testCache ) 188 || is_null($args[$i]) 189 || ! isset( $testCache[$args[$i]] ) 190 || ! ($testCache = & $testCache[$args[$i]]) ) 191 { 192 break; 193 } 194 } 195 196 if( $i == $this->cache_by_col_keys ) 197 { // already loaded! 198 return true; 199 } 200 } 201 else 202 { // we're about to load everything 203 $this->all_loaded = true; 204 } 205 206 207 $result = $DB->get_results( ' 208 SELECT '.implode( ', ', $this->col_key_names ).', '.$this->col_value_name.' 209 FROM '.$this->db_table_name.( 210 isset( $whereList[0] ) 211 ? ' WHERE '.implode( ' AND ', $whereList ) 212 : '' ) ); 213 214 switch( $this->count_col_key_names ) 215 { 216 case 1: 217 if( ! $result ) 218 { // Remember that we've tried it 219 $this->cache[ $arg1 ] = NULL; 220 } 221 else foreach( $result as $loop_row ) 222 { 223 $this->cache[$loop_row->{$this->col_key_names[0]}]->value = $loop_row->{$this->col_value_name}; 224 $this->cache[$loop_row->{$this->col_key_names[0]}]->dbUptodate = true; 225 $this->cache[$loop_row->{$this->col_key_names[0]}]->dbRemove = false; 226 } 227 break; 228 229 case 2: 230 if( ! $result ) 231 { // Remember that we've tried it 232 $this->cache[ $arg1 ][ $arg2 ] = NULL; 233 } 234 else foreach( $result as $loop_row ) 235 { 236 $this->cache[$loop_row->{$this->col_key_names[0]}][$loop_row->{$this->col_key_names[1]}]->value = $loop_row->{$this->col_value_name}; 237 $this->cache[$loop_row->{$this->col_key_names[0]}][$loop_row->{$this->col_key_names[1]}]->dbUptodate = true; 238 $this->cache[$loop_row->{$this->col_key_names[0]}][$loop_row->{$this->col_key_names[1]}]->dbRemove = false; 239 } 240 break; 241 242 case 3: 243 if( ! $result ) 244 { // Remember that we've tried it 245 $this->cache[ $arg1 ][ $arg2 ][ $arg3 ] = NULL; 246 } 247 else foreach( $result as $loop_row ) 248 { 249 $this->cache[$loop_row->{$this->col_key_names[0]}][$loop_row->{$this->col_key_names[1]}][$loop_row->{$this->col_key_names[2]}]->value = $loop_row->{$this->col_value_name}; 250 $this->cache[$loop_row->{$this->col_key_names[0]}][$loop_row->{$this->col_key_names[1]}][$loop_row->{$this->col_key_names[2]}]->dbUptodate = true; 251 $this->cache[$loop_row->{$this->col_key_names[0]}][$loop_row->{$this->col_key_names[1]}][$loop_row->{$this->col_key_names[2]}]->dbRemove = false; 252 } 253 break; 254 } 255 256 return true; 257 } 258 259 260 /** 261 * Get a setting from the DB settings table. 262 * 263 * @uses get_default() 264 * @param string First column key 265 * @param string Second column key 266 * @param string Third column key 267 * @return string|false|NULL value as string on success; NULL if not found; false in case of error 268 */ 269 function get( $col_key1, $col_key2 = NULL, $col_key3 = NULL ) 270 { 271 global $debug; 272 273 if( $debug ) 274 { 275 global $Debuglog, $Timer; 276 $this_class = get_class($this); 277 $Timer->resume('abstractsettings_'.$this_class.'_get'); 278 } 279 280 switch( $this->count_col_key_names ) 281 { 282 case 1: 283 $this->_load( $col_key1 ); 284 285 if( isset($this->cache[ $col_key1 ]->unserialized) ) 286 { // The value has been unserialized before: 287 $r = $this->cache[ $col_key1 ]->value; 288 } 289 elseif( isset($this->cache[ $col_key1 ]->value) ) 290 { // First attempt to access the value, we need to unserialize it: 291 // Try to unserialize setting (once) - this is as fast as checking an array of values that should get unserialized 292 if( ($r = @unserialize($this->cache[ $col_key1 ]->value)) !== false ) 293 { 294 $this->cache[ $col_key1 ]->value = $r; 295 } 296 else 297 { 298 $r = $this->cache[ $col_key1 ]->value; 299 } 300 $this->cache[ $col_key1 ]->unserialized = true; 301 } 302 else 303 { // The value is not in the cache, we use the default: 304 $r = $this->get_default( $col_key1 ); 305 $this->cache[ $col_key1 ]->value = $r; // remember in cache 306 $this->cache[ $col_key1 ]->dbUptodate = true; 307 $this->cache[ $col_key1 ]->unserialized = true; 308 $from_default = true; // for debug 309 } 310 break; 311 312 case 2: 313 $this->_load( $col_key1, $col_key2 ); 314 315 if( isset($this->cache[ $col_key1 ][ $col_key2 ]->unserialized) ) 316 { 317 $r = $this->cache[ $col_key1 ][ $col_key2 ]->value; 318 } 319 elseif( isset($this->cache[ $col_key1 ][ $col_key2 ]->value) ) 320 { 321 // Try to unserialize setting (once) - this is as fast as checking an array of values that should get unserialized 322 if( ($r = @unserialize($this->cache[ $col_key1 ][ $col_key2 ]->value)) !== false ) 323 { 324 $this->cache[ $col_key1 ][ $col_key2 ]->value = $r; 325 } 326 else 327 { 328 $r = $this->cache[ $col_key1 ][ $col_key2 ]->value; 329 } 330 $this->cache[ $col_key1 ][ $col_key2 ]->unserialized = true; 331 } 332 else 333 { 334 $r = $this->get_default( $col_key2 ); 335 $this->cache[ $col_key1 ][ $col_key2 ]->value = $r; // remember in cache 336 $this->cache[ $col_key1 ][ $col_key2 ]->dbUptodate = true; 337 $this->cache[ $col_key1 ][ $col_key2 ]->unserialized = true; 338 $from_default = true; // for debug 339 } 340 break; 341 342 case 3: 343 $this->_load( $col_key1, $col_key2, $col_key3 ); 344 345 if( isset($this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->unserialized) ) 346 { 347 $r = $this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->value; 348 } 349 elseif( isset($this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->value) ) 350 { 351 // Try to unserialize setting (once) - this is as fast as checking an array of values that should get unserialized 352 if( ($r = @unserialize($this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->value)) !== false ) 353 { 354 $this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->value = $r; 355 } 356 else 357 { 358 $r = $this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->value; 359 } 360 $this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->unserialized = true; 361 } 362 else 363 { 364 $r = $this->get_default( $col_key3 ); 365 $this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->value = $r; // remember in cache 366 $this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->dbUptodate = true; 367 $this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->unserialized = true; 368 $from_default = true; // for debug 369 } 370 break; 371 } 372 373 if( $debug ) 374 { 375 $Debuglog->add( $this_class.'::get( '.$col_key1.'/'.$col_key2.'/'.$col_key3.' ): ' 376 .( isset($from_default) ? '[DEFAULT]: ' : '' ) 377 .var_export( $r, true ), 'settings' ); 378 $Timer->pause('abstractsettings_'.$this_class.'_get'); 379 } 380 381 return $r; 382 } 383 384 385 /** 386 * Get the default for the last key of {@link $col_key_names} 387 * 388 * @param string The last column key 389 * @return NULL|mixed NULL if no default is set, otherwise the value (should be string). 390 */ 391 function get_default( $last_key ) 392 { 393 if( isset($this->_defaults[ $last_key ]) ) 394 { 395 return $this->_defaults[ $last_key ]; 396 } 397 398 return NULL; 399 } 400 401 402 /** 403 * Only set the first variable (passed by reference) if we could retrieve a 404 * setting. 405 * 406 * @param mixed variable to set maybe (by reference) 407 * @param string the values for the column keys (depends on $this->col_key_names 408 * and must match its count and order) 409 * @return boolean true on success (variable was set), false if not 410 */ 411 function get_cond( & $toset ) 412 { 413 $args = func_get_args(); 414 array_shift( $args ); 415 416 $result = call_user_func_array( array( & $this, 'get' ), $args ); 417 418 if( $result !== NULL && $result !== false ) 419 { // No error and value retrieved 420 $toset = $result; 421 return true; 422 } 423 else 424 { 425 return false; 426 } 427 } 428 429 430 /** 431 * Temporarily sets a setting ({@link dbupdate()} writes it to DB). 432 * 433 * @param string $args,... the values for the {@link $col_key_names column keys} 434 * and {@link $col_value_name column value}. Must match order and count! 435 * @return boolean true, if the value has been set, false if it has not changed. 436 */ 437 function set() 438 { 439 global $Debuglog; 440 441 $args = func_get_args(); 442 $value = array_pop($args); 443 444 call_user_func_array( array(&$this, '_load'), $args ); 445 446 $debugMsg = get_class($this).'::set( '.implode(', ', $args ).' ): '; 447 448 switch( $this->count_col_key_names ) 449 { 450 case 1: 451 $atCache = & $this->cache[ $args[0] ]; 452 break; 453 454 case 2: 455 $atCache = & $this->cache[ $args[0] ][ $args[1] ]; 456 break; 457 458 case 3: 459 $atCache = & $this->cache[ $args[0] ][ $args[1] ][ $args[2] ]; 460 break; 461 462 default: 463 return false; 464 } 465 466 $atCache->dbRemove = false; 467 468 if( isset($atCache->value) ) 469 { 470 if( $atCache->value == $value ) 471 { // already set 472 $Debuglog->add( $debugMsg.' Already set to the same value.', 'settings' ); 473 return false; 474 } 475 } 476 477 $atCache->value = $value; 478 $atCache->dbUptodate = false; 479 $atCache->unserialized = true; 480 481 $Debuglog->add( $debugMsg.' SET!', 'settings' ); 482 483 return true; 484 } 485 486 487 /** 488 * Set an array of values. 489 * 490 * @param array Array of parameters for {@link set()} 491 */ 492 function set_array( $array ) 493 { 494 foreach( $array as $lSet ) 495 { 496 call_user_func_array( array( & $this, 'set' ), $lSet ); 497 } 498 } 499 500 501 /** 502 * Remove a setting. 503 * 504 * @param array List of {@link $col_key_names} 505 * @return boolean 506 */ 507 function delete( $args ) 508 { 509 $args = func_get_args(); 510 511 switch( $this->count_col_key_names ) 512 { 513 case 1: 514 $atCache = & $this->cache[ $args[0] ]; 515 break; 516 517 case 2: 518 $atCache = & $this->cache[ $args[0] ][ $args[1] ]; 519 break; 520 521 case 3: 522 $atCache = & $this->cache[ $args[0] ][ $args[1] ][ $args[2] ]; 523 break; 524 525 default: 526 return false; 527 } 528 529 $atCache->dbRemove = true; 530 unset($atCache->unserialized); 531 unset($atCache->value); 532 533 return true; 534 } 535 536 537 /** 538 * Delete an array of values. 539 * 540 * @param array Array of parameters for {@link delete()} 541 */ 542 function delete_array( $array ) 543 { 544 foreach( $array as $lDel ) 545 { 546 call_user_func_array( array( & $this, 'delete' ), $lDel ); 547 } 548 } 549 550 551 /** 552 * Delete values for {@link $_defaults default settings} in DB. 553 * 554 * This will use the default settings on the next {@link get()} 555 * again. 556 * 557 * @return boolean true, if settings have been updated; false otherwise 558 */ 559 function restore_defaults() 560 { 561 $this->delete_array( array_keys( $this->_defaults ) ); 562 563 return $this->dbupdate(); 564 } 565 566 567 /** 568 * Commit changed settings to DB. 569 * 570 * @return boolean true, if settings have been updated; false otherwise 571 */ 572 function dbupdate() 573 { 574 if( empty($this->cache) ) 575 { 576 return false; 577 } 578 579 global $DB; 580 581 $query_insert = array(); 582 $query_where_delete = array(); 583 584 switch( $this->count_col_key_names ) 585 { 586 case 1: 587 foreach( $this->cache as $key => $value ) 588 { 589 if( $value === NULL ) 590 { // Remembered as not existing 591 continue; 592 } 593 if( ! empty($value->dbRemove) ) 594 { 595 $query_where_delete[] = "{$this->col_key_names[0]} = '$key'"; 596 unset( $this->cache[$key] ); 597 } 598 elseif( isset($value->dbUptodate) && !$value->dbUptodate ) 599 { 600 $value = $value->value; 601 if( is_array( $value ) || is_object( $value ) ) 602 { 603 $value = serialize($value); 604 } 605 $query_insert[] = "('$key', '".$DB->escape( $value )."')"; 606 $this->cache[$key]->dbUptodate = true; 607 } 608 } 609 break; 610 611 case 2: 612 foreach( $this->cache as $key => $value ) 613 { 614 foreach( $value as $key2 => $value2 ) 615 { 616 if( $value2 === NULL ) 617 { // Remembered as not existing 618 continue; 619 } 620 if( ! empty($value2->dbRemove) ) 621 { 622 $query_where_delete[] = "{$this->col_key_names[0]} = '$key' AND {$this->col_key_names[1]} = '$key2'"; 623 unset( $this->cache[$key][$key2] ); 624 } 625 elseif( isset($value2->dbUptodate) && !$value2->dbUptodate ) 626 { 627 $value2 = $value2->value; 628 if( is_array( $value2 ) || is_object( $value2 ) ) 629 { 630 $value2 = serialize($value2); 631 } 632 $query_insert[] = "('$key', '$key2', '".$DB->escape( $value2 )."')"; 633 $this->cache[$key][$key2]->dbUptodate = true; 634 } 635 } 636 } 637 break; 638 639 case 3: 640 foreach( $this->cache as $key => $value ) 641 { 642 foreach( $value as $key2 => $value2 ) 643 { 644 foreach( $value2 as $key3 => $value3 ) 645 { 646 if( $value3 === NULL ) 647 { // Remembered as not existing 648 continue; 649 } 650 if( ! empty($value3->dbRemove) ) 651 { 652 $query_where_delete[] = "{$this->col_key_names[0]} = '$key' AND {$this->col_key_names[1]} = '$key2' AND {$this->col_key_names[2]} = '$key3'"; 653 unset( $this->cache[$key][$key2][$key3] ); 654 } 655 elseif( isset($value3->dbUptodate) && !$value3->dbUptodate ) 656 { 657 $value3 = $value3->value; 658 if( is_array($value3) || is_object($value3) ) 659 { 660 $value3 = serialize($value3); 661 } 662 $query_insert[] = "('$key', '$key2', '$key3', '".$DB->escape( $value3 )."')"; 663 $this->cache[$key][$key2][$key3]->dbUptodate = true; 664 } 665 } 666 } 667 } 668 break; 669 670 default: 671 return false; 672 } 673 674 675 $r = false; 676 677 if( ! empty($query_where_delete) ) 678 { 679 $query = 'DELETE FROM '.$this->db_table_name." WHERE\n(".implode( ")\nOR (", $query_where_delete ).')'; 680 $r = (boolean)$DB->query( $query ); 681 } 682 683 684 if( ! empty($query_insert) ) 685 { 686 $query = 'REPLACE INTO '.$this->db_table_name.' ('.implode( ', ', $this->col_key_names ).', '.$this->col_value_name 687 .') VALUES '.implode(', ', $query_insert); 688 $r = $DB->query( $query ) || $r; 689 } 690 691 return $r; 692 } 693 694 695 /** 696 * Reset cache (includes settings to be written to DB). 697 * 698 * This is useful, to rollback settings that have been made, e.g. when a Plugin 699 * decides that his settings should not get updated. 700 */ 701 function reset() 702 { 703 $this->cache = NULL; 704 $this->all_loaded = false; 705 } 706 707 } 708 709 710 /* 711 * $Log: _abstractsettings.class.php,v $ 712 * Revision 1.1 2007/06/25 11:01:20 fplanque 713 * MODULES (refactored MVC) 714 * 715 * Revision 1.21 2007/04/26 00:10:59 fplanque 716 * (c) 2007 717 * 718 * Revision 1.20 2007/02/06 00:41:52 waltercruz 719 * Changing double quotes to single quotes 720 * 721 * Revision 1.19 2006/12/07 23:13:11 fplanque 722 * @var needs to have only one argument: the variable type 723 * Otherwise, I can't code! 724 * 725 * Revision 1.18 2006/11/24 18:27:25 blueyed 726 * Fixed link to b2evo CVS browsing interface in file docblocks 727 * 728 * Revision 1.17 2006/11/15 21:04:46 blueyed 729 * - Fixed removing setting after delete() and get() (from defaults) (When getting value from default do not reset $dbRemove property) 730 * - Opt: default settings are already unserialized 731 * 732 * Revision 1.16 2006/11/15 20:18:50 blueyed 733 * Fixed AbstractSettings::delete(): unset properties in cache 734 * 735 * Revision 1.15 2006/11/04 01:35:02 blueyed 736 * Fixed unserializing of array() 737 */ 738 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Thu Nov 29 23:58:50 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |