diff --git a/api/src/Cache.php b/api/src/Cache.php index 33a0e8edbb..7966164c26 100644 --- a/api/src/Cache.php +++ b/api/src/Cache.php @@ -578,7 +578,7 @@ class Cache $db = $GLOBALS['egw']->db ? $GLOBALS['egw']->db : $GLOBALS['egw_setup']->db; try { - if (($rs = $db->select(config::TABLE,'config_value',array( + if (($rs = $db->select(Config::TABLE,'config_value',array( 'config_app' => 'phpgwapi', 'config_name' => $name, ),__LINE__,__FILE__))) diff --git a/api/src/Config.php b/api/src/Config.php new file mode 100755 index 0000000000..6c9243efae --- /dev/null +++ b/api/src/Config.php @@ -0,0 +1,361 @@ + original class Copyright (C) 2000, 2001 Joseph Engo + * @author Ralf Becker + * @version $Id$ + */ + +namespace EGroupware\Api; + +use egw_customfields; +use translation; + +/** + * eGW's application configuration in a centralized location + * + * New config values are stored JSON serialized now instead of PHP serialized before 14.1. + */ +class Config +{ + /** + * Name of the config table + * + */ + const TABLE = 'egw_config'; + /** + * Reference to the global db class + * + * @var Db + */ + static private $db; + /** + * Cache for the config data shared by all instances of this class + * + * @var array + */ + static private $configs; + + /** + * app the particular config class is instanciated for + * + * @var string + */ + private $appname; + /** + * actual config-data of the instanciated class + * + * @deprecated dont use direct + * @var array + */ + public $config_data; + + /** + * Constructor for the old non-static use + * + * @param string $appname + */ + function __construct($appname = '') + { + if (!$appname) + { + $appname = $GLOBALS['egw_info']['flags']['currentapp']; + } + $this->appname = $appname; + } + + /** + * reads the whole repository for $this->appname, appname has to be set via the constructor + * + * You can also use the static config::read($app) method, without instanciating the class. + * + * @return array the whole config-array for that app + */ + function read_repository() + { + $this->config_data = self::read($this->appname); + + //echo __CLASS__.'::'.__METHOD__."() this->appname=$this->appname\n"; _debug_array($this->config_data); + + return $this->config_data; + } + + /** + * updates the whole repository for $this->appname, you have to call read_repository() before (!) + */ + function save_repository() + { + if (is_array($this->config_data)) + { + self::$db->lock(array(config::TABLE)); + foreach($this->config_data as $name => $value) + { + self::save_value($name, $value, $this->appname, false); + } + foreach(self::$configs[$this->appname] as $name => $value) + { + if (!isset($this->config_data[$name])) // has been deleted + { + self::save_value($name, null, $this->appname, false); + //self::$db->delete(config::TABLE,array('config_app'=>$this->appname,'config_name'=>$name),__LINE__,__FILE__); + } + } + self::$db->unlock(); + + if ($this->appname == 'phpgwapi' && method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited + { + $GLOBALS['egw']->invalidate_session_cache(); // in case egw_info is cached in the session (phpgwapi is in egw_info[server]) + } + self::$configs[$this->appname] = $this->config_data; + + Cache::setInstance(__CLASS__, 'configs', self::$configs); + } + } + + /** + * updates or insert a single config-value direct into the database + * + * Can (under recent PHP version) only be used static! + * Use $this->value() or $this->delete_value() together with $this->save_repository() for non-static usage. + * + * @param string $name name of the config-value + * @param mixed $value content, empty or null values are not saved, but deleted + * @param string $app app-name (depreacted to use default of $this->appname set via the constructor!) + * @param boolean $update_cache =true update instance cache and for phpgwapi invalidate session-cache + * @throws Exception\WrongParameter if no $app parameter given for static call + * @return boolean|int true if no change, else number of affected rows + */ + static function save_value($name, $value, $app, $update_cache=true) + { + if (!$app && (!isset($this) || !is_a($this,__CLASS__))) + { + throw new Exception\WrongParameter('$app parameter required for static call of config::save_value($name,$value,$app)!'); + } + //echo "

config::save_value('$name','".print_r($value,True)."','$app')

\n"; + if (!$app || isset($this) && is_a($this,__CLASS__) && $app == $this->appname) + { + $app = $this->appname; + $this->config_data[$name] = $value; + } + if (!isset(self::$configs)) + { + self::init_static(); + } + //echo "

config::save_value('$name','".print_r($value,True)."','$app')

\n"; + if (isset(self::$configs[$app][$name]) && self::$configs[$app][$name] === $value) + { + return True; // no change ==> exit + } + + if (!isset($value) || $value === '') + { + if (isset(self::$configs[$app])) unset(self::$configs[$app][$name]); + self::$db->delete(config::TABLE,array('config_app'=>$app,'config_name'=>$name),__LINE__,__FILE__); + } + else + { + self::$configs[$app][$name] = $value; + if(is_array($value)) $value = json_encode($value); + self::$db->insert(config::TABLE,array('config_value'=>$value),array('config_app'=>$app,'config_name'=>$name),__LINE__,__FILE__); + } + if ($update_cache) + { + if ($app == 'phpgwapi' && method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited + { + $GLOBALS['egw']->invalidate_session_cache(); // in case egw_info is cached in the session (phpgwapi is in egw_info[server]) + } + Cache::setInstance(__CLASS__, 'configs', self::$configs); + } + return self::$db->affected_rows(); + } + + /** + * deletes the whole repository for $this->appname, appname has to be set via the constructor + * + */ + function delete_repository() + { + if (!isset(self::$configs)) + { + self::init_static(); + } + self::$db->delete(config::TABLE,array('config_app' => $this->appname),__LINE__,__FILE__); + + unset(self::$configs[$this->appname]); + Cache::setInstance(__CLASS__, 'configs', self::$configs); + } + + /** + * deletes a single value from the repository, you need to call save_repository after + * + * @param $variable_name string name of the config + */ + function delete_value($variable_name) + { + unset($this->config_data[$variable_name]); + } + + /** + * sets a single value in the repositry, you need to call save_repository after + * + * @param $variable_name string name of the config + * @param $variable_data mixed the content + */ + function value($variable_name,$variable_data) + { + $this->config_data[$variable_name] = $variable_data; + } + + /** + * Reads the configuration for an applications + * + * Does some caching to not read it twice (in the same request) + * + * @param string $app + * @return array + */ + static function read($app) + { + if (!isset(self::$configs)) + { + self::init_static(); + } + return self::$configs[$app]; + } + + /** + * get customfield array of an application + * + * @param string $app + * @param boolean $all_private_too =false should all the private fields be returned too, default no + * @param string $only_type2 =null if given only return fields of type2 == $only_type2 + * @deprecated use egw_customfields::get() + * @return array with customfields + */ + static function get_customfields($app, $all_private_too=false, $only_type2=null) + { + //error_log(__METHOD__."('$app', $all_private_too, $only_type2) deprecated, use egw_customfields::get() in ". function_backtrace()); + return egw_customfields::get($app, $all_private_too, $only_type2); + } + + /** + * get_content_types of using application + * + * @param string $app + * @return array with content-types + */ + static function get_content_types($app) + { + $config = self::read($app); + + return is_array($config['types']) ? $config['types'] : array(); + } + + /** + * Return configuration for all apps, save to be transmitted to browser + * + * You can add further values to the white-list, but keep in mind they are publicly visible (eg. via anon user of sitemgr)!!! + * + * @return array + */ + static public function clientConfigs() + { + static $white_list = array( + 'all' => array('customfields', 'types'), + 'phpgwapi' => array('webserver_url','server_timezone','enforce_ssl','system_charset', + 'checkfornewversion','checkappversions','email_address_format', // admin >> site config + 'site_title','login_logo_file','login_logo_url','login_logo_title','favicon_file', + 'markuntranslated','link_list_thumbnail','enabled_spellcheck','debug_minify', + 'call_link','call_popup', // addressbook + 'hide_birthdays','calview_no_consolidate', 'egw_tutorial_disable'), // calendar + 'projectmanager' => array('hours_per_workday', 'duration_units'), + 'manual' => array('manual_remote_egw_url'), + 'infolog' => array('status'), + 'timesheet' => array('status_labels'), + ); + if (!isset(self::$configs)) + { + self::init_static(); + } + $client_config = array(); + foreach(self::$configs as $app => $config) + { + foreach($config as $name => $value) + { + if (strpos($name, 'pass') !== false) continue; + + if (in_array($name, $white_list['all']) || isset($white_list[$app]) && in_array($name, $white_list[$app])) + { + $client_config[$app][$name] = $value; + } + } + // currently not used, therefore no need to add it + //$client_config[$app]['customfields'] = egw_customfields::get($app); + } + // some things need on client-side which are not direct configs + $client_config['phpgwapi']['max_lang_time'] = translation::max_lang_time(); + + return $client_config; + } + + /** + * Unserialize data from either json_encode or PHP serialize + * + * @param string $str serialized prefs + * @return array + */ + protected static function unserialize($str) + { + // handling of new json-encoded arrays + if ($str[0] == '{' || $str[0] == '[') + { + return json_decode($str, true); + } + // handling of not serialized strings + if ($str[0] != 'a' || $str[1] != ':') + { + return $str; + } + // handling of old PHP serialized config values + $data = php_safe_unserialize($str); + if($data === false) + { + // manually retrieve the string lengths of the serialized array if unserialize failed (iso / utf-8 conversation) + $data = php_safe_unserialize(preg_replace_callback('!s:(\d+):"(.*?)";!s', function($matches) + { + return 's:'.mb_strlen($matches[2],'8bit').':"'.$matches[2].'";'; + }, $str)); + } + // returning original string, if unserialize failed, eg. for "a:hello" + return $data === false ? $str : $data; + } + + /** + * Initialise class: reference to db and self::$configs cache + */ + public static function init_static() + { + // we use a reference here (no clone), as we no longer use egw_db::row() or egw_db::next_record()! + if (isset($GLOBALS['egw_setup']) && is_a($GLOBALS['egw_setup']->db, 'egw_db')) + { + self::$db = $GLOBALS['egw_setup']->db; + } + else + { + self::$db = $GLOBALS['egw']->db; + } + // if item is not cached or cache is not looking alright --> query config from database + if (!(self::$configs = Cache::getInstance(__CLASS__, 'configs')) || !is_array(self::$configs['phpgwapi'])) + { + self::$configs = array(); + foreach(self::$db->select(config::TABLE,'*',false,__LINE__,__FILE__) as $row) + { + self::$configs[$row['config_app']][$row['config_name']] = self::unserialize($row['config_value']); + //error_log(__METHOD__."() configs[$row[config_app]][$row[config_name]]=".array2string(self::$configs[$row['config_app']][$row['config_name']])); + } + Cache::setInstance(__CLASS__, 'configs', self::$configs); + } + } +} diff --git a/api/src/Db/Backup.php b/api/src/Db/Backup.php index 16953bd6b4..ca02a970df 100644 --- a/api/src/Db/Backup.php +++ b/api/src/Db/Backup.php @@ -15,7 +15,6 @@ namespace EGroupware\Api\Db; use EGroupware\Api; -use config; use translation; use html; @@ -316,11 +315,11 @@ class Backup */ function saveConfig($minCount,$backupFiles=null) { - config::save_value('backup_mincount',$this->backup_mincount=(int)$minCount,'phpgwapi'); + Config::save_value('backup_mincount',$this->backup_mincount=(int)$minCount,'phpgwapi'); if (!is_null($backupFiles)) { - config::save_value('backup_files',$this->backup_files=(boolean)$backupFiles,'phpgwapi'); + Config::save_value('backup_files',$this->backup_files=(boolean)$backupFiles,'phpgwapi'); } } @@ -429,7 +428,7 @@ class Backup if ($convert_to_system_charset) // store the changed charset { - $this->db->insert(config::TABLE, array( + $this->db->insert(Config::TABLE, array( 'config_value' => $this->schema_proc->system_charset, ),array( 'config_app' => 'phpgwapi', diff --git a/api/src/Vfs.php b/api/src/Vfs.php index 8a4b32f21a..ed8b704b65 100644 --- a/api/src/Vfs.php +++ b/api/src/Vfs.php @@ -16,7 +16,6 @@ namespace EGroupware\Api; // explicitly import old phpgwapi classes used: use mime_magic; use common; -use config; use html; use translation; use HTTP_WebDAV_Server; @@ -324,7 +323,7 @@ class Vfs extends Vfs\StreamWrapper if (!isset($GLOBALS['egw_info']['server']['vfs_fstab'])) // happens eg. in setup { - $api_config = config::read('phpgwapi'); + $api_config = Config::read('phpgwapi'); if (isset($api_config['vfs_fstab']) && is_array($api_config['vfs_fstab'])) { self::$fstab = $api_config['vfs_fstab']; @@ -370,7 +369,7 @@ class Vfs extends Vfs\StreamWrapper if ($persitent_mount) { - config::save_value('vfs_fstab',self::$fstab,'phpgwapi'); + Config::save_value('vfs_fstab',self::$fstab,'phpgwapi'); $GLOBALS['egw_info']['server']['vfs_fstab'] = self::$fstab; // invalidate session cache if (method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited @@ -401,7 +400,7 @@ class Vfs extends Vfs\StreamWrapper } unset(self::$fstab[$path]); - config::save_value('vfs_fstab',self::$fstab,'phpgwapi'); + Config::save_value('vfs_fstab',self::$fstab,'phpgwapi'); $GLOBALS['egw_info']['server']['vfs_fstab'] = self::$fstab; // invalidate session cache if (method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited diff --git a/api/src/Vfs/Sqlfs/StreamWrapper.php b/api/src/Vfs/Sqlfs/StreamWrapper.php index 338f4c8ac2..b20f48b795 100644 --- a/api/src/Vfs/Sqlfs/StreamWrapper.php +++ b/api/src/Vfs/Sqlfs/StreamWrapper.php @@ -18,7 +18,6 @@ use EGroupware\Api; // explicitly import old phpgwapi classes used: use mime_magic; -use config; /** @@ -1185,7 +1184,7 @@ class StreamWrapper implements Vfs\StreamWrapperIface } $GLOBALS['egw_info']['server']['max_subquery_depth'] = --$max_subquery_depth; error_log(__METHOD__."() decremented max_subquery_depth to $max_subquery_depth"); - config::save_value('max_subquery_depth', $max_subquery_depth, 'phpgwapi'); + Api\Config::save_value('max_subquery_depth', $max_subquery_depth, 'phpgwapi'); if (method_exists($GLOBALS['egw'],'invalidate_session_cache')) $GLOBALS['egw']->invalidate_session_cache(); return self::url_stat($url, $flags, $eacl_access); } diff --git a/phpgwapi/inc/class.config.inc.php b/phpgwapi/inc/class.config.inc.php index b92be9e5de..74450002c9 100755 --- a/phpgwapi/inc/class.config.inc.php +++ b/phpgwapi/inc/class.config.inc.php @@ -8,349 +8,9 @@ * @version $Id$ */ +use EGroupware\Api; + /** - * eGW's application configuration in a centralized location - * - * New config values are stored JSON serialized now instead of PHP serialized before 14.1. + * @deprecated use Api\Config */ -class config -{ - /** - * Name of the config table - * - */ - const TABLE = 'egw_config'; - /** - * Reference to the global db class - * - * @var egw_db - */ - static private $db; - /** - * Cache for the config data shared by all instances of this class - * - * @var array - */ - static private $configs; - - /** - * app the particular config class is instanciated for - * - * @var string - */ - private $appname; - /** - * actual config-data of the instanciated class - * - * @deprecated dont use direct - * @var array - */ - public $config_data; - - /** - * Constructor for the old non-static use - * - * @param string $appname - */ - function __construct($appname = '') - { - if (!$appname) - { - $appname = $GLOBALS['egw_info']['flags']['currentapp']; - } - $this->appname = $appname; - } - - /** - * reads the whole repository for $this->appname, appname has to be set via the constructor - * - * You can also use the static config::read($app) method, without instanciating the class. - * - * @return array the whole config-array for that app - */ - function read_repository() - { - $this->config_data = self::read($this->appname); - - //echo __CLASS__.'::'.__METHOD__."() this->appname=$this->appname\n"; _debug_array($this->config_data); - - return $this->config_data; - } - - /** - * updates the whole repository for $this->appname, you have to call read_repository() before (!) - */ - function save_repository() - { - if (is_array($this->config_data)) - { - self::$db->lock(array(config::TABLE)); - foreach($this->config_data as $name => $value) - { - self::save_value($name, $value, $this->appname, false); - } - foreach(self::$configs[$this->appname] as $name => $value) - { - if (!isset($this->config_data[$name])) // has been deleted - { - self::save_value($name, null, $this->appname, false); - //self::$db->delete(config::TABLE,array('config_app'=>$this->appname,'config_name'=>$name),__LINE__,__FILE__); - } - } - self::$db->unlock(); - - if ($this->appname == 'phpgwapi' && method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited - { - $GLOBALS['egw']->invalidate_session_cache(); // in case egw_info is cached in the session (phpgwapi is in egw_info[server]) - } - self::$configs[$this->appname] = $this->config_data; - - egw_cache::setInstance(__CLASS__, 'configs', self::$configs); - } - } - - /** - * updates or insert a single config-value direct into the database - * - * Can (under recent PHP version) only be used static! - * Use $this->value() or $this->delete_value() together with $this->save_repository() for non-static usage. - * - * @param string $name name of the config-value - * @param mixed $value content, empty or null values are not saved, but deleted - * @param string $app app-name (depreacted to use default of $this->appname set via the constructor!) - * @param boolean $update_cache=true update instance cache and for phpgwapi invalidate session-cache - * @throws egw_exception_wrong_parameter if no $app parameter given for static call - * @return boolean|int true if no change, else number of affected rows - */ - static function save_value($name, $value, $app, $update_cache=true) - { - if (!$app && (!isset($this) || !is_a($this,__CLASS__))) - { - throw new egw_exception_wrong_parameter('$app parameter required for static call of config::save_value($name,$value,$app)!'); - } - //echo "

config::save_value('$name','".print_r($value,True)."','$app')

\n"; - if (!$app || isset($this) && is_a($this,__CLASS__) && $app == $this->appname) - { - $app = $this->appname; - $this->config_data[$name] = $value; - } - if (!isset(self::$configs)) - { - self::init_static(); - } - //echo "

config::save_value('$name','".print_r($value,True)."','$app')

\n"; - if (isset(self::$configs[$app][$name]) && self::$configs[$app][$name] === $value) - { - return True; // no change ==> exit - } - - if (!isset($value) || $value === '') - { - if (isset(self::$configs[$app])) unset(self::$configs[$app][$name]); - self::$db->delete(config::TABLE,array('config_app'=>$app,'config_name'=>$name),__LINE__,__FILE__); - } - else - { - self::$configs[$app][$name] = $value; - if(is_array($value)) $value = json_encode($value); - self::$db->insert(config::TABLE,array('config_value'=>$value),array('config_app'=>$app,'config_name'=>$name),__LINE__,__FILE__); - } - if ($update_cache) - { - if ($app == 'phpgwapi' && method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited - { - $GLOBALS['egw']->invalidate_session_cache(); // in case egw_info is cached in the session (phpgwapi is in egw_info[server]) - } - egw_cache::setInstance(__CLASS__, 'configs', self::$configs); - } - return self::$db->affected_rows(); - } - - /** - * deletes the whole repository for $this->appname, appname has to be set via the constructor - * - */ - function delete_repository() - { - if (!isset(self::$configs)) - { - self::init_static(); - } - self::$db->delete(config::TABLE,array('config_app' => $this->appname),__LINE__,__FILE__); - - unset(self::$configs[$this->appname]); - egw_cache::setInstance(__CLASS__, 'configs', self::$configs); - } - - /** - * deletes a single value from the repository, you need to call save_repository after - * - * @param $variable_name string name of the config - */ - function delete_value($variable_name) - { - unset($this->config_data[$variable_name]); - } - - /** - * sets a single value in the repositry, you need to call save_repository after - * - * @param $variable_name string name of the config - * @param $variable_data mixed the content - */ - function value($variable_name,$variable_data) - { - $this->config_data[$variable_name] = $variable_data; - } - - /** - * Reads the configuration for an applications - * - * Does some caching to not read it twice (in the same request) - * - * @param string $app - * @return array - */ - static function read($app) - { - if (!isset(self::$configs)) - { - self::init_static(); - } - return self::$configs[$app]; - } - - /** - * get customfield array of an application - * - * @param string $app - * @param boolean $all_private_too=false should all the private fields be returned too, default no - * @param string $only_type2=null if given only return fields of type2 == $only_type2 - * @deprecated use egw_customfields::get() - * @return array with customfields - */ - static function get_customfields($app, $all_private_too=false, $only_type2=null) - { - //error_log(__METHOD__."('$app', $all_private_too, $only_type2) deprecated, use egw_customfields::get() in ". function_backtrace()); - return egw_customfields::get($app, $all_private_too, $only_type2); - } - - /** - * get_content_types of using application - * - * @param string $app - * @return array with content-types - */ - static function get_content_types($app) - { - $config = self::read($app); - - return is_array($config['types']) ? $config['types'] : array(); - } - - /** - * Return configuration for all apps, save to be transmitted to browser - * - * You can add further values to the white-list, but keep in mind they are publicly visible (eg. via anon user of sitemgr)!!! - * - * @return array - */ - static public function clientConfigs() - { - static $white_list = array( - 'all' => array('customfields', 'types'), - 'phpgwapi' => array('webserver_url','server_timezone','enforce_ssl','system_charset', - 'checkfornewversion','checkappversions','email_address_format', // admin >> site config - 'site_title','login_logo_file','login_logo_url','login_logo_title','favicon_file', - 'markuntranslated','link_list_thumbnail','enabled_spellcheck','debug_minify', - 'call_link','call_popup', // addressbook - 'hide_birthdays','calview_no_consolidate', 'egw_tutorial_disable'), // calendar - 'projectmanager' => array('hours_per_workday', 'duration_units'), - 'manual' => array('manual_remote_egw_url'), - 'infolog' => array('status'), - 'timesheet' => array('status_labels'), - ); - if (!isset(self::$configs)) - { - self::init_static(); - } - $client_config = array(); - foreach(self::$configs as $app => $config) - { - foreach($config as $name => $value) - { - if (strpos($name, 'pass') !== false) continue; - - if (in_array($name, $white_list['all']) || isset($white_list[$app]) && in_array($name, $white_list[$app])) - { - $client_config[$app][$name] = $value; - } - } - // currently not used, therefore no need to add it - //$client_config[$app]['customfields'] = egw_customfields::get($app); - } - // some things need on client-side which are not direct configs - $client_config['phpgwapi']['max_lang_time'] = translation::max_lang_time(); - - return $client_config; - } - - /** - * Unserialize data from either json_encode or PHP serialize - * - * @param string $str serialized prefs - * @return array - */ - protected static function unserialize($str) - { - // handling of new json-encoded arrays - if ($str[0] == '{' || $str[0] == '[') - { - return json_decode($str, true); - } - // handling of not serialized strings - if ($str[0] != 'a' || $str[1] != ':') - { - return $str; - } - // handling of old PHP serialized config values - $data = php_safe_unserialize($str); - if($data === false) - { - // manually retrieve the string lengths of the serialized array if unserialize failed (iso / utf-8 conversation) - $data = php_safe_unserialize(preg_replace_callback('!s:(\d+):"(.*?)";!s', function($matches) - { - return 's:'.mb_strlen($matches[2],'8bit').':"'.$matches[2].'";'; - }, $str)); - } - // returning original string, if unserialize failed, eg. for "a:hello" - return $data === false ? $str : $data; - } - - /** - * Initialise class: reference to db and self::$configs cache - */ - public static function init_static() - { - // we use a reference here (no clone), as we no longer use egw_db::row() or egw_db::next_record()! - if (isset($GLOBALS['egw_setup']) && is_a($GLOBALS['egw_setup']->db, 'egw_db')) - { - self::$db = $GLOBALS['egw_setup']->db; - } - else - { - self::$db = $GLOBALS['egw']->db; - } - // if item is not cached or cache is not looking alright --> query config from database - if (!(self::$configs = egw_cache::getInstance(__CLASS__, 'configs')) || !is_array(self::$configs['phpgwapi'])) - { - self::$configs = array(); - foreach(self::$db->select(config::TABLE,'*',false,__LINE__,__FILE__) as $row) - { - self::$configs[$row['config_app']][$row['config_name']] = self::unserialize($row['config_value']); - //error_log(__METHOD__."() configs[$row[config_app]][$row[config_name]]=".array2string(self::$configs[$row['config_app']][$row['config_name']])); - } - egw_cache::setInstance(__CLASS__, 'configs', self::$configs); - } - } -} +class config extends Api\Config {} \ No newline at end of file