Re-commit r41410 (parts of at least) with fixes (case problems). Passes all the tests...
[lhc/web/wiklou.git] / includes / Interwiki.php
1 <?php
2 /**
3 * @file
4 * Interwiki table entry
5 */
6
7 /**
8 * The interwiki class
9 * All information is loaded on creation when called by Interwiki::fetch( $prefix ).
10 * All work is done on slave, because this should *never* change (except during schema updates etc, which arent wiki-related)
11 */
12 class Interwiki {
13
14 // Cache - removed in LRU order when it hits limit
15 protected static $smCache = array();
16 const CACHE_LIMIT = 100; // 0 means unlimited, any other value is max number of entries.
17
18 protected $mPrefix, $mURL, $mLocal, $mTrans;
19
20 function __construct( $prefix = null, $url = '', $local = 0, $trans = 0 )
21 {
22 $this->mPrefix = $prefix;
23 $this->mURL = $url;
24 $this->mLocal = $local;
25 $this->mTrans = $trans;
26 }
27
28 /**
29 * Check whether an interwiki prefix exists
30 *
31 * @return bool Whether it exists
32 * @param $prefix string Interwiki prefix to use
33 */
34 static public function isValidInterwiki( $prefix ){
35 global $wgContLang;
36 $prefix = $wgContLang->lc( $prefix );
37 if( isset( self::$smCache[$prefix] ) ){
38 return true;
39 }
40 global $wgInterwikiCache;
41 if ($wgInterwikiCache) {
42 return Interwiki::isValidInterwikiCached( $key );
43 }
44 $iw = new Interwiki;
45 if( !$iw->load( $prefix ) ){
46 return false;
47 }
48 if( self::CACHE_LIMIT && count( self::$smCache ) >= self::CACHE_LIMIT ){
49 array_shift( self::$smCache );
50 }
51 self::$smCache[$prefix] = &$iw;
52 return true;
53 }
54
55 /**
56 * Fetch an Interwiki object
57 *
58 * @return Interwiki Object, or null if not valid
59 * @param $prefix string Interwiki prefix to use
60 */
61 static public function fetch( $prefix ) {
62 global $wgContLang;
63 $prefix = $wgContLang->lc( $prefix );
64 if( isset( self::$smCache[$prefix] ) ){
65 return self::$smCache[$prefix];
66 }
67 global $wgInterwikiCache;
68 if ($wgInterwikiCache) {
69 return Interwiki::getInterwikiCached( $key );
70 }
71 $iw = new Interwiki;
72 if( !$iw->load( $prefix ) ){
73 return false;
74 }
75 if( self::CACHE_LIMIT && count( self::$smCache ) >= self::CACHE_LIMIT ){
76 array_shift( self::$smCache );
77 }
78 self::$smCache[$prefix] = &$iw;
79 return $iw;
80 }
81
82 /**
83 * Fetch interwiki prefix data from local cache in constant database.
84 *
85 * @note More logic is explained in DefaultSettings.
86 *
87 * @param $key \type{\string} Database key
88 * @return \type{\Interwiki} An interwiki object
89 */
90 protected static function getInterwikiCached( $key ) {
91 global $wgInterwikiCache, $wgInterwikiScopes, $wgInterwikiFallbackSite;
92 static $db, $site;
93
94 if (!$db)
95 $db=dba_open($wgInterwikiCache,'r','cdb');
96 /* Resolve site name */
97 if ($wgInterwikiScopes>=3 and !$site) {
98 $site = dba_fetch('__sites:' . wfWikiID(), $db);
99 if ($site=="")
100 $site = $wgInterwikiFallbackSite;
101 }
102 $value = dba_fetch( wfMemcKey( $key ), $db);
103 if ($value=='' and $wgInterwikiScopes>=3) {
104 /* try site-level */
105 $value = dba_fetch("_{$site}:{$key}", $db);
106 }
107 if ($value=='' and $wgInterwikiScopes>=2) {
108 /* try globals */
109 $value = dba_fetch("__global:{$key}", $db);
110 }
111 if ($value=='undef')
112 $value='';
113 $s = new Interwiki( $key );
114 if ( $value != '' ) {
115 list( $local, $url ) = explode( ' ', $value, 2 );
116 $s->mURL = $url;
117 $s->mLocal = (int)$local;
118 }
119 if( self::CACHE_LIMIT && count( self::$smCache ) >= self::CACHE_LIMIT ){
120 array_shift( self::$smCache );
121 }
122 self::$smCache[$prefix] = &$s;
123 return $s;
124 }
125
126 /**
127 * Check whether an interwiki is in the cache
128 *
129 * @note More logic is explained in DefaultSettings.
130 *
131 * @param $key \type{\string} Database key
132 * @return \type{\bool} Whether it exists
133 */
134 protected static function isValidInterwikiCached( $key ) {
135 global $wgInterwikiCache, $wgInterwikiScopes, $wgInterwikiFallbackSite;
136 static $db, $site;
137
138 if (!$db)
139 $db=dba_open($wgInterwikiCache,'r','cdb');
140 /* Resolve site name */
141 if ($wgInterwikiScopes>=3 and !$site) {
142 $site = dba_fetch('__sites:' . wfWikiID(), $db);
143 if ($site=="")
144 $site = $wgInterwikiFallbackSite;
145 }
146 $value = dba_fetch( wfMemcKey( $key ), $db);
147 if ($value=='' and $wgInterwikiScopes>=3) {
148 /* try site-level */
149 $value = dba_fetch("_{$site}:{$key}", $db);
150 }
151 if ($value=='' and $wgInterwikiScopes>=2) {
152 /* try globals */
153 $value = dba_fetch("__global:{$key}", $db);
154 }
155 if ($value=='undef')
156 $value='';
157 if ( $value != '' ) {
158 return true;
159 }else{
160 return false;
161 }
162 }
163
164 /**
165 * Clear all member variables in the current object. Does not clear
166 * the block from the DB.
167 */
168 function clear() {
169 $this->mURL = '';
170 $this->mLocal = $this->mTrans = 0;
171 $this->mPrefix = null;
172 }
173
174 /**
175 * Get the DB object
176 *
177 * @return Database
178 */
179 function &getDB(){
180 $db = wfGetDB( DB_SLAVE );
181 return $db;
182 }
183
184 /**
185 * Load interwiki from the DB
186 *
187 * @param $prefix The interwiki prefix
188 * @return bool The prefix is valid
189 *
190 */
191 function load( $prefix ) {
192 global $wgMemc;
193 $key = wfMemcKey( 'interwiki', $prefix );
194 $mc = $wgMemc->get( $key );
195 if( $mc && is_array( $mc ) ){ // is_array is hack for old keys
196 if( $this->loadFromArray( $mc ) ){
197 wfDebug("Succeeded\n");
198 return true;
199 }
200 }else{
201 $db =& $this->getDB();
202
203 $res = $db->resultObject( $db->select( 'interwiki', '*', array( 'iw_prefix' => $prefix ),
204 __METHOD__ ) );
205 if ( $this->loadFromResult( $res ) ) {
206 $mc = array( 'url' => $this->mURL, 'local' => $this->mLocal, 'trans' => $this->mTrans );
207 $wgMemc->add( $key, $mc );
208 return true;
209 }
210 }
211
212 # Give up
213 $this->clear();
214 return false;
215 }
216
217 /**
218 * Fill in member variables from an array (e.g. memcached result)
219 *
220 * @return bool Whether everything was there
221 * @param $res ResultWrapper Row from the interwiki table
222 */
223 function loadFromArray( $mc ) {
224 if( isset( $mc['url'] ) && isset( $mc['local'] ) && isset( $mc['trans'] ) ){
225 $this->mURL = $mc['url'];
226 $this->mLocal = $mc['local'];
227 $this->mTrans = $mc['trans'];
228 return true;
229 }
230 return false;
231 }
232
233 /**
234 * Fill in member variables from a result wrapper
235 *
236 * @return bool Whether there was a row there
237 * @param $res ResultWrapper Row from the interwiki table
238 */
239 function loadFromResult( ResultWrapper $res ) {
240 $ret = false;
241 if ( 0 != $res->numRows() ) {
242 # Get first entry
243 $row = $res->fetchObject();
244 $this->initFromRow( $row );
245 $ret = true;
246 }
247 $res->free();
248 return $ret;
249 }
250
251 /**
252 * Given a database row from the interwiki table, initialize
253 * member variables
254 *
255 * @param $row ResultWrapper A row from the interwiki table
256 */
257 function initFromRow( $row ) {
258 $this->mPrefix = $row->iw_prefix;
259 $this->mURL = $row->iw_url;
260 $this->mLocal = $row->iw_local;
261 $this->mTrans = $row->iw_trans;
262 }
263
264 /**
265 * Get the URL for a particular title (or with $1 if no title given)
266 *
267 * @param $title string What text to put for the article name
268 * @return string The URL
269 */
270 function getURL( $title = null ){
271 $url = $this->mURL;
272 if( $title != null ){
273 $url = str_replace( "$1", $title, $url );
274 }
275 return $url;
276 }
277
278 function isLocal(){
279 return $this->mLocal;
280 }
281
282 function isTranscludable(){
283 return $this->mTrans;
284 }
285
286 }