MediaWiki
REL1_23
|
00001 <?php 00029 abstract class PrefixSearch { 00039 public static function titleSearch( $search, $limit, $namespaces = array() ) { 00040 $search = new StringPrefixSearch; 00041 return $search->search( $search, $limit, $namespaces ); 00042 } 00043 00052 public function search( $search, $limit, $namespaces = array() ) { 00053 $search = trim( $search ); 00054 if ( $search == '' ) { 00055 return array(); // Return empty result 00056 } 00057 $namespaces = $this->validateNamespaces( $namespaces ); 00058 00059 // Find a Title which is not an interwiki and is in NS_MAIN 00060 $title = Title::newFromText( $search ); 00061 if ( $title && !$title->isExternal() ) { 00062 $ns = array( $title->getNamespace() ); 00063 if ( $ns[0] == NS_MAIN ) { 00064 $ns = $namespaces; // no explicit prefix, use default namespaces 00065 } 00066 return $this->searchBackend( 00067 $ns, $title->getText(), $limit ); 00068 } 00069 00070 // Is this a namespace prefix? 00071 $title = Title::newFromText( $search . 'Dummy' ); 00072 if ( $title && $title->getText() == 'Dummy' 00073 && $title->getNamespace() != NS_MAIN 00074 && !$title->isExternal() ) 00075 { 00076 $namespaces = array( $title->getNamespace() ); 00077 $search = ''; 00078 } 00079 00080 return $this->searchBackend( $namespaces, $search, $limit ); 00081 } 00082 00091 public function searchWithVariants( $search, $limit, array $namespaces ) { 00092 wfProfileIn( __METHOD__ ); 00093 $searches = $this->search( $search, $limit, $namespaces ); 00094 00095 // if the content language has variants, try to retrieve fallback results 00096 $fallbackLimit = $limit - count( $searches ); 00097 if ( $fallbackLimit > 0 ) { 00098 global $wgContLang; 00099 00100 $fallbackSearches = $wgContLang->autoConvertToAllVariants( $search ); 00101 $fallbackSearches = array_diff( array_unique( $fallbackSearches ), array( $search ) ); 00102 00103 foreach ( $fallbackSearches as $fbs ) { 00104 $fallbackSearchResult = $this->search( $fbs, $fallbackLimit, $namespaces ); 00105 $searches = array_merge( $searches, $fallbackSearchResult ); 00106 $fallbackLimit -= count( $fallbackSearchResult ); 00107 00108 if ( $fallbackLimit == 0 ) { 00109 break; 00110 } 00111 } 00112 } 00113 wfProfileOut( __METHOD__ ); 00114 return $searches; 00115 } 00116 00124 protected abstract function titles( array $titles ); 00125 00134 protected abstract function strings( array $strings ); 00135 00143 protected function searchBackend( $namespaces, $search, $limit ) { 00144 if ( count( $namespaces ) == 1 ) { 00145 $ns = $namespaces[0]; 00146 if ( $ns == NS_MEDIA ) { 00147 $namespaces = array( NS_FILE ); 00148 } elseif ( $ns == NS_SPECIAL ) { 00149 return $this->titles( $this->specialSearch( $search, $limit ) ); 00150 } 00151 } 00152 $srchres = array(); 00153 if ( wfRunHooks( 'PrefixSearchBackend', array( $namespaces, $search, $limit, &$srchres ) ) ) { 00154 return $this->titles( $this->defaultSearchBackend( $namespaces, $search, $limit ) ); 00155 } 00156 return $this->strings( $srchres ); 00157 } 00158 00166 protected function specialSearch( $search, $limit ) { 00167 global $wgContLang; 00168 00169 # normalize searchKey, so aliases with spaces can be found - bug 25675 00170 $search = str_replace( ' ', '_', $search ); 00171 00172 $searchKey = $wgContLang->caseFold( $search ); 00173 00174 // Unlike SpecialPage itself, we want the canonical forms of both 00175 // canonical and alias title forms... 00176 $keys = array(); 00177 foreach ( SpecialPageFactory::getList() as $page => $class ) { 00178 $keys[$wgContLang->caseFold( $page )] = $page; 00179 } 00180 00181 foreach ( $wgContLang->getSpecialPageAliases() as $page => $aliases ) { 00182 if ( !array_key_exists( $page, SpecialPageFactory::getList() ) ) {# bug 20885 00183 continue; 00184 } 00185 00186 foreach ( $aliases as $alias ) { 00187 $keys[$wgContLang->caseFold( $alias )] = $alias; 00188 } 00189 } 00190 ksort( $keys ); 00191 00192 $srchres = array(); 00193 foreach ( $keys as $pageKey => $page ) { 00194 if ( $searchKey === '' || strpos( $pageKey, $searchKey ) === 0 ) { 00195 // bug 27671: Don't use SpecialPage::getTitleFor() here because it 00196 // localizes its input leading to searches for e.g. Special:All 00197 // returning Spezial:MediaWiki-Systemnachrichten and returning 00198 // Spezial:Alle_Seiten twice when $wgLanguageCode == 'de' 00199 $srchres[] = Title::makeTitleSafe( NS_SPECIAL, $page ); 00200 } 00201 00202 if ( count( $srchres ) >= $limit ) { 00203 break; 00204 } 00205 } 00206 00207 return $srchres; 00208 } 00209 00221 protected function defaultSearchBackend( $namespaces, $search, $limit ) { 00222 $ns = array_shift( $namespaces ); // support only one namespace 00223 if ( in_array( NS_MAIN, $namespaces ) ) { 00224 $ns = NS_MAIN; // if searching on many always default to main 00225 } 00226 00227 $t = Title::newFromText( $search, $ns ); 00228 $prefix = $t ? $t->getDBkey() : ''; 00229 $dbr = wfGetDB( DB_SLAVE ); 00230 $res = $dbr->select( 'page', 00231 array( 'page_id', 'page_namespace', 'page_title' ), 00232 array( 00233 'page_namespace' => $ns, 00234 'page_title ' . $dbr->buildLike( $prefix, $dbr->anyString() ) 00235 ), 00236 __METHOD__, 00237 array( 'LIMIT' => $limit, 'ORDER BY' => 'page_title' ) 00238 ); 00239 $srchres = array(); 00240 foreach ( $res as $row ) { 00241 $srchres[] = Title::newFromRow( $row ); 00242 } 00243 return $srchres; 00244 } 00245 00252 protected function validateNamespaces( $namespaces ) { 00253 global $wgContLang; 00254 00255 // We will look at each given namespace against wgContLang namespaces 00256 $validNamespaces = $wgContLang->getNamespaces(); 00257 if ( is_array( $namespaces ) && count( $namespaces ) > 0 ) { 00258 $valid = array(); 00259 foreach ( $namespaces as $ns ) { 00260 if ( is_numeric( $ns ) && array_key_exists( $ns, $validNamespaces ) ) { 00261 $valid[] = $ns; 00262 } 00263 } 00264 if ( count( $valid ) > 0 ) { 00265 return $valid; 00266 } 00267 } 00268 00269 return array( NS_MAIN ); 00270 } 00271 } 00272 00277 class TitlePrefixSearch extends PrefixSearch { 00278 00279 protected function titles( array $titles ) { 00280 return $titles; 00281 } 00282 00283 protected function strings( array $strings ) { 00284 $titles = array_map( 'Title::newFromText', $strings ); 00285 $lb = new LinkBatch( $titles ); 00286 $lb->setCaller( __METHOD__ ); 00287 $lb->execute(); 00288 return $titles; 00289 } 00290 } 00291 00296 class StringPrefixSearch extends PrefixSearch { 00297 00298 protected function titles( array $titles ) { 00299 return array_map( function( Title $t ) { return $t->getPrefixedText(); }, $titles ); 00300 } 00301 00302 protected function strings( array $strings ) { 00303 return $strings; 00304 } 00305 }