PageRenderTime 54ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/extensions/Configure/Configure.diff.php

https://github.com/ChuguluGames/mediawiki-svn
PHP | 433 lines | 283 code | 53 blank | 97 comment | 64 complexity | bf503ca22a61e789608654b50bc0e91b MD5 | raw file
  1. <?php
  2. if ( !defined( 'MEDIAWIKI' ) ) die();
  3. /**
  4. * Class that generate differences between two versions of wiki configuration
  5. *
  6. * @ingroup Extensions
  7. */
  8. abstract class ConfigurationDiff {
  9. protected $diff;
  10. protected $version;
  11. protected $wikis;
  12. protected $callback = null;
  13. /**
  14. * Constructor
  15. *
  16. * @param $diff String: old version
  17. * @param $version String: new versions
  18. * @param $wikis Array: array of wiki names
  19. */
  20. public function __construct( $diff, $version, $wikis ) {
  21. $this->diff = $diff;
  22. $this->version = $version;
  23. $this->wikis = $wikis;
  24. }
  25. /**
  26. * Get the old configuration
  27. * @return Array
  28. */
  29. protected abstract function getOldVersion();
  30. /**
  31. * Get the new configuration
  32. * @return Array
  33. */
  34. protected abstract function getNewVersion();
  35. /**
  36. * Get as 3D array of settings
  37. * @return array
  38. */
  39. protected abstract function getSettings();
  40. /**
  41. * Get the array type of $setting
  42. *
  43. * @param $setting setting name
  44. * @return string
  45. */
  46. protected abstract function getArrayType( $setting );
  47. /**
  48. * Set a callback function that return a bool wheter a setting can be viewed
  49. * by the current user
  50. *
  51. * @param $callback callback
  52. * @return old callback
  53. */
  54. public function setViewCallback( $callback ) {
  55. $temp = $this->callback;
  56. if ( is_callable( $callback ) )
  57. $this->callback = $callback;
  58. return $temp;
  59. }
  60. /**
  61. * Can $setting be viewed by the current user?
  62. *
  63. * @param $setting String: setting name
  64. * @return bool
  65. */
  66. protected function isSettingViewable( $setting ) {
  67. if ( !is_callable( $this->callback ) )
  68. return true;
  69. return (bool)call_user_func_array( $this->callback, array( $setting ) );
  70. }
  71. /**
  72. * Clean up configuration by removing unwanted wikis, and wikis that aren't
  73. * either in $old or $new
  74. *
  75. * @param $old Array
  76. * @param $new Array
  77. * @return array of wikis names
  78. */
  79. function cleanWikis( &$old, &$new ) {
  80. $wikis = array();
  81. if ( $this->wikis === true )
  82. $this->wikis = array_unique( array_merge( array_keys( $old ), array_keys( $new ) ) );
  83. foreach ( $this->wikis as $wiki ) {
  84. if ( isset( $old[$wiki] ) && isset( $new[$wiki] ) )
  85. $wikis[] = $wiki;
  86. }
  87. if ( !count( $wikis ) )
  88. return false;
  89. $old_ = array();
  90. $new_ = array();
  91. foreach ( $wikis as $wiki ) {
  92. $old_[$wiki] = $old[$wiki];
  93. $new_[$wiki] = $new[$wiki];
  94. }
  95. $old = $old_;
  96. $new = $new_;
  97. return $wikis;
  98. }
  99. /**
  100. * Get the HTML of the diff
  101. */
  102. function getHTML() {
  103. global $wgOut;
  104. $wgOut->addStyle( 'common/diff.css' );
  105. $old = $this->getOldVersion();
  106. $new = $this->getNewVersion();
  107. if ( !( $wikis = $this->cleanWikis( $old, $new ) ) ) {
  108. return wfMsgExt( 'configure-no-diff', array( 'parse' ) );
  109. }
  110. $text = '';
  111. foreach ( $wikis as $wiki ) {
  112. $text .= '<h2>' . htmlspecialchars( $wiki ) . "</h2>\n";
  113. $text .= $this->processDiff( $old[$wiki], $new[$wiki] );
  114. }
  115. return $text;
  116. }
  117. /**
  118. * Process a diff between to configuration
  119. *
  120. * @param $old Array
  121. * @param $new Array
  122. * @return String: XHTML
  123. */
  124. function processDiff( $old, $new ) {
  125. $text = '';
  126. $settings = $this->getSettings();
  127. foreach ( $settings as $sectionName => $sectionGroups ) {
  128. $sectionDiff = '';
  129. foreach ( $sectionGroups as $groupName => $groupSettings ) {
  130. $groupDiff = '';
  131. foreach ( $groupSettings as $setting => $type ) {
  132. $oldSetting = isset( $old[$setting] ) ? $old[$setting] : null;
  133. $newSetting = isset( $new[$setting] ) ? $new[$setting] : null;
  134. if ( $oldSetting === $newSetting || !$this->isSettingViewable( $setting ) ) {
  135. continue;
  136. }
  137. else
  138. $groupDiff .= $this->processDiffSetting( $setting, $oldSetting, $newSetting, $type ) . "\n";
  139. }
  140. if ( $groupDiff != '' ) {
  141. $name = wfMsgExt( 'configure-section-' . $groupName, array( 'parseinline' ) );
  142. if ( wfEmptyMsg( 'configure-section-' . $groupName, $name ) )
  143. $name = $groupName;
  144. $sectionDiff .= "<tr><td colspan=\"4\"><h4 class=\"config-diff-group\">{$name}</h4></td></tr>\n";
  145. $sectionDiff .= $groupDiff;
  146. }
  147. }
  148. if ( $sectionDiff != '' ) {
  149. $name = wfMsgExt( 'configure-section-' . $sectionName, array( 'parseinline' ) );
  150. $text .= "<tr><td colspan=\"4\"><h3 class=\"config-diff-section\">{$name}</h3></td></tr>\n";
  151. $text .= $sectionDiff;
  152. }
  153. }
  154. if ( empty( $text ) )
  155. return wfMsgExt( 'configure-no-diff', array( 'parse' ) );
  156. $ret = "<table class='diff'>\n";
  157. $ret .= "<col class='diff-marker' />";
  158. $ret .= "<col class='diff-content' />";
  159. $ret .= "<col class='diff-marker' />";
  160. $ret .= "<col class='diff-content' />";
  161. $ret .= $text;
  162. $ret .= "</table>";
  163. return $ret;
  164. }
  165. /**
  166. * Process a diff for one setting
  167. *
  168. * @param $name String: setting name
  169. * @patam $old Mixed: old value
  170. * @param $new Mixed: new value
  171. * @param $type String: setting type
  172. * @return String: XHTML
  173. */
  174. function processDiffSetting( $name, $old, $new, $type ) {
  175. $msg = 'configure-setting-' . $name;
  176. $msgVal = wfMsgExt( $msg, array( 'parseinline' ) );
  177. $rawVal = Xml::element( 'tt', null, "\$$name" );
  178. if ( wfEmptyMsg( $msg, $msgVal ) )
  179. $msgVal = $rawVal;
  180. else
  181. $msgVal = "$msgVal ($rawVal)";
  182. $oldSet = $this->getSettingAsArray( WebConfiguration::filterVar( $old ), $name, $type );
  183. $newSet = $this->getSettingAsArray( WebConfiguration::filterVar( $new ), $name, $type );
  184. $diffs = new Diff( $oldSet, $newSet );
  185. $formatter = new TableDiffFormatter();
  186. return "<tr><td class=\"diff-lineno configure-setting\" colspan=\"4\">{$msgVal}</td></tr>\n" .
  187. $formatter->format( $diffs );
  188. }
  189. /**
  190. * Get an array representing the setting
  191. *
  192. * @param $setting Mixed: setting value
  193. * @param $name String: setting name
  194. * @param $type String: setting type
  195. * @return Array
  196. */
  197. function getSettingAsArray( $setting, $name, $type ) {
  198. if ( $setting === null ) {
  199. $val = array();
  200. } elseif ( $type == 'array' ) {
  201. if( !is_array( $setting ) )
  202. return array();
  203. $arrType = $this->getArrayType( $name );
  204. if ( $arrType == 'simple' || $arrType == 'ns-simple' ) {
  205. $val = array_values( $setting );
  206. } elseif ( $arrType == 'assoc' ) {
  207. $arrVal = array();
  208. foreach ( $setting as $key => $value ) {
  209. $arrVal[] = "$key: $value";
  210. }
  211. $val = $arrVal;
  212. } elseif ( $arrType == 'simple-dual' ) {
  213. $arrVal = array();
  214. foreach ( $setting as $key => $value ) {
  215. $arrVal[] = implode( ',', $value );
  216. }
  217. $val = $arrVal;
  218. } elseif ( $arrType == 'ns-bool' || $arrType == 'ns-text' || $arrType == 'ns-array' ) {
  219. $arrVal = array();
  220. foreach ( $setting as $key => $value ) {
  221. if ( $arrType == 'ns-bool' )
  222. $value = $value ? 'true' : 'false';
  223. if ( $arrType == 'ns-array' )
  224. $value = is_array( $value ) ? implode( ',', $value ) : '';
  225. $arrVal[] = "$key: $value";
  226. }
  227. $val = $arrVal;
  228. } elseif ( $arrType == 'group-array' ) {
  229. $arrVal = array();
  230. foreach ( $setting as $key => $value ) {
  231. $arrVal[] = "$key: " . implode( ',', $value );
  232. }
  233. $val = $arrVal;
  234. } elseif ( $arrType == 'group-bool' ) {
  235. $arrVal = array();
  236. ksort($setting);
  237. foreach ( $setting as $key1 => $value1 ) {
  238. ksort($value1);
  239. foreach ( $value1 as $key2 => $value2 ) {
  240. if ($value2) // Only show 'true's
  241. $arrVal[] = "$key1, $key2: " . 'true';
  242. }
  243. }
  244. $val = $arrVal;
  245. } elseif ( $arrType == 'rate-limits' ) {
  246. $val = array();
  247. ## Just walk the tree and print out the data.
  248. foreach( $setting as $action => $limits ) {
  249. foreach( $limits as $group => $limit ) {
  250. if (is_array($limit) && count($limit) == 2) { // Only show set limits
  251. list( $count, $period ) = $limit;
  252. if ($count == 0 || $period == 0)
  253. continue;
  254. $val[] = "$action, $group: " . wfMsg( 'configure-throttle-summary', $count, $period );
  255. }
  256. }
  257. }
  258. } elseif ( $arrType == 'promotion-conds' ) {
  259. ## For each group, print out the full conditions.
  260. $val = array();
  261. $opToName = array_flip( array( 'or' => '|', 'and' => '&', 'xor' => '^', 'not' => '!' ) );
  262. $validOps = array_keys( $opToName );
  263. foreach( $setting as $group => $conds ) {
  264. if ( !is_array( $conds ) ) {
  265. $val[] = "$group: ".wfMsg( "configure-condition-description-$conds" );
  266. continue;
  267. }
  268. if ( count( $conds ) == 0 ) {
  269. $val[] = "$group: ".wfMsg( 'configure-autopromote-noconds' );
  270. continue;
  271. }
  272. if ( count( $conds ) > 1 && in_array( $conds[0], $validOps ) ) {
  273. $boolop = array_shift( $conds );
  274. $boolop = $opToName[$boolop];
  275. $val[] = "$group: " . wfMsg( "configure-boolop-description-$boolop" );
  276. } else {
  277. $conds = array( $conds );
  278. }
  279. // Analyse each individual one...
  280. foreach( $conds as $cond ) {
  281. if ($cond == array( APCOND_AGE, -1 ) ) {
  282. $val[] = "$group: " . wfMsg( 'configure-autopromote-noconds' );
  283. continue;
  284. }
  285. if( !is_array( $cond ) ) {
  286. $cond = array( $cond );
  287. }
  288. $name = array_shift( $cond );
  289. $argSummary = implode( ', ', $cond );
  290. $count = count( $cond );
  291. $val[] = "$group: ".wfMsgExt( "configure-condition-description-$name", array( 'parsemag' ), $argSummary, $count );
  292. }
  293. }
  294. } else {
  295. $val = explode( "\n", var_export( $setting, 1 ) );
  296. }
  297. } elseif ( $type == 'bool' ) {
  298. $val = array( $setting ? 'true' : 'false' );
  299. } else {
  300. $val = explode( "\n", (string)$setting );
  301. }
  302. return $val;
  303. }
  304. }
  305. /**
  306. * Generate diff for preview in Special:Configure
  307. *
  308. * @ingroup Extensions
  309. */
  310. class CorePreviewConfigurationDiff extends ConfigurationDiff {
  311. protected function getOldVersion() {
  312. return $this->diff;
  313. }
  314. protected function getNewVersion() {
  315. return $this->version;
  316. }
  317. protected function getSettings() {
  318. return ConfigurationSettings::singleton( CONF_SETTINGS_CORE )->getSettings();
  319. }
  320. protected function getArrayType( $setting ) {
  321. return ConfigurationSettings::singleton( CONF_SETTINGS_CORE )->getArrayType( $setting );
  322. }
  323. }
  324. /**
  325. * Generate diff for preview in Special:Extensions
  326. *
  327. * @ingroup Extensions
  328. */
  329. class ExtPreviewConfigurationDiff extends ConfigurationDiff {
  330. protected function getOldVersion() {
  331. return $this->diff;
  332. }
  333. protected function getNewVersion() {
  334. return $this->version;
  335. }
  336. protected function getSettings() {
  337. return ConfigurationSettings::singleton( CONF_SETTINGS_EXT )->getSettings();
  338. }
  339. protected function getArrayType( $setting ) {
  340. return ConfigurationSettings::singleton( CONF_SETTINGS_EXT )->getArrayType( $setting );
  341. }
  342. }
  343. /**
  344. * Generate diff for history in Special:ViewConfig
  345. *
  346. * @ingroup Extensions
  347. */
  348. class HistoryConfigurationDiff extends ConfigurationDiff {
  349. protected function getOldVersion() {
  350. global $wgConf;
  351. $settings = $wgConf->getOldSettings( $this->diff );
  352. if ($this->diff == 'default') { ## Special case: Replicate settings across all wikis for a fair comparison.
  353. $new = $this->getNewVersion();
  354. $defaultSettings = array();
  355. ## This is kinda annoying. We can't copy ALL settings over, because not all settings are stored.
  356. foreach( $new as $wiki => $newSettings ) {
  357. if ($wiki == '__metadata') ## Ignore metadata.
  358. continue;
  359. $defaultSettings[$wiki] = array();
  360. foreach( $newSettings as $key => $value ) {
  361. if (isset($settings['default'][$key]))
  362. $defaultSettings[$wiki][$key] = $settings['default'][$key];
  363. }
  364. }
  365. $settings = $defaultSettings;
  366. }
  367. return $settings;
  368. }
  369. protected function getNewVersion() {
  370. global $wgConf;
  371. $settings = $wgConf->getOldSettings( $this->version );
  372. return $settings;
  373. }
  374. protected function getSettings() {
  375. return ConfigurationSettings::singleton( CONF_SETTINGS_BOTH )->getSettings();
  376. }
  377. protected function getArrayType( $setting ) {
  378. return ConfigurationSettings::singleton( CONF_SETTINGS_BOTH )->getArrayType( $setting );
  379. }
  380. }