Index: branches/iwtransclusion/phase3/languages/messages/MessagesEn.php |
— | — | @@ -4330,6 +4330,18 @@ |
4331 | 4331 | 'compare-rev2' => 'Revision 2', |
4332 | 4332 | 'compare-submit' => 'Compare', |
4333 | 4333 | |
| 4334 | +# Special:GlobalFileUsage |
| 4335 | +'globalfileusage' => 'Global file usage', |
| 4336 | +'globalfileusage-for' => 'Global file usage for "$1"', |
| 4337 | +'globalfileusage-desc' => '[[Special:GlobalFileUsage|Special page]] to view global file usage', |
| 4338 | +'globalfileusage-ok' => 'Search', |
| 4339 | +'globalfileusage-text' => 'Search global file usage', |
| 4340 | +'globalfileusage-no-results' => '[[$1]] is not used on other wikis.', |
| 4341 | +'globalfileusage-on-wiki' => 'Usage on $2', |
| 4342 | +'globalfileusage-of-file' => 'The following other wikis use this file:', |
| 4343 | +'globalfileusage-more' => 'View [[{{#Special:GlobalUsage}}/$1|more global usage]] of this file.', |
| 4344 | +'globalfileusage-filterlocal' => 'Do not show local usage', |
| 4345 | + |
4334 | 4346 | # Special:GlobalTemplateUsage |
4335 | 4347 | 'globaltemplateusage' => 'Global template usage', |
4336 | 4348 | 'globaltemplateusage-for' => 'Global template usage for "$1"', |
Index: branches/iwtransclusion/phase3/includes/GlobalUsageQuery.php |
— | — | @@ -0,0 +1,351 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * A helper class to query the globalimagelinks table |
| 5 | + * |
| 6 | + */ |
| 7 | +class GlobalUsageQuery { |
| 8 | + private $limit = 50; |
| 9 | + private $offset; |
| 10 | + private $hasMore = false; |
| 11 | + private $filterLocal = false; |
| 12 | + private $result; |
| 13 | + private $continue; |
| 14 | + private $reversed = false; |
| 15 | + private $target = null; |
| 16 | + |
| 17 | + /** |
| 18 | + * @param $target mixed Title or db key, or array of db keys of target(s) |
| 19 | + */ |
| 20 | + public function __construct( $target ) { |
| 21 | + global $wgGlobalDatabase; |
| 22 | + $this->db = wfGetDB( DB_SLAVE, array(), $wgGlobalDatabase ); |
| 23 | + if ( $target instanceof Title && $target->getNamespace( ) == NS_FILE ) |
| 24 | + $this->target = $target->getDBKey(); |
| 25 | + else |
| 26 | + $this->target = $target; |
| 27 | + $this->offset = array(); |
| 28 | + |
| 29 | + } |
| 30 | + |
| 31 | + /** |
| 32 | + * Set the offset parameter |
| 33 | + * |
| 34 | + * @param $offset string offset |
| 35 | + * @param $reversed bool True if this is the upper offset |
| 36 | + */ |
| 37 | + public function setOffset( $offset, $reversed = null ) { |
| 38 | + if ( !is_null( $reversed ) ) |
| 39 | + $this->reversed = $reversed; |
| 40 | + |
| 41 | + if ( !is_array( $offset ) ) |
| 42 | + $offset = explode( '|', $offset ); |
| 43 | + |
| 44 | + if ( count( $offset ) == 3 ) { |
| 45 | + $this->offset = $offset; |
| 46 | + return true; |
| 47 | + } else { |
| 48 | + return false; |
| 49 | + } |
| 50 | + } |
| 51 | + /** |
| 52 | + * Return the offset set by the user |
| 53 | + * |
| 54 | + * @return array offset |
| 55 | + */ |
| 56 | + public function getOffsetString() { |
| 57 | + return implode( '|', $this->offset ); |
| 58 | + } |
| 59 | + /** |
| 60 | + * Is the result reversed |
| 61 | + * |
| 62 | + * @return bool |
| 63 | + */ |
| 64 | + public function isReversed() { |
| 65 | + return $this->reversed; |
| 66 | + } |
| 67 | + |
| 68 | + /** |
| 69 | + * Returns the string used for continuation in a file search |
| 70 | + * |
| 71 | + * @return string |
| 72 | + * |
| 73 | + */ |
| 74 | + public function getContinueFileString() { |
| 75 | + if ( $this->hasMore() ) |
| 76 | + return "{$this->lastRow->gil_to}|{$this->lastRow->gil_wiki}|{$this->lastRow->gil_page}"; |
| 77 | + else |
| 78 | + return ''; |
| 79 | + } |
| 80 | + |
| 81 | + /** |
| 82 | + * Returns the string used for continuation in a template search |
| 83 | + * |
| 84 | + * @return string |
| 85 | + * |
| 86 | + */ |
| 87 | + public function getContinueTemplateString() { |
| 88 | + if ( $this->hasMore() ) |
| 89 | + return "{$this->lastRow->gtl_to_title}|{$this->lastRow->gtl_from_wiki}|{$this->lastRow->gtl_from_page}"; |
| 90 | + else |
| 91 | + return ''; |
| 92 | + } |
| 93 | + |
| 94 | + /** |
| 95 | + * Set the maximum amount of items to return. Capped at 500. |
| 96 | + * |
| 97 | + * @param $limit int The limit |
| 98 | + */ |
| 99 | + public function setLimit( $limit ) { |
| 100 | + $this->limit = min( $limit, 500 ); |
| 101 | + } |
| 102 | + /** |
| 103 | + * Returns the user set limit |
| 104 | + */ |
| 105 | + public function getLimit() { |
| 106 | + return $this->limit; |
| 107 | + } |
| 108 | + |
| 109 | + /** |
| 110 | + * Set whether to filter out the local usage |
| 111 | + */ |
| 112 | + public function filterLocal( $value = true ) { |
| 113 | + $this->filterLocal = $value; |
| 114 | + } |
| 115 | + |
| 116 | + /** |
| 117 | + * Executes the query for a file search |
| 118 | + */ |
| 119 | + public function searchTemplate() { |
| 120 | + global $wgLocalInterwiki; |
| 121 | + |
| 122 | + /* Construct a where clause */ |
| 123 | + // Add target template(s) |
| 124 | + $where = array( 'gtl_to_prefix' => $wgLocalInterwiki, |
| 125 | + 'gtl_to_namespace' => $this->target->getNamespace( ), |
| 126 | + 'gtl_to_title' => $this->target->getDBkey( ) |
| 127 | + ); |
| 128 | + |
| 129 | + // Set the continuation condition |
| 130 | + $order = 'ASC'; |
| 131 | + if ( $this->offset ) { |
| 132 | + $qTo = $this->db->addQuotes( $this->offset[0] ); |
| 133 | + $qWiki = $this->db->addQuotes( $this->offset[1] ); |
| 134 | + $qPage = intval( $this->offset[2] ); |
| 135 | + |
| 136 | + // Check which limit we got in order to determine which way to traverse rows |
| 137 | + if ( $this->reversed ) { |
| 138 | + // Reversed traversal; do not include offset row |
| 139 | + $op1 = '<'; |
| 140 | + $op2 = '<'; |
| 141 | + $order = 'DESC'; |
| 142 | + } else { |
| 143 | + // Normal traversal; include offset row |
| 144 | + $op1 = '>'; |
| 145 | + $op2 = '>='; |
| 146 | + $order = 'ASC'; |
| 147 | + } |
| 148 | + |
| 149 | + $where[] = "(gtl_to_title $op1 $qTo) OR " . |
| 150 | + "(gtl_to_title = $qTo AND gtl_from_wiki $op1 $qWiki) OR " . |
| 151 | + "(gtl_to_title = $qTo AND gtl_from_wiki = $qWiki AND gtl_from_page $op2 $qPage)"; |
| 152 | + } |
| 153 | + |
| 154 | + /* Perform select (Duh.) */ |
| 155 | + $res = $this->db->select( 'globaltemplatelinks', |
| 156 | + array( |
| 157 | + 'gtl_to_title', |
| 158 | + 'gtl_from_wiki', |
| 159 | + 'gtl_from_page', |
| 160 | + 'gtl_from_namespace', |
| 161 | + 'gtl_from_title' |
| 162 | + ), |
| 163 | + $where, |
| 164 | + __METHOD__, |
| 165 | + array( |
| 166 | + 'ORDER BY' => "gtl_to_title $order, gtl_from_wiki $order, gtl_from_page $order", |
| 167 | + // Select an extra row to check whether we have more rows available |
| 168 | + 'LIMIT' => $this->limit + 1, |
| 169 | + ) |
| 170 | + ); |
| 171 | + |
| 172 | + /* Process result */ |
| 173 | + // Always return the result in the same order; regardless whether reversed was specified |
| 174 | + // reversed is really only used to determine from which direction the offset is |
| 175 | + $rows = array(); |
| 176 | + foreach ( $res as $row ) { |
| 177 | + $rows[] = $row; |
| 178 | + } |
| 179 | + if ( $this->reversed ) { |
| 180 | + $rows = array_reverse( $rows ); |
| 181 | + } |
| 182 | + |
| 183 | + // Build the result array |
| 184 | + $count = 0; |
| 185 | + $this->hasMore = false; |
| 186 | + $this->result = array(); |
| 187 | + foreach ( $rows as $row ) { |
| 188 | + $count++; |
| 189 | + if ( $count > $this->limit ) { |
| 190 | + // We've reached the extra row that indicates that there are more rows |
| 191 | + $this->hasMore = true; |
| 192 | + $this->lastRow = $row; |
| 193 | + break; |
| 194 | + } |
| 195 | + |
| 196 | + if ( !isset( $this->result[$row->gtl_to_title] ) ) { |
| 197 | + $this->result[$row->gtl_to_title] = array(); |
| 198 | + } |
| 199 | + if ( !isset( $this->result[$row->gtl_to_title][$row->gtl_from_wiki] ) ) { |
| 200 | + $this->result[$row->gtl_to_title][$row->gtl_from_wiki] = array(); |
| 201 | + } |
| 202 | + |
| 203 | + $this->result[$row->gtl_to_title][$row->gtl_from_wiki][] = array( |
| 204 | + 'template' => $row->gtl_to_title, |
| 205 | + 'id' => $row->gtl_from_page, |
| 206 | + 'namespace' => $row->gtl_from_namespace, |
| 207 | + 'title' => $row->gtl_from_title, |
| 208 | + 'wiki' => $row->gtl_from_wiki, |
| 209 | + ); |
| 210 | + } |
| 211 | + } |
| 212 | + |
| 213 | + /** |
| 214 | + * Executes the query for a template search |
| 215 | + */ |
| 216 | + public function searchFile() { |
| 217 | + /* Construct a where clause */ |
| 218 | + // Add target image(s) |
| 219 | + $where = array( 'gil_to' => $this->target ); |
| 220 | + |
| 221 | + if ( $this->filterLocal ) |
| 222 | + // Don't show local file usage |
| 223 | + $where[] = 'gil_wiki != ' . $this->db->addQuotes( wfWikiId() ); |
| 224 | + |
| 225 | + // Set the continuation condition |
| 226 | + $order = 'ASC'; |
| 227 | + if ( $this->offset ) { |
| 228 | + $qTo = $this->db->addQuotes( $this->offset[0] ); |
| 229 | + $qWiki = $this->db->addQuotes( $this->offset[1] ); |
| 230 | + $qPage = intval( $this->offset[2] ); |
| 231 | + |
| 232 | + // Check which limit we got in order to determine which way to traverse rows |
| 233 | + if ( $this->reversed ) { |
| 234 | + // Reversed traversal; do not include offset row |
| 235 | + $op1 = '<'; |
| 236 | + $op2 = '<'; |
| 237 | + $order = 'DESC'; |
| 238 | + } else { |
| 239 | + // Normal traversal; include offset row |
| 240 | + $op1 = '>'; |
| 241 | + $op2 = '>='; |
| 242 | + $order = 'ASC'; |
| 243 | + } |
| 244 | + |
| 245 | + $where[] = "(gil_to $op1 $qTo) OR " . |
| 246 | + "(gil_to = $qTo AND gil_wiki $op1 $qWiki) OR " . |
| 247 | + "(gil_to = $qTo AND gil_wiki = $qWiki AND gil_page $op2 $qPage)"; |
| 248 | + } |
| 249 | + |
| 250 | + /* Perform select (Duh.) */ |
| 251 | + $res = $this->db->select( 'globalimagelinks', |
| 252 | + array( |
| 253 | + 'gil_to', |
| 254 | + 'gil_wiki', |
| 255 | + 'gil_page', |
| 256 | + 'gil_page_namespace', |
| 257 | + 'gil_page_title' |
| 258 | + ), |
| 259 | + $where, |
| 260 | + __METHOD__, |
| 261 | + array( |
| 262 | + 'ORDER BY' => "gil_to $order, gil_wiki $order, gil_page $order", |
| 263 | + // Select an extra row to check whether we have more rows available |
| 264 | + 'LIMIT' => $this->limit + 1, |
| 265 | + ) |
| 266 | + ); |
| 267 | + |
| 268 | + /* Process result */ |
| 269 | + // Always return the result in the same order; regardless whether reversed was specified |
| 270 | + // reversed is really only used to determine from which direction the offset is |
| 271 | + $rows = array(); |
| 272 | + foreach ( $res as $row ) |
| 273 | + $rows[] = $row; |
| 274 | + if ( $this->reversed ) |
| 275 | + $rows = array_reverse( $rows ); |
| 276 | + |
| 277 | + // Build the result array |
| 278 | + $count = 0; |
| 279 | + $this->hasMore = false; |
| 280 | + $this->result = array(); |
| 281 | + foreach ( $rows as $row ) { |
| 282 | + $count++; |
| 283 | + if ( $count > $this->limit ) { |
| 284 | + // We've reached the extra row that indicates that there are more rows |
| 285 | + $this->hasMore = true; |
| 286 | + $this->lastRow = $row; |
| 287 | + break; |
| 288 | + } |
| 289 | + |
| 290 | + if ( !isset( $this->result[$row->gil_to] ) ) |
| 291 | + $this->result[$row->gil_to] = array(); |
| 292 | + if ( !isset( $this->result[$row->gil_to][$row->gil_wiki] ) ) |
| 293 | + $this->result[$row->gil_to][$row->gil_wiki] = array(); |
| 294 | + |
| 295 | + $this->result[$row->gil_to][$row->gil_wiki][] = array( |
| 296 | + 'image' => $row->gil_to, |
| 297 | + 'id' => $row->gil_page, |
| 298 | + 'namespace' => $row->gil_page_namespace, |
| 299 | + 'title' => $row->gil_page_title, |
| 300 | + 'wiki' => $row->gil_wiki, |
| 301 | + ); |
| 302 | + } |
| 303 | + } |
| 304 | + |
| 305 | + /** |
| 306 | + * Returns the result set. The result is a 4 dimensional array |
| 307 | + * (file, wiki, page), whose items are arrays with keys: |
| 308 | + * - image or template: File name or template name |
| 309 | + * - id: Page id |
| 310 | + * - namespace: Page namespace text |
| 311 | + * - title: Unprefixed page title |
| 312 | + * - wiki: Wiki id |
| 313 | + * |
| 314 | + * @return array Result set |
| 315 | + */ |
| 316 | + public function getResult() { |
| 317 | + return $this->result; |
| 318 | + } |
| 319 | + /** |
| 320 | + * Returns a 3 dimensional array with the result of the first file. Useful |
| 321 | + * if only one resource was queried. |
| 322 | + * |
| 323 | + * For further information see documentation of getResult() |
| 324 | + * |
| 325 | + * @return array Result set |
| 326 | + */ |
| 327 | + public function getSingleResult() { |
| 328 | + if ( $this->result ) { |
| 329 | + return current( $this->result ); |
| 330 | + } else { |
| 331 | + return array(); |
| 332 | + } |
| 333 | + } |
| 334 | + |
| 335 | + /** |
| 336 | + * Returns whether there are more results |
| 337 | + * |
| 338 | + * @return bool |
| 339 | + */ |
| 340 | + public function hasMore() { |
| 341 | + return $this->hasMore; |
| 342 | + } |
| 343 | + |
| 344 | + /** |
| 345 | + * Returns the result length |
| 346 | + * |
| 347 | + * @return int |
| 348 | + */ |
| 349 | + public function count() { |
| 350 | + return count( $this->result ); |
| 351 | + } |
| 352 | +} |
Property changes on: branches/iwtransclusion/phase3/includes/GlobalUsageQuery.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 353 | + native |
Index: branches/iwtransclusion/phase3/includes/specials/SpecialGlobalTemplateUsage.php |
— | — | @@ -71,7 +71,7 @@ |
72 | 72 | private function showResult() { |
73 | 73 | global $wgRequest; |
74 | 74 | |
75 | | - $query = new GlobalTemplateUsageQuery( $this->target ); |
| 75 | + $query = new GlobalUsageQuery( $this->target ); |
76 | 76 | |
77 | 77 | // Extract params from $wgRequest |
78 | 78 | if ( $wgRequest->getText( 'from' ) ) { |
— | — | @@ -82,7 +82,7 @@ |
83 | 83 | $query->setLimit( $wgRequest->getInt( 'limit', 50 ) ); |
84 | 84 | |
85 | 85 | // Perform query |
86 | | - $query->execute(); |
| 86 | + $query->searchTemplate(); |
87 | 87 | |
88 | 88 | // Show result |
89 | 89 | global $wgOut; |
— | — | @@ -101,7 +101,7 @@ |
102 | 102 | $wgOut->addHtml( $navbar ); |
103 | 103 | |
104 | 104 | $wgOut->addHtml( '<div id="mw-globaltemplateusage-result">' ); |
105 | | - foreach ( $query->getSingleTemplateResult() as $wiki => $result ) { |
| 105 | + foreach ( $query->getSingleResult() as $wiki => $result ) { |
106 | 106 | $wgOut->addHtml( |
107 | 107 | '<h2>' . wfMsgExt( |
108 | 108 | 'globaltemplateusage-on-wiki', 'parseinline', |
— | — | @@ -151,7 +151,7 @@ |
152 | 152 | |
153 | 153 | # Find out which strings are for the prev and which for the next links |
154 | 154 | $offset = $query->getOffsetString(); |
155 | | - $continue = $query->getContinueString(); |
| 155 | + $continue = $query->getContinueTemplateString(); |
156 | 156 | if ( $query->isReversed() ) { |
157 | 157 | $from = $offset; |
158 | 158 | $to = $continue; |
— | — | @@ -205,244 +205,4 @@ |
206 | 206 | } |
207 | 207 | } |
208 | 208 | |
209 | | -/** |
210 | | - * This class has been copied from Extension:GlobalUsage / GlobalUsageQuery.php |
211 | | - * Extension:GlobalUsage should be built-in and the GlobalUsageQuery adapted |
212 | | - * to be able to fetch the global usage of templates as well as files. |
213 | | - * |
214 | | - * @author Bryan Tong Minh <bryan.tongminh@gmail.com> |
215 | | - * @author Peter Potrowl <peter017@gmail.com> |
216 | | - */ |
217 | | -class GlobalTemplateUsageQuery { |
218 | | - private $limit = 50; |
219 | | - private $offset; |
220 | | - private $hasMore = false; |
221 | | - private $result; |
222 | | - private $continue; |
223 | | - private $reversed = false; |
224 | | - private $target = null; |
225 | 209 | |
226 | | - /** |
227 | | - * @param $target mixed Title or db key, or array of db keys of target(s) |
228 | | - */ |
229 | | - public function __construct( $target ) { |
230 | | - global $wgGlobalDatabase; |
231 | | - $this->db = wfGetDB( DB_SLAVE, array(), $wgGlobalDatabase ); |
232 | | - $this->target = $target; |
233 | | - $this->offset = array(); |
234 | | - } |
235 | | - |
236 | | - /** |
237 | | - * Set the offset parameter |
238 | | - * |
239 | | - * @param $offset string offset |
240 | | - * @param $reversed bool True if this is the upper offset |
241 | | - */ |
242 | | - public function setOffset( $offset, $reversed = null ) { |
243 | | - if ( !is_null( $reversed ) ) { |
244 | | - $this->reversed = $reversed; |
245 | | - } |
246 | | - |
247 | | - if ( !is_array( $offset ) ) { |
248 | | - $offset = explode( '|', $offset ); |
249 | | - } |
250 | | - |
251 | | - if ( count( $offset ) == 3 ) { |
252 | | - $this->offset = $offset; |
253 | | - return true; |
254 | | - } else { |
255 | | - return false; |
256 | | - } |
257 | | - } |
258 | | - /** |
259 | | - * Return the offset set by the user |
260 | | - * |
261 | | - * @return array offset |
262 | | - */ |
263 | | - public function getOffsetString() { |
264 | | - return implode( '|', $this->offset ); |
265 | | - } |
266 | | - |
267 | | - /** |
268 | | - * Is the result reversed |
269 | | - * |
270 | | - * @return bool |
271 | | - */ |
272 | | - public function isReversed() { |
273 | | - return $this->reversed; |
274 | | - } |
275 | | - |
276 | | - /** |
277 | | - * Returns the string used for continuation |
278 | | - * |
279 | | - * @return string |
280 | | - * |
281 | | - */ |
282 | | - public function getContinueString() { |
283 | | - if ( $this->hasMore() ) |
284 | | - return "{$this->lastRow->gtl_to_title}|{$this->lastRow->gtl_from_wiki}|{$this->lastRow->gtl_from_page}"; |
285 | | - else |
286 | | - return ''; |
287 | | - } |
288 | | - |
289 | | - /** |
290 | | - * Set the maximum amount of items to return. Capped at 500. |
291 | | - * |
292 | | - * @param $limit int The limit |
293 | | - */ |
294 | | - public function setLimit( $limit ) { |
295 | | - $this->limit = min( $limit, 500 ); |
296 | | - } |
297 | | - |
298 | | - /** |
299 | | - * Returns the user set limit |
300 | | - */ |
301 | | - public function getLimit() { |
302 | | - return $this->limit; |
303 | | - } |
304 | | - |
305 | | - /** |
306 | | - * Executes the query |
307 | | - */ |
308 | | - public function execute() { |
309 | | - global $wgLocalInterwiki; |
310 | | - |
311 | | - /* Construct a where clause */ |
312 | | - // Add target template(s) |
313 | | - $where = array( 'gtl_to_prefix' => $wgLocalInterwiki, |
314 | | - 'gtl_to_namespace' => $this->target->getNamespace( ), |
315 | | - 'gtl_to_title' => $this->target->getDBkey( ) |
316 | | - ); |
317 | | - |
318 | | - // Set the continuation condition |
319 | | - $order = 'ASC'; |
320 | | - if ( $this->offset ) { |
321 | | - $qTo = $this->db->addQuotes( $this->offset[0] ); |
322 | | - $qWiki = $this->db->addQuotes( $this->offset[1] ); |
323 | | - $qPage = intval( $this->offset[2] ); |
324 | | - |
325 | | - // Check which limit we got in order to determine which way to traverse rows |
326 | | - if ( $this->reversed ) { |
327 | | - // Reversed traversal; do not include offset row |
328 | | - $op1 = '<'; |
329 | | - $op2 = '<'; |
330 | | - $order = 'DESC'; |
331 | | - } else { |
332 | | - // Normal traversal; include offset row |
333 | | - $op1 = '>'; |
334 | | - $op2 = '>='; |
335 | | - $order = 'ASC'; |
336 | | - } |
337 | | - |
338 | | - $where[] = "(gtl_to_title $op1 $qTo) OR " . |
339 | | - "(gtl_to_title = $qTo AND gtl_from_wiki $op1 $qWiki) OR " . |
340 | | - "(gtl_to_title = $qTo AND gtl_from_wiki = $qWiki AND gtl_from_page $op2 $qPage)"; |
341 | | - } |
342 | | - |
343 | | - /* Perform select (Duh.) */ |
344 | | - $res = $this->db->select( 'globaltemplatelinks', |
345 | | - array( |
346 | | - 'gtl_to_title', |
347 | | - 'gtl_from_wiki', |
348 | | - 'gtl_from_page', |
349 | | - 'gtl_from_namespace', |
350 | | - 'gtl_from_title' |
351 | | - ), |
352 | | - $where, |
353 | | - __METHOD__, |
354 | | - array( |
355 | | - 'ORDER BY' => "gtl_to_title $order, gtl_from_wiki $order, gtl_from_page $order", |
356 | | - // Select an extra row to check whether we have more rows available |
357 | | - 'LIMIT' => $this->limit + 1, |
358 | | - ) |
359 | | - ); |
360 | | - |
361 | | - /* Process result */ |
362 | | - // Always return the result in the same order; regardless whether reversed was specified |
363 | | - // reversed is really only used to determine from which direction the offset is |
364 | | - $rows = array(); |
365 | | - foreach ( $res as $row ) { |
366 | | - $rows[] = $row; |
367 | | - } |
368 | | - if ( $this->reversed ) { |
369 | | - $rows = array_reverse( $rows ); |
370 | | - } |
371 | | - |
372 | | - // Build the result array |
373 | | - $count = 0; |
374 | | - $this->hasMore = false; |
375 | | - $this->result = array(); |
376 | | - foreach ( $rows as $row ) { |
377 | | - $count++; |
378 | | - if ( $count > $this->limit ) { |
379 | | - // We've reached the extra row that indicates that there are more rows |
380 | | - $this->hasMore = true; |
381 | | - $this->lastRow = $row; |
382 | | - break; |
383 | | - } |
384 | | - |
385 | | - if ( !isset( $this->result[$row->gtl_to_title] ) ) { |
386 | | - $this->result[$row->gtl_to_title] = array(); |
387 | | - } |
388 | | - if ( !isset( $this->result[$row->gtl_to_title][$row->gtl_from_wiki] ) ) { |
389 | | - $this->result[$row->gtl_to_title][$row->gtl_from_wiki] = array(); |
390 | | - } |
391 | | - |
392 | | - $this->result[$row->gtl_to_title][$row->gtl_from_wiki][] = array( |
393 | | - 'template' => $row->gtl_to_title, |
394 | | - 'id' => $row->gtl_from_page, |
395 | | - 'namespace' => $row->gtl_from_namespace, |
396 | | - 'title' => $row->gtl_from_title, |
397 | | - 'wiki' => $row->gtl_from_wiki, |
398 | | - ); |
399 | | - } |
400 | | - } |
401 | | - /** |
402 | | - * Returns the result set. The result is a 4 dimensional array |
403 | | - * (file, wiki, page), whose items are arrays with keys: |
404 | | - * - template: File name |
405 | | - * - id: Page id |
406 | | - * - namespace: Page namespace text |
407 | | - * - title: Unprefixed page title |
408 | | - * - wiki: Wiki id |
409 | | - * |
410 | | - * @return array Result set |
411 | | - */ |
412 | | - public function getResult() { |
413 | | - return $this->result; |
414 | | - } |
415 | | - |
416 | | - /** |
417 | | - * Returns a 3 dimensional array with the result of the first file. Useful |
418 | | - * if only one template was queried. |
419 | | - * |
420 | | - * For further information see documentation of getResult() |
421 | | - * |
422 | | - * @return array Result set |
423 | | - */ |
424 | | - public function getSingleTemplateResult() { |
425 | | - if ( $this->result ) { |
426 | | - return current( $this->result ); |
427 | | - } else { |
428 | | - return array(); |
429 | | - } |
430 | | - } |
431 | | - |
432 | | - /** |
433 | | - * Returns whether there are more results |
434 | | - * |
435 | | - * @return bool |
436 | | - */ |
437 | | - public function hasMore() { |
438 | | - return $this->hasMore; |
439 | | - } |
440 | | - |
441 | | - /** |
442 | | - * Returns the result length |
443 | | - * |
444 | | - * @return int |
445 | | - */ |
446 | | - public function count() { |
447 | | - return count( $this->result ); |
448 | | - } |
449 | | -} |
Index: branches/iwtransclusion/phase3/includes/specials/SpecialGlobalFileUsage.php |
— | — | @@ -0,0 +1,224 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Special page to show global file usage. Also contains hook functions for |
| 5 | + * showing usage on an image page. |
| 6 | + */ |
| 7 | + |
| 8 | +class SpecialGlobalFileUsage extends SpecialPage { |
| 9 | + public function __construct() { |
| 10 | + parent::__construct( 'GlobalFileUsage', 'globalfileusage' ); |
| 11 | + |
| 12 | + wfLoadExtensionMessages( 'globalfileusage' ); |
| 13 | + } |
| 14 | + |
| 15 | + /** |
| 16 | + * Entry point |
| 17 | + */ |
| 18 | + public function execute( $par ) { |
| 19 | + global $wgOut, $wgRequest; |
| 20 | + |
| 21 | + $target = $par ? $par : $wgRequest->getVal( 'target' ); |
| 22 | + $this->target = Title::makeTitleSafe( NS_FILE, $target ); |
| 23 | + |
| 24 | + $this->filterLocal = $wgRequest->getCheck( 'filterlocal' ); |
| 25 | + |
| 26 | + $this->setHeaders(); |
| 27 | + |
| 28 | + $this->showForm(); |
| 29 | + |
| 30 | + if ( is_null( $this->target ) ) |
| 31 | + { |
| 32 | + $wgOut->setPageTitle( wfMsg( 'globalfileusage' ) ); |
| 33 | + return; |
| 34 | + } |
| 35 | + |
| 36 | + $wgOut->setPageTitle( wfMsg( 'globalfileusage-for', $this->target->getPrefixedText() ) ); |
| 37 | + |
| 38 | + $this->showResult(); |
| 39 | + } |
| 40 | + |
| 41 | + /** |
| 42 | + * Shows the search form |
| 43 | + */ |
| 44 | + private function showForm() { |
| 45 | + global $wgScript, $wgOut, $wgRequest; |
| 46 | + |
| 47 | + /* Build form */ |
| 48 | + $html = Xml::openElement( 'form', array( 'action' => $wgScript ) ) . "\n"; |
| 49 | + // Name of SpecialPage |
| 50 | + $html .= Xml::hidden( 'title', $this->getTitle()->getPrefixedText() ) . "\n"; |
| 51 | + // Limit |
| 52 | + $html .= Xml::hidden( 'limit', $wgRequest->getInt( 'limit', 50 ) ); |
| 53 | + // Input box with target prefilled if available |
| 54 | + $formContent = "\t" . Xml::input( 'target', 40, is_null( $this->target ) ? '' |
| 55 | + : $this->target->getText() ) |
| 56 | + // Submit button |
| 57 | + . "\n\t" . Xml::element( 'input', array( |
| 58 | + 'type' => 'submit', |
| 59 | + 'value' => wfMsg( 'globalfileusage-ok' ) |
| 60 | + ) ) |
| 61 | + // Filter local checkbox |
| 62 | + . "\n\t<p>" . Xml::checkLabel( wfMsg( 'globalfileusage-filterlocal' ), |
| 63 | + 'filterlocal', 'mw-filterlocal', $this->filterLocal ) . '</p>'; |
| 64 | + |
| 65 | + if ( !is_null( $this->target ) && wfFindFile( $this->target ) ) { |
| 66 | + // Show the image if it exists |
| 67 | + global $wgUser, $wgContLang; |
| 68 | + $skin = $wgUser->getSkin(); |
| 69 | + |
| 70 | + $html .= $skin->makeImageLinkObj( $this->target, |
| 71 | + $this->target->getPrefixedText(), |
| 72 | + /* $alt */ '', /* $align */ $wgContLang->alignEnd(), |
| 73 | + /* $handlerParams */ array(), /* $framed */ false, |
| 74 | + /* $thumb */ true ); |
| 75 | + } |
| 76 | + |
| 77 | + // Wrap the entire form in a nice fieldset |
| 78 | + $html .= Xml::fieldSet( wfMsg( 'globalfileusage-text' ), $formContent ) . "\n</form>"; |
| 79 | + |
| 80 | + $wgOut->addHtml( $html ); |
| 81 | + } |
| 82 | + |
| 83 | + /** |
| 84 | + * Creates as queryer and executes it based on $wgRequest |
| 85 | + */ |
| 86 | + private function showResult() { |
| 87 | + global $wgRequest; |
| 88 | + |
| 89 | + $query = new GlobalUsageQuery( $this->target ); |
| 90 | + |
| 91 | + // Extract params from $wgRequest |
| 92 | + if ( $wgRequest->getText( 'from' ) ) |
| 93 | + $query->setOffset( $wgRequest->getText( 'from' ) ); |
| 94 | + elseif ( $wgRequest->getText( 'to' ) ) |
| 95 | + $query->setOffset( $wgRequest->getText( 'to' ), true ); |
| 96 | + $query->setLimit( $wgRequest->getInt( 'limit', 50 ) ); |
| 97 | + $query->filterLocal( $this->filterLocal ); |
| 98 | + |
| 99 | + // Perform query |
| 100 | + $query->searchFile(); |
| 101 | + |
| 102 | + // Show result |
| 103 | + global $wgOut; |
| 104 | + |
| 105 | + // Don't show form element if there is no data |
| 106 | + if ( $query->count() == 0 ) { |
| 107 | + $wgOut->addWikiMsg( 'globalfileusage-no-results', $this->target->getPrefixedText() ); |
| 108 | + return; |
| 109 | + } |
| 110 | + |
| 111 | + $offset = $query->getOffsetString(); |
| 112 | + $navbar = $this->getNavBar( $query ); |
| 113 | + $targetName = $this->target->getText(); |
| 114 | + |
| 115 | + // Top navbar |
| 116 | + $wgOut->addHtml( $navbar ); |
| 117 | + |
| 118 | + $wgOut->addHtml( '<div id="mw-globalfileusage-result">' ); |
| 119 | + foreach ( $query->getSingleResult() as $wiki => $result ) { |
| 120 | + $wgOut->addHtml( |
| 121 | + '<h2>' . wfMsgExt( |
| 122 | + 'globalfileusage-on-wiki', 'parseinline', |
| 123 | + $targetName, WikiMap::getWikiName( $wiki ) ) |
| 124 | + . "</h2><ul>\n" ); |
| 125 | + foreach ( $result as $item ) |
| 126 | + $wgOut->addHtml( "\t<li>" . self::formatItem( $item ) . "</li>\n" ); |
| 127 | + $wgOut->addHtml( "</ul>\n" ); |
| 128 | + } |
| 129 | + $wgOut->addHtml( '</div>' ); |
| 130 | + |
| 131 | + // Bottom navbar |
| 132 | + $wgOut->addHtml( $navbar ); |
| 133 | + } |
| 134 | + /** |
| 135 | + * Helper to format a specific item |
| 136 | + */ |
| 137 | + public static function formatItem( $item ) { |
| 138 | + if ( !$item['namespace'] ) |
| 139 | + $page = $item['title']; |
| 140 | + else |
| 141 | + $page = "{$item['namespace']}:{$item['title']}"; |
| 142 | + |
| 143 | + $link = WikiMap::makeForeignLink( $item['wiki'], $page, |
| 144 | + str_replace( '_', ' ', $page ) ); |
| 145 | + // Return only the title if no link can be constructed |
| 146 | + return $link === false ? $page : $link; |
| 147 | + } |
| 148 | + |
| 149 | + /** |
| 150 | + * Helper function to create the navbar, stolen from wfViewPrevNext |
| 151 | + * |
| 152 | + * @param $query GlobalUsageQuery An executed GlobalUsageQuery object |
| 153 | + * @return string Navbar HTML |
| 154 | + */ |
| 155 | + protected function getNavBar( $query ) { |
| 156 | + global $wgLang, $wgUser; |
| 157 | + |
| 158 | + $skin = $wgUser->getSkin(); |
| 159 | + |
| 160 | + $target = $this->target->getText(); |
| 161 | + $limit = $query->getLimit(); |
| 162 | + $fmtLimit = $wgLang->formatNum( $limit ); |
| 163 | + |
| 164 | + # Find out which strings are for the prev and which for the next links |
| 165 | + $offset = $query->getOffsetString(); |
| 166 | + $continue = $query->getContinueFileString(); |
| 167 | + if ( $query->isReversed() ) { |
| 168 | + $from = $offset; |
| 169 | + $to = $continue; |
| 170 | + } else { |
| 171 | + $from = $continue; |
| 172 | + $to = $offset; |
| 173 | + } |
| 174 | + |
| 175 | + # Get prev/next link display text |
| 176 | + $prev = wfMsgExt( 'prevn', array( 'parsemag', 'escape' ), $fmtLimit ); |
| 177 | + $next = wfMsgExt( 'nextn', array( 'parsemag', 'escape' ), $fmtLimit ); |
| 178 | + # Get prev/next link title text |
| 179 | + $pTitle = wfMsgExt( 'prevn-title', array( 'parsemag', 'escape' ), $fmtLimit ); |
| 180 | + $nTitle = wfMsgExt( 'nextn-title', array( 'parsemag', 'escape' ), $fmtLimit ); |
| 181 | + |
| 182 | + # Fetch the title object |
| 183 | + $title = $this->getTitle(); |
| 184 | + |
| 185 | + # Make 'previous' link |
| 186 | + if ( $to ) { |
| 187 | + $attr = array( 'title' => $pTitle, 'class' => 'mw-prevlink' ); |
| 188 | + $q = array( 'limit' => $limit, 'to' => $to, 'target' => $target ); |
| 189 | + if ( $this->filterLocal ) |
| 190 | + $q['filterlocal'] = '1'; |
| 191 | + $plink = $skin->link( $title, $prev, $attr, $q ); |
| 192 | + } else { |
| 193 | + $plink = $prev; |
| 194 | + } |
| 195 | + |
| 196 | + # Make 'next' link |
| 197 | + if ( $from ) { |
| 198 | + $attr = array( 'title' => $nTitle, 'class' => 'mw-nextlink' ); |
| 199 | + $q = array( 'limit' => $limit, 'from' => $from, 'target' => $target ); |
| 200 | + if ( $this->filterLocal ) |
| 201 | + $q['filterlocal'] = '1'; |
| 202 | + $nlink = $skin->link( $title, $next, $attr, $q ); |
| 203 | + } else { |
| 204 | + $nlink = $next; |
| 205 | + } |
| 206 | + |
| 207 | + # Make links to set number of items per page |
| 208 | + $numLinks = array(); |
| 209 | + foreach ( array( 20, 50, 100, 250, 500 ) as $num ) { |
| 210 | + $fmtLimit = $wgLang->formatNum( $num ); |
| 211 | + |
| 212 | + $q = array( 'offset' => $offset, 'limit' => $num, 'target' => $target ); |
| 213 | + if ( $this->filterLocal ) |
| 214 | + $q['filterlocal'] = '1'; |
| 215 | + $lTitle = wfMsgExt( 'shown-title', array( 'parsemag', 'escape' ), $num ); |
| 216 | + $attr = array( 'title' => $lTitle, 'class' => 'mw-numlink' ); |
| 217 | + |
| 218 | + $numLinks[] = $skin->link( $title, $fmtLimit, $attr, $q ); |
| 219 | + } |
| 220 | + $nums = $wgLang->pipeList( $numLinks ); |
| 221 | + |
| 222 | + return wfMsgHtml( 'viewprevnext', $plink, $nlink, $nums ); |
| 223 | + } |
| 224 | +} |
| 225 | + |
Property changes on: branches/iwtransclusion/phase3/includes/specials/SpecialGlobalFileUsage.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 226 | + native |
Index: branches/iwtransclusion/phase3/includes/DefaultSettings.php |
— | — | @@ -4727,6 +4727,7 @@ |
4728 | 4728 | 'Export' => 'pagetools', |
4729 | 4729 | 'Import' => 'pagetools', |
4730 | 4730 | 'Whatlinkshere' => 'pagetools', |
| 4731 | + 'GlobalFileUsage' => 'pagetools', |
4731 | 4732 | 'GlobalTemplateUsage' => 'pagetools', |
4732 | 4733 | |
4733 | 4734 | 'Statistics' => 'wiki', |
Index: branches/iwtransclusion/phase3/includes/AutoLoader.php |
— | — | @@ -98,6 +98,7 @@ |
99 | 99 | 'FormatExif' => 'includes/Exif.php', |
100 | 100 | 'FormOptions' => 'includes/FormOptions.php', |
101 | 101 | 'GlobalDependency' => 'includes/CacheDependency.php', |
| 102 | + 'GlobalUsageQuery' => 'includes/GlobalUsageQuery.php', |
102 | 103 | 'HashBagOStuff' => 'includes/BagOStuff.php', |
103 | 104 | 'HashtableReplacer' => 'includes/StringUtils.php', |
104 | 105 | 'HistoryBlobCurStub' => 'includes/HistoryBlob.php', |
— | — | @@ -619,6 +620,7 @@ |
620 | 621 | 'SpecialComparePages' => 'includes/specials/SpecialComparePages.php', |
621 | 622 | 'SpecialExport' => 'includes/specials/SpecialExport.php', |
622 | 623 | 'SpecialFilepath' => 'includes/specials/SpecialFilepath.php', |
| 624 | + 'SpecialGlobalFileUsage' => 'includes/specials/SpecialGlobalFileUsage.php', |
623 | 625 | 'SpecialGlobalTemplateUsage' => 'includes/specials/SpecialGlobalTemplateUsage.php', |
624 | 626 | 'SpecialImport' => 'includes/specials/SpecialImport.php', |
625 | 627 | 'SpecialListGroupRights' => 'includes/specials/SpecialListgrouprights.php', |
Index: branches/iwtransclusion/phase3/includes/SpecialPage.php |
— | — | @@ -173,6 +173,7 @@ |
174 | 174 | # Page tools |
175 | 175 | 'ComparePages' => 'SpecialComparePages', |
176 | 176 | 'Export' => 'SpecialExport', |
| 177 | + 'GlobalFileUsage' => 'SpecialGlobalFileUsage', |
177 | 178 | 'GlobalTemplateUsage' => 'SpecialGlobalTemplateUsage', |
178 | 179 | 'Import' => 'SpecialImport', |
179 | 180 | 'Undelete' => 'UndeleteForm', |