From 68ed90f748978d2fc941a01ca3081664da0df8e5 Mon Sep 17 00:00:00 2001 From: Alexandre Emsenhuber Date: Mon, 25 Aug 2008 16:46:34 +0000 Subject: [PATCH] Tweaks for SiteConfiguration: * Introduced SiteConfiguration::$siteParamsCallback, a callback function that returns an array of params to define custom parameters to replace and wiki tags so that they can be used at run time (e.g. for CentralAuth or SiteMatrix), can also override SiteConfiguration::siteFromDB(). See the documentation of that variable for further information. Backward compatibility is maintened for paramters passed to SiteConfiguration::get() and similar functions but the vaules returned by the callback function will override them. * Added SiteConfiguration::arrayMerge() for merging arrays, written by Werdna. Warning: as array_merge(), it may change numeric keys, so don't use it for settings having namespaces index in keys. * Removed SiteFromDB hook, deprecated by the callback function * document a bit --- docs/hooks.txt | 5 - includes/SiteConfiguration.php | 269 +++++++++++++++++++++++++-------- 2 files changed, 209 insertions(+), 65 deletions(-) diff --git a/docs/hooks.txt b/docs/hooks.txt index ea460557e2..cb84704119 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -1067,11 +1067,6 @@ $text: Text being shown $title: Title of the custom script/stylesheet page $output: Current OutputPage object -'SiteFromDB': Customise the conversion of a database name to site information in SiteConfiguration -$db: The DB name being converted. -&$site: The site type (out). -&$lang: The "language" (subdomain) - 'SiteNoticeBefore': Before the sitenotice/anonnotice is composed &$siteNotice: HTML returned as the sitenotice Return true to allow the normal method of notice selection/rendering to work, diff --git a/includes/SiteConfiguration.php b/includes/SiteConfiguration.php index 6a1a8637bb..3910bdbf8c 100644 --- a/includes/SiteConfiguration.php +++ b/includes/SiteConfiguration.php @@ -8,19 +8,48 @@ // Hide this pattern from Doxygen, which spazzes out at it /// @cond -if (!defined('SITE_CONFIGURATION')) { -define('SITE_CONFIGURATION', 1); +if( !defined( 'SITE_CONFIGURATION' ) ){ +define( 'SITE_CONFIGURATION', 1 ); /// @endcond /** * This is a class used to hold configuration settings, particularly for multi-wiki sites. - * */ class SiteConfiguration { - var $suffixes = array(); - var $wikis = array(); - var $settings = array(); - var $localVHosts = array(); + + /** + * Array of suffixes, for self::siteFromDB() + */ + public $suffixes = array(); + + /** + * Array of wikis, should be the same as $wgLocalDatabases + */ + public $wikis = array(); + + /** + * The whole array of settings + */ + public $settings = array(); + + /** + * Array of domains that are local and can be handled by the same server + */ + public $localVHosts = array(); + + /** + * A callback function that returns an array with the following keys (all + * optional): + * - suffix: site's suffix + * - lang: site's lang + * - tags: array of wiki tags + * - params: array of parameters to be replaced + * The function will receive the SiteConfiguration instance in the first + * argument and the wiki in the second one. + * if suffix and lang are passed they will be used for the return value of + * self::siteFromDB() and self::$suffixes will be ignored + */ + public $siteParamsCallback = null; /** * Retrieves a configuration setting for a given wiki. @@ -31,72 +60,88 @@ class SiteConfiguration { * @param $wikiTags Array The tags assigned to the wiki. * @return Mixed the value of the setting requested. */ - function get( $settingName, $wiki, $suffix, $params = array(), $wikiTags = array() ) { - if ( array_key_exists( $settingName, $this->settings ) ) { + public function get( $settingName, $wiki, $suffix = null, $params = array(), $wikiTags = array() ) { + $params = $this->mergeParams( $wiki, $suffix, $params, $wikiTags ); + return $this->getSetting( $settingName, $wiki, $params ); + } + + /** + * Really retrieves a configuration setting for a given wiki. + * + * @param $settingName String ID of the setting name to retrieve. + * @param $wiki String Wiki ID of the wiki in question. + * @param $params Array: array of parameters. + * @return Mixed the value of the setting requested. + */ + protected function getSetting( $settingName, $wiki, /*array*/ $params ){ + $retval = null; + if( array_key_exists( $settingName, $this->settings ) ) { $thisSetting =& $this->settings[$settingName]; do { // Do individual wiki settings - if ( array_key_exists( $wiki, $thisSetting ) ) { + if( array_key_exists( $wiki, $thisSetting ) ) { $retval = $thisSetting[$wiki]; break; - } elseif ( array_key_exists( "+$wiki", $thisSetting ) && is_array($thisSetting["+$wiki"]) ) { + } elseif( array_key_exists( "+$wiki", $thisSetting ) && is_array( $thisSetting["+$wiki"] ) ) { $retval = $thisSetting["+$wiki"]; } // Do tag settings - foreach ( $wikiTags as $tag ) { - if ( array_key_exists( $tag, $thisSetting ) ) { - if ( isset($retval) && is_array($retval) && is_array($thisSetting[$tag]) ) { - $retval = array_merge( $retval, $thisSetting[$tag] ); + foreach( $params['tags'] as $tag ) { + if( array_key_exists( $tag, $thisSetting ) ) { + if ( isset( $retval ) && is_array( $retval ) && is_array( $thisSetting[$tag] ) ) { + $retval = self::arrayMerge( $retval, $thisSetting[$tag] ); } else { $retval = $thisSetting[$tag]; } break 2; - } elseif ( array_key_exists( "+$tag", $thisSetting ) && is_array($thisSetting["+$tag"]) ) { - if (!isset($retval)) + } elseif( array_key_exists( "+$tag", $thisSetting ) && is_array($thisSetting["+$tag"]) ) { + if( !isset( $retval ) ) $retval = array(); - $retval = array_merge( $retval, $thisSetting["+$tag"] ); + $retval = self::arrayMerge( $retval, $thisSetting["+$tag"] ); } } - // Do suffix settings - if ( array_key_exists( $suffix, $thisSetting ) ) { - if ( isset($retval) && is_array($retval) && is_array($thisSetting[$suffix]) ) { - $retval = array_merge( $retval, $thisSetting[$suffix] ); - } else { - $retval = $thisSetting[$suffix]; + $suffix = $params['suffix']; + if( !is_null( $suffix ) ) { + if( array_key_exists( $suffix, $thisSetting ) ) { + if ( isset($retval) && is_array($retval) && is_array($thisSetting[$suffix]) ) { + $retval = self::arrayMerge( $retval, $thisSetting[$suffix] ); + } else { + $retval = $thisSetting[$suffix]; + } + break; + } elseif( array_key_exists( "+$suffix", $thisSetting ) && is_array($thisSetting["+$suffix"]) ) { + if (!isset($retval)) + $retval = array(); + $retval = self::arrayMerge( $retval, $thisSetting["+$suffix"] ); } - break; - } elseif ( array_key_exists( "+$suffix", $thisSetting ) && is_array($thisSetting["+$suffix"]) ) { - if (!isset($retval)) - $retval = array(); - $retval = array_merge( $retval, $thisSetting["+$suffix"] ); } // Fall back to default. - if ( array_key_exists( 'default', $thisSetting ) ) { - if ( isset($retval) && is_array($retval) && is_array($thisSetting['default']) ) { - $retval = array_merge( $retval, $thisSetting['default'] ); + if( array_key_exists( 'default', $thisSetting ) ) { + if( is_array( $retval ) && is_array( $thisSetting['default'] ) ) { + $retval = self::arrayMerge( $retval, $thisSetting['default'] ); } else { $retval = $thisSetting['default']; } break; } - $retval = null; } while ( false ); - } else { - $retval = NULL; } - if ( !is_null( $retval ) && count( $params ) ) { - foreach ( $params as $key => $value ) { + if( !is_null( $retval ) && count( $params['params'] ) ) { + foreach ( $params['params'] as $key => $value ) { $retval = $this->doReplace( '$' . $key, $value, $retval ); } } return $retval; } - /** Type-safe string replace; won't do replacements on non-strings */ + /** + * Type-safe string replace; won't do replacements on non-strings + * private? + */ function doReplace( $from, $to, $in ) { if( is_string( $in ) ) { return str_replace( $from, $to, $in ); @@ -118,19 +163,20 @@ class SiteConfiguration { * @param $wikiTags Array The tags assigned to the wiki. * @return Array Array of settings requested. */ - function getAll( $wiki, $suffix, $params, $wikiTags = array() ) { + public function getAll( $wiki, $suffix = null, $params = array(), $wikiTags = array() ) { + $params = $this->mergeParams( $wiki, $suffix, $params, $wikiTags ); $localSettings = array(); - foreach ( $this->settings as $varname => $stuff ) { + foreach( $this->settings as $varname => $stuff ) { $append = false; $var = $varname; if ( substr( $varname, 0, 1 ) == '+' ) { $append = true; $var = substr( $varname, 1 ); } - - $value = $this->get( $varname, $wiki, $suffix, $params, $wikiTags ); - if ( $append && is_array($value) && is_array( $GLOBALS[$var] ) ) - $value = array_merge( $value, $GLOBALS[$var] ); + + $value = $this->getSetting( $varname, $wiki, $params ); + if ( $append && is_array( $value ) && is_array( $GLOBALS[$var] ) ) + $value = self::arrayMerge( $value, $GLOBALS[$var] ); if ( !is_null( $value ) ) { $localSettings[$var] = $value; } @@ -147,7 +193,7 @@ class SiteConfiguration { * @param $wikiTags Array The tags assigned to the wiki. * @return bool The value of the setting requested. */ - function getBool( $setting, $wiki, $suffix, $wikiTags = array() ) { + public function getBool( $setting, $wiki, $suffix = null, $wikiTags = array() ) { return (bool)($this->get( $setting, $wiki, $suffix, array(), $wikiTags ) ); } @@ -169,7 +215,7 @@ class SiteConfiguration { * @param $params Array List of parameters. $.'key' is replaced by $value in all returned data. * @param $wikiTags Array The tags assigned to the wiki. */ - function extractVar( $setting, $wiki, $suffix, &$var, $params, $wikiTags = array() ) { + public function extractVar( $setting, $wiki, $suffix, &$var, $params = array(), $wikiTags = array() ) { $value = $this->get( $setting, $wiki, $suffix, $params, $wikiTags ); if ( !is_null( $value ) ) { $var = $value; @@ -184,13 +230,18 @@ class SiteConfiguration { * @param $params Array List of parameters. $.'key' is replaced by $value in all returned data. * @param $wikiTags Array The tags assigned to the wiki. */ - function extractGlobal( $setting, $wiki, $suffix, $params, $wikiTags = array() ) { - $value = $this->get( $setting, $wiki, $suffix, $params, $wikiTags ); + public function extractGlobal( $setting, $wiki, $suffix = null, $params = array(), $wikiTags = array() ) { + $params = $this->mergeParams( $wiki, $suffix, $params, $wikiTags ); + $this->extractGlobalSetting( $setting, $wiki, $params ); + } + + public function extractGlobalSetting( $setting, $wiki, $params ) { + $value = $this->getSetting( $setting, $wiki, $params ); if ( !is_null( $value ) ) { if (substr($setting,0,1) == '+' && is_array($value)) { $setting = substr($setting,1); if ( is_array($GLOBALS[$setting]) ) { - $GLOBALS[$setting] = array_merge( $GLOBALS[$setting], $value ); + $GLOBALS[$setting] = self::arrayMerge( $GLOBALS[$setting], $value ); } else { $GLOBALS[$setting] = $value; } @@ -207,23 +258,93 @@ class SiteConfiguration { * @param $params Array List of parameters. $.'key' is replaced by $value in all returned data. * @param $wikiTags Array The tags assigned to the wiki. */ - function extractAllGlobals( $wiki, $suffix, $params, $wikiTags = array() ) { + public function extractAllGlobals( $wiki, $suffix = null, $params = array(), $wikiTags = array() ) { + $params = $this->mergeParams( $wiki, $suffix, $params, $wikiTags ); foreach ( $this->settings as $varName => $setting ) { - $this->extractGlobal( $varName, $wiki, $suffix, $params, $wikiTags ); + $this->extractGlobalSetting( $varName, $wiki, $params ); + } + } + + /** + * Return specific settings for $wiki + * See the documentation of self::$siteParamsCallback for more in-depth + * documentation about this function + * + * @param $wiki String + * @return array + */ + protected function getWikiParams( $wiki ){ + static $default = array( + 'suffix' => null, + 'lang' => null, + 'tags' => array(), + 'params' => array(), + ); + + if( !is_callable( $this->siteParamsCallback ) ) + return $default; + + $ret = call_user_func_array( $this->siteParamsCallback, array( $this, $wiki ) ); + # Validate the returned value + if( !is_array( $ret ) ) + return $default; + + foreach( $default as $name => $def ){ + if( !isset( $ret[$name] ) || ( is_array( $default[$name] ) && !is_array( $ret[$name] ) ) ) + $ret[$name] = $default[$name]; } + + return $ret; + } + + /** + * Merge params beetween the ones passed to the function and the ones given + * by self::$siteParamsCallback for backward compatibility + * Values returned by self::getWikiParams() have the priority. + * + * @param $wiki String Wiki ID of the wiki in question. + * @param $suffix String The suffix of the wiki in question. + * @param $params Array List of parameters. $.'key' is replaced by $value in + * all returned data. + * @param $wikiTags Array The tags assigned to the wiki. + * @return array + */ + protected function mergeParams( $wiki, $suffix, /*array*/ $params, /*array*/ $wikiTags ){ + $ret = $this->getWikiParams( $wiki ); + + if( is_null( $ret['suffix'] ) ) + $ret['suffix'] = $suffix; + + $ret['tags'] = array_unique( array_merge( $ret['tags'], $wikiTags ) ); + + // Automatically fill that ones if needed + if( !isset( $ret['params']['lang'] ) && !is_null( $ret['lang'] ) ) + $ret['params']['lang'] = $ret['lang']; + if( !isset( $ret['params']['site'] ) && !is_null( $ret['suffix'] ) ) + $ret['params']['site'] = $ret['suffix']; + + $ret['params'] += $params; + /*echo "$wiki
\n"; + var_dump( $ret ); + echo "
\n"; + foreach( debug_backtrace() as $row ) + echo "File: {$row['file']} Line: {$row['line']}
\n"; + echo "
\n";*/ + return $ret; } /** * Work out the site and language name from a database name * @param $db */ - function siteFromDB( $db ) { - $site = NULL; - $lang = NULL; - - // Only run hooks if they *can* be run. - if (function_exists( 'wfRunHooks' ) && !wfRunHooks( 'SiteFromDB', array( $db, &$site, &$lang ) ) ) - return array( $site, $lang ); + public function siteFromDB( $db ) { + // Allow override + $def = $this->getWikiParams( $db ); + if( !is_null( $def['suffix'] ) && !is_null( $def['lang'] ) ) + return array( $def['suffix'], $def['lang'] ); + + $site = null; + $lang = null; foreach ( $this->suffixes as $suffix ) { if ( $suffix === '' ) { $site = ''; @@ -239,9 +360,37 @@ class SiteConfiguration { return array( $site, $lang ); } - /** Returns true if the given vhost is handled locally. */ - function isLocalVHost( $vhost ) { + /** + * Returns true if the given vhost is handled locally. + * @param $vhost String + * @return bool + */ + public function isLocalVHost( $vhost ) { return in_array( $vhost, $this->localVHosts ); } + + /** + * Merge multiple arrays together. + * On encountering duplicate keys, merge the two, but ONLY if they're arrays. + * PHP's array_merge_recursive() merges ANY duplicate values into arrays, + * which is not fun + */ + static function arrayMerge( $array1/* ... */ ) { + $out = $array1; + for( $i=1; $i < func_num_args(); $i++ ) { + foreach( func_get_arg( $i ) as $key => $value ) { + if ( isset($out[$key]) && is_array($out[$key]) && is_array($value) ) { + $out[$key] = self::arrayMerge( $out[$key], $value ); + } elseif ( !isset($out[$key]) || !$out[$key] && !is_numeric($key) ) { + // Values that evaluate to true given precedence, for the primary purpose of merging permissions arrays. + $out[$key] = $value; + } elseif ( is_numeric( $key ) ) { + $out[] = $value; + } + } + } + + return $out; + } } } -- 2.20.1