/extensions/Translate/utils/StringMatcher.php

https://github.com/ChuguluGames/mediawiki-svn · PHP · 207 lines · 114 code · 21 blank · 72 comment · 17 complexity · e94eb0d8d990777056f6029bbe03c523 MD5 · raw file

  1. <?php
  2. /**
  3. * Code for mangling message keys to avoid conflicting keys.
  4. * @file
  5. * @author Niklas Laxström
  6. * @copyright Copyright © 2008-2010, Niklas Laxström
  7. * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
  8. */
  9. /**
  10. * Interface that key-mangling classes must implement.
  11. *
  12. * The operations have to be reversible so that
  13. * x equals unMangle( mangle( x ) ).
  14. */
  15. interface StringMangler {
  16. /// @todo Does this really need to be in the interface???
  17. public static function EmptyMatcher();
  18. /**
  19. * General way to pass configuration to the mangler.
  20. * @param $configuration \array
  21. */
  22. public function setConf( $configuration );
  23. /**
  24. * Match strings against a pattern.
  25. * If string matches, mangle() should mangle the key.
  26. * @param $string \string Message key.
  27. * @return \bool
  28. */
  29. public function match( $string );
  30. /**
  31. * Mangles a list of message keys.
  32. * @param $data \string or \list{String} Unmangled message keys.
  33. * @return \string or \list{String} Mangled message keys.
  34. */
  35. public function mangle( $data );
  36. /**
  37. * Reverses the operation mangle() did.
  38. * @param $data \string or \list{String} Mangled message keys.
  39. * @return \string or \list{String} Umangled message keys.
  40. */
  41. public function unMangle( $data );
  42. }
  43. /**
  44. * The versatile default implementation of StringMangler interface.
  45. * It supports exact matches and patterns with any-wildcard (*).
  46. * All matching strings are prefixed with the same prefix.
  47. */
  48. class StringMatcher implements StringMangler {
  49. /// Prefix for mangled message keys
  50. protected $sPrefix = '';
  51. /// Exact message keys
  52. protected $aExact = array();
  53. /// Patterns of type foo*
  54. protected $aPrefix = array();
  55. /// Patterns that contain wildcard anywhere else than in the end
  56. protected $aRegex = array();
  57. /**
  58. * Alias for making NO-OP string mangler.
  59. */
  60. public static function EmptyMatcher() {
  61. return new StringMatcher;
  62. }
  63. /**
  64. * Cosntructor, see EmptyMatcher();
  65. */
  66. public function __construct( $prefix = '', $patterns = array() ) {
  67. $this->sPrefix = $prefix;
  68. $this->init( $patterns );
  69. }
  70. public function setConf( $conf ) {
  71. $this->sPrefix = $conf['prefix'];
  72. $this->init( $conf['patterns'] );
  73. }
  74. /**
  75. * Preprocesses the patterns.
  76. * They are split into exact keys, prefix matches and pattern matches to
  77. * speed up matching process.
  78. * @param $strings \list{String} Key patterns.
  79. */
  80. protected function init( Array $strings ) {
  81. foreach ( $strings as $string ) {
  82. $pos = strpos( $string, '*' );
  83. if ( $pos === false ) {
  84. $this->aExact[] = $string;
  85. } elseif ( $pos + 1 === strlen( $string ) ) {
  86. $prefix = substr( $string, 0, - 1 );
  87. $this->aPrefix[$prefix] = strlen( $prefix );
  88. } else {
  89. $string = str_replace( '\\*', '.+', preg_quote( $string ) );
  90. $this->aRegex[] = "/^$string$/";
  91. }
  92. }
  93. }
  94. public function match( $string ) {
  95. if ( in_array( $string, $this->aExact ) ) {
  96. return true;
  97. }
  98. foreach ( $this->aPrefix as $prefix => $len ) {
  99. if ( strncmp( $string, $prefix, $len ) === 0 ) {
  100. return true;
  101. }
  102. }
  103. foreach ( $this->aRegex as $regex ) {
  104. if ( preg_match( $regex, $string ) ) {
  105. return true;
  106. }
  107. }
  108. return false;
  109. }
  110. public function mangle( $data ) {
  111. if ( !$this->sPrefix ) {
  112. return $data;
  113. }
  114. if ( is_array( $data ) ) {
  115. return $this->mangleArray( $data );
  116. } elseif ( is_string( $data ) ) {
  117. return $this->mangleString( $data );
  118. } elseif ( $data === null ) {
  119. return $data;
  120. } else {
  121. throw new MWException( __METHOD__ . ": Unsupported datatype" );
  122. }
  123. }
  124. public function unMangle( $data ) {
  125. if ( !$this->sPrefix ) {
  126. return $data;
  127. }
  128. if ( is_array( $data ) ) {
  129. return $this->mangleArray( $data, true );
  130. } elseif ( is_string( $data ) ) {
  131. return $this->mangleString( $data, true );
  132. } elseif ( $data === null ) {
  133. return $data;
  134. } else {
  135. throw new MWException( __METHOD__ . ": Unsupported datatype" );
  136. }
  137. }
  138. /**
  139. * Mangles or unmangles single string.
  140. * @param $string \string Message key.
  141. * @param $reverse \bool Direction of mangling or unmangling.
  142. * @return \string
  143. */
  144. protected function mangleString( $string, $reverse = false ) {
  145. if ( $reverse ) {
  146. return $this->unMangleString( $string );
  147. } elseif ( $this->match( $string ) ) {
  148. return $this->sPrefix . $string;
  149. } else {
  150. return $string;
  151. }
  152. }
  153. /**
  154. * Unmangles the message key by removing the prefix it it exists.
  155. * @param $string \string Message key.
  156. * @return \string Unmangled message key.
  157. */
  158. protected function unMangleString( $string ) {
  159. if ( strncmp( $string, $this->sPrefix, strlen( $this->sPrefix ) ) === 0 ) {
  160. return substr( $string, strlen( $this->sPrefix ) );
  161. } else {
  162. return $string;
  163. }
  164. }
  165. /**
  166. * Mangles or unmangles list of message keys.
  167. * @param $array \list{String} Message keys.
  168. * @param $reverse \bool Direction of mangling or unmangling.
  169. * @return \list{String} (Un)mangled message keys.
  170. */
  171. protected function mangleArray( Array $array, $reverse = false ) {
  172. $temp = array();
  173. if ( isset( $array[0] ) ) {
  174. foreach ( $array as $key => &$value ) {
  175. $value = $this->mangleString( $value, $reverse );
  176. $temp[$key] = $value; // Assign a reference
  177. }
  178. } else {
  179. foreach ( $array as $key => &$value ) {
  180. $key = $this->mangleString( $key, $reverse );
  181. $temp[$key] = $value; // Assign a reference
  182. }
  183. }
  184. return $temp;
  185. }
  186. }