Source for file _abstractsettings.class.php
Documentation is available at _abstractsettings.class.php
* This file implements the AbstractSettings class designed to handle any kind of settings.
* This file is part of the evoCore framework - {@link http://evocore.net/}
* See also {@link http://sourceforge.net/projects/evocms/}.
* @copyright (c)2003-2010 by Francois PLANQUE - {@link http://fplanque.net/}
* Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
* {@internal License choice
* - If you have received this file as part of a package, please find the license.txt file in
* the same folder or the closest folder above for complete license terms.
* - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
* then you must choose one of the following licenses before using the file:
* - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
* - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
* {@internal Open Source relicensing agreement:
* Daniel HAHLER grants Francois PLANQUE the right to license
* Daniel HAHLER's contributions to this file and the b2evolution project
* under any OSI approved OSS license (http://www.opensource.org/licenses/).
* {@internal Below is a list of authors who have contributed to design/coding of this file: }}
* @author blueyed: Daniel HAHLER
* @author fplanque: Francois PLANQUE
* @version $Id: _abstractsettings.class.php,v 1.9 2010/02/08 17:53:55 efy-yury Exp $
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
// DEBUG: (Turn switch on or off to log debug info for specified category)
$GLOBALS['debug_settings'] =
false;
* Class to handle settings in an abstract manner (to get used with either 1, 2 or 3 DB column keys).
* Arrays and Objects automatically get serialized and unserialized
* (in {@link AbstractSettings::get()} and {@link AbstractSettings::dbupdate()}).
* Note: I've evaluated splitting this into single classes for performance reasons, but only
* get() is relevant performance-wise and we could now only get rid of the switch() therein,
* which is not sufficient to split it into *_base + _X classes. (blueyed, 2006-08)
* @see UserSettings, GeneralSettings, PluginSettings, CollectionSettings
* The DB table which stores the settings.
* Array with DB column key names.
* DB column name for the value.
* The number of column keys to cache by. This are the first x keys of
* {@link $col_key_names}. 0 means 'load all'.
* false, if settings could not be loaded or NULL if not initialized.
* Do we have loaded everything?
* Maps last colkeyname to some default setting that will be used by
* {@link get()} if no value was defined (and it is set as a default).
* @param string The name of the DB table with the settings stored.
* @param array List of names for the DB columns keys that reference a value.
* @param string The name of the DB column that holds the value.
* @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'.
function AbstractSettings( $db_table_name, $col_key_names, $col_value_name, $cache_by_col_keys =
0 )
* internal counter for the number of column keys
if( $this->count_col_key_names >
3 ||
$this->count_col_key_names <
1 )
* Load all settings, disregarding the derived classes setting of
* {@link $cache_by_col_keys} - useful if you know that you want to get
* all user settings for example.
* Loads the settings. Not meant to be called directly, but gets called
* @param string First column key
* @param string Second column key
* @param string Third column key
* @return boolean always true
function _load( $arg1 =
NULL, $arg2 =
NULL, $arg3 =
NULL )
* The where clause - gets filled when {@link $cache_by_col_keys} is used.
{ // The number of column keys to cache by is > 0
$testCache =
$this->cache;
$args =
array( $arg1, $arg2, $arg3 );
||
! isset
( $testCache[$args[$i]] )
||
! ($testCache =
& $testCache[$args[$i]]) )
{ // We cache everything at once!
$result =
$DB->get_results( '
?
' WHERE '.
implode( ' AND ', $whereList )
switch( $this->count_col_key_names )
{ // Remember that we've tried it
$this->cache[ $arg1 ] =
NULL;
else foreach( $result as $loop_row )
{ // Remember that we've tried it
$this->cache[ $arg1 ][ $arg2 ] =
NULL;
else foreach( $result as $loop_row )
{ // Remember that we've tried it
$this->cache[ $arg1 ][ $arg2 ][ $arg3 ] =
NULL;
else foreach( $result as $loop_row )
* Get a setting from the DB settings table.
* @param string First column key
* @param string Second column key
* @param string Third column key
* @return string|false|NULLvalue as string on success; NULL if not found; false in case of error
function get( $col_key1, $col_key2 =
NULL, $col_key3 =
NULL )
$Timer->resume('abstractsettings_'.
$this_class.
'_get', false );
switch( $this->count_col_key_names )
$this->_load( $col_key1 );
if( !empty($this->cache[ $col_key1 ]->unserialized) )
{ // The value has been unserialized before:
$r =
$this->cache[ $col_key1 ]->value;
elseif( isset
($this->cache[ $col_key1 ]->value) )
{ // First attempt to access the value, we need to unserialize it:
// Try to unserialize setting (once) - this is as fast as checking an array of values that should get unserialized
$this->cache[ $col_key1 ]->value =
$r;
$r =
$this->cache[ $col_key1 ]->value;
$this->cache[ $col_key1 ]->unserialized =
true;
{ // The value is not in the cache, we use the default:
$this->cache[ $col_key1 ]->value =
$r; // remember in cache
$this->cache[ $col_key1 ]->dbUptodate =
true;
$this->cache[ $col_key1 ]->unserialized =
true;
$from_default =
true; // for debug
$this->_load( $col_key1, $col_key2 );
if( isset
($this->cache[ $col_key1 ][ $col_key2 ]->unserialized) )
$r =
$this->cache[ $col_key1 ][ $col_key2 ]->value;
elseif( isset
($this->cache[ $col_key1 ][ $col_key2 ]->value) )
// Try to unserialize setting (once) - this is as fast as checking an array of values that should get unserialized
if( ($r =
@unserialize($this->cache[ $col_key1 ][ $col_key2 ]->value)) !==
false )
$this->cache[ $col_key1 ][ $col_key2 ]->value =
$r;
$r =
$this->cache[ $col_key1 ][ $col_key2 ]->value;
$this->cache[ $col_key1 ][ $col_key2 ]->unserialized =
true;
$this->cache[ $col_key1 ][ $col_key2 ]->value =
$r; // remember in cache
$this->cache[ $col_key1 ][ $col_key2 ]->dbUptodate =
true;
$this->cache[ $col_key1 ][ $col_key2 ]->unserialized =
true;
$from_default =
true; // for debug
$this->_load( $col_key1, $col_key2, $col_key3 );
if( isset
($this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->unserialized) )
$r =
$this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->value;
elseif( isset
($this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->value) )
// Try to unserialize setting (once) - this is as fast as checking an array of values that should get unserialized
if( ($r =
@unserialize($this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->value)) !==
false )
$this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->value =
$r;
$r =
$this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->value;
$this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->unserialized =
true;
$this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->value =
$r; // remember in cache
$this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->dbUptodate =
true;
$this->cache[ $col_key1 ][ $col_key2 ][ $col_key3 ]->unserialized =
true;
$from_default =
true; // for debug
$Debuglog->add( $this_class.
'::get( '.
$col_key1.
'/'.
$col_key2.
'/'.
$col_key3.
' ): '
.
( isset
($from_default) ?
'[DEFAULT]: ' :
'' )
$Timer->pause('abstractsettings_'.
$this_class.
'_get', false );
* Get the default for the last key of {@link $col_key_names}
* @param string The last column key
* @return NULL|mixedNULL if no default is set, otherwise the value (should be string).
* Only set the first variable (passed by reference) if we could retrieve a
* @param mixed variable to set maybe (by reference)
* @param string the values for the column keys (depends on $this->col_key_names
* and must match its count and order)
* @return boolean true on success (variable was set), false if not
if( $result !==
NULL &&
$result !==
false )
{ // No error and value retrieved
* Temporarily sets a setting ({@link dbupdate()} writes it to DB).
* @param string $args,... the values for the {@link $col_key_names column keys}
* and {@link $col_value_name column value}. Must match order and count!
* @return boolean true, if the value has been set, false if it has not changed.
switch( $this->count_col_key_names )
$atCache =
& $this->cache[ $args[0] ];
$atCache =
& $this->cache[ $args[0] ][ $args[1] ];
$atCache =
& $this->cache[ $args[0] ][ $args[1] ][ $args[2] ];
$atCache->dbRemove =
false;
if( isset
($atCache->value) )
if( $atCache->value ==
$value )
$Debuglog->add( $debugMsg.
' Already set to the same value.', 'settings' );
$atCache->value =
$value;
$atCache->dbUptodate =
false;
$atCache->unserialized =
false; // We haven't tried to unserialize the value yet
$Debuglog->add( $debugMsg.
' SET!', 'settings' );
* Set an array of values.
* @param array Array of parameters for {@link set()}
foreach( $array as $lSet )
* @param array List of {@link $col_key_names}
switch( $this->count_col_key_names )
$atCache =
& $this->cache[ $args[0] ];
$atCache =
& $this->cache[ $args[0] ][ $args[1] ];
$atCache =
& $this->cache[ $args[0] ][ $args[1] ][ $args[2] ];
$atCache->dbRemove =
true;
unset
($atCache->unserialized);
* Delete an array of values.
* @param array Array of parameters for {@link delete()}
foreach( $array as $lDel )
* Delete values for {@link $_defaults default settings} in DB.
* This will use the default settings on the next {@link get()}
* @return boolean true, if settings have been updated; false otherwise
* Commit changed settings to DB.
* @return boolean true, if settings have been updated; false otherwise
if( empty($this->cache) )
$query_where_delete =
array();
switch( $this->count_col_key_names )
foreach( $this->cache as $key =>
$value )
{ // Remembered as not existing
if( ! empty($value->dbRemove) )
$query_where_delete[] =
"{
$this->col_key_names[0]} = '$key'";
unset
( $this->cache[$key] );
elseif( isset
($value->dbUptodate) &&
!$value->dbUptodate )
$query_insert[] =
"('$key', '".
$DB->escape( $value ).
"')";
$this->cache[$key]->dbUptodate =
true;
foreach( $this->cache as $key =>
$value )
foreach( $value as $key2 =>
$value2 )
{ // Remembered as not existing
if( ! empty($value2->dbRemove) )
$query_where_delete[] =
"{
$this->col_key_names[0]} = '
$key' AND {
$this->col_key_names[1]} = '
$key2'
";
unset
( $this->cache[$key][$key2] );
elseif( isset
($value2->dbUptodate) &&
!$value2->dbUptodate )
$value2 =
$value2->value;
$query_insert[] =
"('$key', '$key2', '".
$DB->escape( $value2 ).
"')";
$this->cache[$key][$key2]->dbUptodate =
true;
foreach( $this->cache as $key =>
$value )
foreach( $value as $key2 =>
$value2 )
foreach( $value2 as $key3 =>
$value3 )
{ // Remembered as not existing
if( ! empty($value3->dbRemove) )
$query_where_delete[] =
"{
$this->col_key_names[0]} = '
$key' AND {
$this->col_key_names[1]} = '
$key2' AND {
$this->col_key_names[2]} = '
$key3'
";
unset
( $this->cache[$key][$key2][$key3] );
elseif( isset
($value3->dbUptodate) &&
!$value3->dbUptodate )
$value3 =
$value3->value;
$query_insert[] =
"('$key', '$key2', '$key3', '".
$DB->escape( $value3 ).
"')";
$this->cache[$key][$key2][$key3]->dbUptodate =
true;
if( ! empty($query_where_delete) )
$query =
'DELETE FROM '.
$this->db_table_name.
" WHERE\n(".
implode( ")\nOR (", $query_where_delete ).
')';
$r = (boolean)
$DB->query( $query );
if( ! empty($query_insert) )
.
') VALUES '.
implode(', ', $query_insert);
$r =
$DB->query( $query ) ||
$r;
* Reset cache (includes settings to be written to DB).
* This is useful, to rollback settings that have been made, e.g. when a Plugin
* decides that his settings should not get updated.
* Get a param from Request and save it to Settings, or default to previously saved user setting.
* If the setting was not set before (and there's no default given that gets returned), $default gets used.
* @param string Request param name
* @param string setting name. Make sure this is unique!
* @param string Force value type to one of:
* - string (strips (HTML-)Tags, trims whitespace)
* - '/^...$/' check regexp pattern match (string)
* - boolean (will force type to boolean, but you can't use 'true' as a default since it has special meaning. There is no real reason to pass booleans on a URL though. Passing 0 and 1 as integers seems to be best practice).
* Value type will be forced only if resulting value (probably from default then) is !== NULL
* @param mixed Default value or TRUE
* @param boolean Do we need to memorize this to regenerate the URL for this page?
* @param boolean Override if variable already set
* @return NULL|mixedNULL, if neither a param was given nor knows about it.
function param_Request( $param_name, $set_name, $type =
'', $default =
'', $memorize =
false, $override =
false ) // we do not force setting it..
$value =
param( $param_name, $type, NULL, $memorize, $override, false ); // we pass NULL here, to see if it got set at all
$this->set( $set_name, $value );
{ // get the value from user settings
$value =
$this->get($set_name);
{ // it's not saved yet and there's not default defined ($_defaults)
* $Log: _abstractsettings.class.php,v $
* Revision 1.9 2010/02/08 17:53:55 efy-yury
* Revision 1.8 2010/01/22 08:39:02 sam2kb
* Fixied warning: call_user_func_array() expects parameter 2 to be array
* Revision 1.7 2009/11/30 00:22:05 fplanque
* show more timers in view of block caching
* Revision 1.6 2009/10/08 20:05:52 efy-maxim
* Modular/Pluggable Permissions
* Revision 1.5 2009/03/08 23:57:45 fplanque
* Revision 1.4 2008/01/21 09:35:34 fplanque
* Revision 1.3 2007/11/28 16:57:50 fplanque
* bugfix when trying to access a serialized value rigth after setting it
* Revision 1.2 2007/11/28 16:38:20 fplanque
* Revision 1.1 2007/06/25 11:01:20 fplanque
* MODULES (refactored MVC)
* Revision 1.21 2007/04/26 00:10:59 fplanque
* Revision 1.20 2007/02/06 00:41:52 waltercruz
* Changing double quotes to single quotes
* Revision 1.19 2006/12/07 23:13:11 fplanque
* @var needs to have only one argument: the variable type
* Otherwise, I can't code!
* Revision 1.18 2006/11/24 18:27:25 blueyed
* Fixed link to b2evo CVS browsing interface in file docblocks
* Revision 1.17 2006/11/15 21:04:46 blueyed
* - Fixed removing setting after delete() and get() (from defaults) (When getting value from default do not reset $dbRemove property)
* - Opt: default settings are already unserialized
* Revision 1.16 2006/11/15 20:18:50 blueyed
* Fixed AbstractSettings::delete(): unset properties in cache
* Revision 1.15 2006/11/04 01:35:02 blueyed
* Fixed unserializing of array()