Index: trunk/extensions/GlobalUsage/GlobalUsageQuery.php |
— | — | @@ -5,11 +5,12 @@ |
6 | 6 | */ |
7 | 7 | class GlobalUsageQuery { |
8 | 8 | private $limit = 50; |
9 | | - private $offset = 0; |
| 9 | + private $offset; |
10 | 10 | private $hasMore = false; |
11 | 11 | private $filterLocal = false; |
12 | 12 | private $result; |
13 | 13 | private $continue; |
| 14 | + private $reversed = false; |
14 | 15 | |
15 | 16 | /** |
16 | 17 | * @param $target mixed Title or db key, or array of db keys of target(s) |
— | — | @@ -21,16 +22,20 @@ |
22 | 23 | $this->target = $target->getDBKey(); |
23 | 24 | else |
24 | 25 | $this->target = $target; |
25 | | - $this->offset = array( '', '', '' ); |
| 26 | + $this->offset = array(); |
26 | 27 | |
27 | 28 | } |
28 | 29 | |
29 | 30 | /** |
30 | 31 | * Set the offset parameter |
31 | 32 | * |
32 | | - * @param $offset int offset |
| 33 | + * @param $offset string offset |
| 34 | + * @param $reversed bool True if this is the upper offset |
33 | 35 | */ |
34 | | - public function setOffset( $offset ) { |
| 36 | + public function setOffset( $offset, $reversed = null ) { |
| 37 | + if ( !is_null( $reversed ) ) |
| 38 | + $this->reversed = $reversed; |
| 39 | + |
35 | 40 | if ( !is_array( $offset ) ) |
36 | 41 | $offset = explode( '|', $offset ); |
37 | 42 | |
— | — | @@ -50,12 +55,24 @@ |
51 | 56 | return implode( '|', $this->offset ); |
52 | 57 | } |
53 | 58 | /** |
| 59 | + * Is the result reversed |
| 60 | + * |
| 61 | + * @return bool |
| 62 | + */ |
| 63 | + public function isReversed() { |
| 64 | + return $this->reversed; |
| 65 | + } |
| 66 | + /** |
54 | 67 | * Returns the string used for continuation |
55 | 68 | * |
56 | 69 | * @return string |
| 70 | + * |
57 | 71 | */ |
58 | 72 | public function getContinueString() { |
59 | | - return "{$this->lastRow->gil_to}|{$this->lastRow->gil_wiki}|{$this->lastRow->gil_page}"; |
| 73 | + if ( $this->hasMore() ) |
| 74 | + return "{$this->lastRow->gil_to}|{$this->lastRow->gil_wiki}|{$this->lastRow->gil_page}"; |
| 75 | + else |
| 76 | + return ''; |
60 | 77 | } |
61 | 78 | |
62 | 79 | /** |
— | — | @@ -85,21 +102,40 @@ |
86 | 103 | * Executes the query |
87 | 104 | */ |
88 | 105 | public function execute() { |
| 106 | + /* Construct a where clause */ |
| 107 | + // Add target image(s) |
89 | 108 | $where = array( 'gil_to' => $this->target ); |
| 109 | + |
90 | 110 | if ( $this->filterLocal ) |
91 | 111 | // Don't show local file usage |
92 | 112 | $where[] = 'gil_wiki != ' . $this->db->addQuotes( wfWikiId() ); |
93 | 113 | |
94 | 114 | // Set the continuation condition |
95 | | - $qTo = $this->db->addQuotes( $this->offset[0] ); |
96 | | - $qWiki = $this->db->addQuotes( $this->offset[1] ); |
97 | | - $qPage = intval( $this->offset[2] ); |
| 115 | + $order = 'ASC'; |
| 116 | + if ( $this->offset ) { |
| 117 | + $qTo = $this->db->addQuotes( $this->offset[0] ); |
| 118 | + $qWiki = $this->db->addQuotes( $this->offset[1] ); |
| 119 | + $qPage = intval( $this->offset[2] ); |
| 120 | + |
| 121 | + // Check which limit we got in order to determine which way to traverse rows |
| 122 | + if ( $this->reversed ) { |
| 123 | + // Reversed traversal; do not include offset row |
| 124 | + $op1 = '<'; |
| 125 | + $op2 = '<'; |
| 126 | + $order = 'DESC'; |
| 127 | + } else { |
| 128 | + // Normal traversal; include offset row |
| 129 | + $op1 = '>'; |
| 130 | + $op2 = '>='; |
| 131 | + $order = 'ASC'; |
| 132 | + } |
| 133 | + |
| 134 | + $where[] = "(gil_to $op1 $qTo) OR " . |
| 135 | + "(gil_to = $qTo AND gil_wiki $op1 $qWiki) OR " . |
| 136 | + "(gil_to = $qTo AND gil_wiki = $qWiki AND gil_page $op2 $qPage)"; |
| 137 | + } |
98 | 138 | |
99 | | - $where[] = "(gil_to > $qTo) OR " . |
100 | | - "(gil_to = $qTo AND gil_wiki > $qWiki) OR " . |
101 | | - "(gil_to = $qTo AND gil_wiki = $qWiki AND gil_page >= $qPage )"; |
102 | | - |
103 | | - |
| 139 | + /* Perform select (Duh.) */ |
104 | 140 | $res = $this->db->select( 'globalimagelinks', |
105 | 141 | array( |
106 | 142 | 'gil_to', |
— | — | @@ -111,16 +147,26 @@ |
112 | 148 | $where, |
113 | 149 | __METHOD__, |
114 | 150 | array( |
115 | | - 'ORDER BY' => 'gil_to, gil_wiki, gil_page', |
| 151 | + 'ORDER BY' => "gil_to $order, gil_wiki $order, gil_page $order", |
116 | 152 | // Select an extra row to check whether we have more rows available |
117 | 153 | 'LIMIT' => $this->limit + 1, |
118 | 154 | ) |
119 | 155 | ); |
120 | 156 | |
| 157 | + /* Process result */ |
| 158 | + // Always return the result in the same order; regardless whether reversed was specified |
| 159 | + // reversed is really only used to determine from which direction the offset is |
| 160 | + $rows = array(); |
| 161 | + foreach ( $res as $row ) |
| 162 | + $rows[] = $row; |
| 163 | + if ( $this->reversed ) |
| 164 | + $rows = array_reverse( $rows ); |
| 165 | + |
| 166 | + // Build the result array |
121 | 167 | $count = 0; |
122 | 168 | $this->hasMore = false; |
123 | 169 | $this->result = array(); |
124 | | - foreach ( $res as $row ) { |
| 170 | + foreach ( $rows as $row ) { |
125 | 171 | $count++; |
126 | 172 | if ( $count > $this->limit ) { |
127 | 173 | // We've reached the extra row that indicates that there are more rows |
Index: trunk/extensions/GlobalUsage/SpecialGlobalUsage.php |
— | — | @@ -85,7 +85,10 @@ |
86 | 86 | $query = new GlobalUsageQuery( $this->target ); |
87 | 87 | |
88 | 88 | // Extract params from $wgRequest |
89 | | - $query->setOffset( $wgRequest->getText( 'offset' ) ); |
| 89 | + if ( $wgRequest->getText( 'from' ) ) |
| 90 | + $query->setOffset( $wgRequest->getText( 'from' ) ); |
| 91 | + elseif ( $wgRequest->getText( 'to' ) ) |
| 92 | + $query->setOffset( $wgRequest->getText( 'to' ), true ); |
90 | 93 | $query->setLimit( $wgRequest->getInt( 'limit', 50 ) ); |
91 | 94 | $query->filterLocal( $this->filterLocal ); |
92 | 95 | |
— | — | @@ -217,9 +220,17 @@ |
218 | 221 | $target = $this->target->getText(); |
219 | 222 | $limit = $query->getLimit(); |
220 | 223 | $fmtLimit = $wgLang->formatNum( $limit ); |
| 224 | + |
| 225 | + # Find out which strings are for the prev and which for the next links |
221 | 226 | $offset = $query->getOffsetString(); |
222 | | - if ( $offset == '||' ) |
223 | | - $offset = ''; |
| 227 | + $continue = $query->getContinueString(); |
| 228 | + if ( $query->isReversed() ) { |
| 229 | + $from = $offset; |
| 230 | + $to = $continue; |
| 231 | + } else { |
| 232 | + $from = $continue; |
| 233 | + $to = $offset; |
| 234 | + } |
224 | 235 | |
225 | 236 | # Get prev/next link display text |
226 | 237 | $prev = wfMsgExt( 'prevn', array('parsemag','escape'), $fmtLimit ); |
— | — | @@ -232,18 +243,18 @@ |
233 | 244 | $title = $this->getTitle(); |
234 | 245 | |
235 | 246 | # Make 'previous' link |
236 | | - if ( $offset ) { |
| 247 | + if ( $to ) { |
237 | 248 | $attr = array( 'title' => $pTitle, 'class' => 'mw-prevlink' ); |
238 | | - $q = array( 'limit' => $limit, 'offset' => $offset, 'target' => $target ); |
| 249 | + $q = array( 'limit' => $limit, 'to' => $to, 'target' => $target ); |
239 | 250 | $plink = $skin->link( $title, $prev, $attr, $q ); |
240 | 251 | } else { |
241 | 252 | $plink = $prev; |
242 | 253 | } |
243 | 254 | |
244 | 255 | # Make 'next' link |
245 | | - if ( $query->hasMore() ) { |
| 256 | + if ( $from ) { |
246 | 257 | $attr = array( 'title' => $nTitle, 'class' => 'mw-nextlink' ); |
247 | | - $q = array( 'limit' => $limit, 'offset' => $query->getContinueString(), 'target' => $target ); |
| 258 | + $q = array( 'limit' => $limit, 'from' => $from, 'target' => $target ); |
248 | 259 | $nlink = $skin->link( $title, $next, $attr, $q ); |
249 | 260 | } else { |
250 | 261 | $nlink = $next; |