1<?php 2 3if (!class_exists('settingshierarchy',false)){ 4 5require_once('settingslevel.class.php'); 6 7 8class settingshierarchy{ 9 private $_root = null; // root settingslevel of the hierarchy 10 private $_pluginname = null; // the pluginname of the settings we set 11 private $_meta = array(); // the metadata for each setting (from plugin config) array by key=>meta 12 private $_defaults = array(); // the defaults for each settings (from plugin config) array by key=>default 13 private $_values = array(); // the values and protections set by admins in admin pages. array by path => [key => [ prot, value]]; 14 15 private $_lang = null; // to be used for getLang (lang of the _pluginname) 16 private static $_config_lang = null; // to be used if needed (lang of the config plugin) 17 private static $conf_local = null; // local configurations (only for plugins) 18 private static $conf_protected = null; // protected configurations (only for plugins) 19 public static $cache = null; // memcache 20 public static $helper = null; // settingstree for local getLang 21 22 23 function __construct($pluginname,$meta,$defaults,$values){ 24 $this->_pluginname = $pluginname; 25 $this->_meta = $meta; 26 $this->_defaults = $defaults; 27 $this->_values = $values; 28 29 30 } 31 function getLang($key){ 32 return $this->_getLang($key); 33 } 34 function _getLang($key,$config_plugin = false){ 35 $lang = $this->_getLangInited($config_plugin); 36 global $conf; 37 if (!($ret = @$lang[$conf['lang']][$key])){ 38 if (!($ret = @$lang['en'][$key])){ 39 // we need to check, if it's '{setting}_o_{key}' from a plugin setting, and return null if it is, but translation does not exists, to display only the 'key' part of it. 40 if (!preg_match('~^(?:'.implode('|',array_keys($this->_meta)).')_o_(.*)$~',$key,$match)){ 41 if (!$config_plugin && ($ret = $this->_getLang($key,true)) === null){ // check if it a key for config plugin. 42 // Note: if lang keys needs to be html escaped then there is a conceptual problem about msgids... 43 $ret = "{msgid:{$key}}"; // else we need to return the something if we want to display, that the key is missing instead of simply ignore a message... 44 } 45 /** imagine a situation: 46 * function resultMessage($error){ 47 * $message = ''; 48 * if ($error) 49 * $message .= getLang('corruption_warning'); // key missing, should be 'Corruption WARNING!'; 50 * $message .= ' '.sprintf( 51 * getLang('your_data_is_%s_saved'), // key=>value: 'Your data is %s saved!' 52 * ($error ? getLang('not') : ''), // key missing, should be 'not' 53 * ); 54 * if ($error) 55 * $message .= ' '.getLang('backup_your_data'); // key missing, should be 'Make sure you backup your data manually!' 56 * return trim($message); 57 * } 58 * on error: 59 * The user should see if keys where there: 'Corruption WARNING! Your data is not saved! Make sure you backup your data manually!'; 60 * User should at least see: '{msgid:corruption_warning} Your data is {msgid:not} saved! {msgid:backup_your_data}'; 61 * By ignoring missing messages, the user will see: 'Your data is saved!'; 62 */ 63 } 64 else{ 65 if (($ret = $this->_getLang($match[1],$config_plugin)) === "{msgid:{$key}}"); // try to get the 'key' part as localized from the '{setting}_o_{key}' 66 return null; // if there is not localisation for the key, then return null. 67 } 68 } 69 } 70 return $ret; 71 } 72 73 private function _getLangInited($config_plugin = false){ 74 if($config_plugin){ 75 $_lang = &$this->_config_lang; 76 }else{ 77 $_lang = &$this->_lang; 78 } 79 if ($_lang === null){ 80 // set the $_lang as a reference for the lang array we're updating 81 global $conf; 82 $_lang = array(); 83 $type = $config_plugin ? 'lang' : 'settings'; 84 $pluginname = ($config_plugin ? 'config' : $this->_pluginname); 85 $ls = array($conf['lang']); 86 if ($conf['lang'] !== 'en') $ls[] = 'en'; // English is always the fallback. 87 88 foreach ($ls as $l){ // for all language we need 89 $path = DOKU_INC."lib/plugins/{$pluginname}/lang/{$l}/{$type}.php"; 90 if (static::$cache //if caching is enabled 91 && @filemtime($path) <= static::$cache->get("plugin_{$pluginname}_lang_{$l}_{$type}_time") // and cached version is old enough (note: cache is not bound to settingstree: "plugin_{name}_lang_{lang}_type[_time]" is usable by all plugins 92 && $ll = static::$cache->get("plugin_{$pluginname}_lang_{$l}_{$type}") // and cache contains the language array 93 ){ 94 $_lang[$l] = $ll; 95 continue; // use that, no need to include the files. 96 } 97 if (file_exists($path)){ 98 $lang = array(); 99 @include($path); 100 $_lang[$l] = $lang; 101 if (static::$cache){ // update the cache so next we don't need to read filesystem 102 static::$cache->set("plugin_{$pluginname}_lang_{$l}_{$type}",$lang,0); 103 static::$cache->set("plugin_{$pluginname}_lang_{$l}_{$type}_time",filemtime($path),0); 104 } 105 } 106 } 107 } 108 return $_lang; 109 } 110 function getPluginName(){return $this->_pluginname;} 111 function getLevel($folder){ 112 if (!$this->_root) $this->_loadTree(); 113 $path = explode(':',ltrim(strtr($folder,'/',':'),':')); 114 if ($path[0] == '') return $this->_root; 115 return $this->_root->getLevel($path); 116 } 117 118 119 function getFieldConfig(){ 120 $return = array(); 121 foreach ($this->_meta as $key=>$meta){ 122 if (@$meta['_ignore_for_settingstree']) continue; 123 $return[$key] = $meta; 124 } 125 return $return; 126 } 127 128 129 private function _loadTree(){ 130 $this->_root = new settingslevel($this,null,':'); 131 foreach ($this->_values as $path=>$values){ 132 if ($path == ':'){ 133 $this->_root->setValues($values); 134 } 135 else{ 136 $this->_root->addLevel($path,$values); 137 } 138 } 139 } 140 function getValueTree(){ 141 return $this->_root->getValuesRecursive(); 142 } 143 144 function getDefault($key){ return @$this->_defaults[$key]; } 145 function getLocal($key){ return self::_getlocal($key,$this->_pluginname); } 146 function getProtected($key){ return self::_getprotected($key,$this->_pluginname); } 147 function isExtended($key){ return self::_isextended($key,$this->_pluginname); } 148 149 static function _getlocal($key,$pluginname){ 150 if (static::_isextended($key,$pluginname)){ 151 return null; 152 } 153 if (!static::$conf_local){ 154 $conf = array(); 155 require (DOKU_INC."conf/local.php"); 156 if (is_array(!$conf['plugin'])) $conf['plugin'] = array(); // no plugins sub-array 157 static::$conf_local = $conf['plugin']; 158 } 159 return @static::$conf_local[$pluginname][$key]; 160 } 161 static function _getprotected($key,$pluginname){ 162 if (static::_isextended($key,$pluginname)){ 163 return null; 164 } 165 if (!static::$conf_protected){ 166 $conf = array(); 167 require (DOKU_INC."conf/local.protected.php"); 168 if (is_array(!$conf['plugin'])) $conf['plugin'] = array(); // no plugins sub-array 169 static::$conf_protected = $conf['plugin']; 170 } 171 return @static::$conf_protected[$pluginname][$key]; 172 } 173 static function _isextended($key,$pluginname){ 174 global $conf; 175 return !array_key_exists($key,(array)@$conf['plugin'][$pluginname]); 176 } 177 178 function showHierarchyLevelRecursive($level,$key,&$empty){ 179 $ch_empty = true; 180 $chn = $level->getChildren(); 181 if (!empty($chn)){ 182 $chhtml = '<ul>'; 183 foreach ($chn as $ch){ 184 $_chhtml = $this->showHierarchyLevelRecursive($ch,$key,$_empty); 185 if (!$_empty) $chhtml .= $_chhtml; 186 $ch_empty = $ch_empty && $_empty; 187 } 188 $chhtml .= '</ul>'; 189 } 190 $p = $level->isLevelProtected($key); 191 $v = $level->isLevelValue($key); 192 $empty = !$p && !$v && $ch_empty; 193 $lev = "<li data-path='{$level->getPath()}' class='".($empty ? 'empty':'')."'>"; 194 $lev .= "<b class='".($p ? 'protect':'').' '.($v ? 'value':'')."'>" 195 ."{$level->getLevelNameRelative()}</b>"; 196 $lev .= ($p ? "<span class='_p'>".settingshierarchy::$helper->getLang('became_protected').".</span>" : ""); 197 $lev .= ($v ? "<span class='_v'>".settingshierarchy::$helper->getLang('value_set_to')." <code>{$this->format($key,$level->getLevelValue($key))}</code>".($level->isLevelValueIgnored($key) ? " <i class='_i'>".settingshierarchy::$helper->getLang('but_ignored')."</i>" : "").".</span>" : ""); 198 return $lev . ($ch_empty ? "" : $chhtml) ."</li>"; 199 } 200 function showHierarchy($key){ 201 $ret .= '<ul class="settings_hierarchy_history">'; 202 $ret .= "<li class='title'>".sprintf(settingshierarchy::$helper->getLang("settings_for_%s"),$key).'</li>'; 203 if (!$this->isExtended($key)){ 204 $v = $this->getLocal($key) !== null; 205 $p = $this->getProtected($key) !== null; 206 $ret .= "<li><b class='".($p ? 'protect':'').' '.($v ? 'value':'')."'>".settingshierarchy::$helper->getLang("in_config").":</b>"; 207 $ret .= "<span class='_d'>".settingshierarchy::$helper->getLang('default_is')." <code>{$this->format($key,$this->getDefault($key))}</code>.</span>"; 208 $ret .= ($p ? "<span class='_p'>".settingshierarchy::$helper->getLang('became_protected').".</span>" : ""); 209 $ret .= ($v ? "<span class='_v'>".settingshierarchy::$helper->getLang('local_is')." <code>{$this->format($key,$this->getLocal($key))}</code>.</span>" : ""); 210 } 211 else{ 212 $ret .= "<li><b>".settingshierarchy::$helper->getLang("this_is_extended")."</b>"; 213 $ret .= "<span class='_d'>".settingshierarchy::$helper->getLang('default_is')." <code>{$this->format($key,$this->getDefault($key))}</code>.</span>"; 214 } 215 if (!$this->_root) $this->_loadTree(); 216 $roothtml = "<ul>".$this->showHierarchyLevelRecursive($this->_root,$key,$empty)."</ul>"; 217 return $ret. ($empty ? "" : $roothtml)."</li></ul>"; 218 } 219 function format($key,$value){ 220 if ($value === null) return "[".settingshierarchy::$helper->getLang('default_value')."]"; 221 if ($this->_meta[$key][0] == 'onoff'){ 222 return settingshierarchy::$helper->getLang($value ? "on" : "off"); 223 } 224 if ($value === ''){ 225 return "[".settingshierarchy::$helper->getLang('empty_string')."]"; 226 } 227 return $value; 228 } 229 230} 231} // class_exists 232