Index: trunk/phase3/includes/Pager.php |
— | — | @@ -67,10 +67,15 @@ |
68 | 68 | public $mPastTheEndRow; |
69 | 69 | |
70 | 70 | /** |
71 | | - * The index to actually be used for ordering. This is a single string |
72 | | - * even if multiple orderings are supported. |
| 71 | + * The index to actually be used for ordering. This is a single column, |
| 72 | + * for one ordering, even if multiple orderings are supported. |
73 | 73 | */ |
74 | 74 | protected $mIndexField; |
| 75 | + /** |
| 76 | + * An array of secondary columns to order by. These fields are not part of the offset. |
| 77 | + * This is a column list for one ordering, even if multiple orderings are supported. |
| 78 | + */ |
| 79 | + protected $mExtraSortFields; |
75 | 80 | /** For pages that support multiple types of ordering, which one to use. |
76 | 81 | */ |
77 | 82 | protected $mOrderType; |
— | — | @@ -115,18 +120,22 @@ |
116 | 121 | $this->mDb = wfGetDB( DB_SLAVE ); |
117 | 122 | |
118 | 123 | $index = $this->getIndexField(); |
| 124 | + $extraSort = $this->getExtraSortFields(); |
119 | 125 | $order = $this->mRequest->getVal( 'order' ); |
120 | 126 | if( is_array( $index ) && isset( $index[$order] ) ) { |
121 | 127 | $this->mOrderType = $order; |
122 | 128 | $this->mIndexField = $index[$order]; |
| 129 | + $this->mExtraSortFields = (array)$extraSort[$order]; |
123 | 130 | } elseif( is_array( $index ) ) { |
124 | 131 | # First element is the default |
125 | 132 | reset( $index ); |
126 | 133 | list( $this->mOrderType, $this->mIndexField ) = each( $index ); |
| 134 | + $this->mExtraSortFields = (array)$extraSort[$this->mOrderType]; |
127 | 135 | } else { |
128 | 136 | # $index is not an array |
129 | 137 | $this->mOrderType = null; |
130 | 138 | $this->mIndexField = $index; |
| 139 | + $this->mExtraSortFields = (array)$extraSort; |
131 | 140 | } |
132 | 141 | |
133 | 142 | if( !isset( $this->mDefaultDirection ) ) { |
— | — | @@ -269,11 +278,16 @@ |
270 | 279 | $conds = isset( $info['conds'] ) ? $info['conds'] : array(); |
271 | 280 | $options = isset( $info['options'] ) ? $info['options'] : array(); |
272 | 281 | $join_conds = isset( $info['join_conds'] ) ? $info['join_conds'] : array(); |
| 282 | + $sortColumns = array_merge( array( $this->mIndexField ), $this->mExtraSortFields ); |
273 | 283 | if ( $descending ) { |
274 | | - $options['ORDER BY'] = $this->mIndexField; |
| 284 | + $options['ORDER BY'] = implode( ',', $sortColumns ); |
275 | 285 | $operator = '>'; |
276 | 286 | } else { |
277 | | - $options['ORDER BY'] = $this->mIndexField . ' DESC'; |
| 287 | + $orderBy = array(); |
| 288 | + foreach ( $sortColumns as $col ) { |
| 289 | + $orderBy[] = $col . ' DESC'; |
| 290 | + } |
| 291 | + $options['ORDER BY'] = implode( ',', $orderBy ); |
278 | 292 | $operator = '<'; |
279 | 293 | } |
280 | 294 | if ( $offset != '' ) { |
— | — | @@ -574,10 +588,30 @@ |
575 | 589 | * |
576 | 590 | * Needless to say, it's really not a good idea to use a non-unique index |
577 | 591 | * for this! That won't page right. |
| 592 | + * |
| 593 | + * @return string|Array |
578 | 594 | */ |
579 | 595 | abstract function getIndexField(); |
580 | 596 | |
581 | 597 | /** |
| 598 | + * This function should be overridden to return the names of secondary columns |
| 599 | + * to order by in addition to the column in getIndexField(). These fields will |
| 600 | + * not be used in the pager offset or in any links for users. |
| 601 | + * |
| 602 | + * If getIndexField() returns an array of 'querykey' => 'indexfield' pairs then |
| 603 | + * this must return a corresponding array of 'querykey' => array( fields...) pairs, |
| 604 | + * so that a request with &count=querykey will use array( fields...) to sort. |
| 605 | + * |
| 606 | + * This is useful for pagers that GROUP BY a unique column (say page_id) |
| 607 | + * and ORDER BY another (say page_len). Using GROUP BY and ORDER BY both on |
| 608 | + * page_len,page_id avoids temp tables (given a page_len index). This would |
| 609 | + * also work if page_id was non-unique but we had a page_len,page_id index. |
| 610 | + * |
| 611 | + * @return Array |
| 612 | + */ |
| 613 | + protected function getExtraSortFields() { return array(); } |
| 614 | + |
| 615 | + /** |
582 | 616 | * Return the default sorting direction: false for ascending, true for de- |
583 | 617 | * scending. You can also have an associative array of ordertype => dir, |
584 | 618 | * if multiple order types are supported. In this case getIndexField() |
Index: trunk/extensions/FlaggedRevs/presentation/specialpages/reports/ProblemChanges_body.php |
— | — | @@ -346,6 +346,7 @@ |
347 | 347 | } |
348 | 348 | array_unshift( $tables, 'flaggedpages' ); // order matters |
349 | 349 | $this->mIndexField = 'fp_pending_since'; |
| 350 | + $this->mExtraSortFields = array( 'fp_page_id' ); |
350 | 351 | $groupBy = 'fp_pending_since,fp_page_id'; |
351 | 352 | # Show outdated pages for a specific review level |
352 | 353 | } else { |
— | — | @@ -372,6 +373,7 @@ |
373 | 374 | } |
374 | 375 | array_unshift( $tables, 'flaggedpage_pending' ); // order matters |
375 | 376 | $this->mIndexField = 'fpp_pending_since'; |
| 377 | + $this->mExtraSortFields = array( 'fpp_page_id' ); |
376 | 378 | $groupBy = 'fpp_pending_since,fpp_page_id'; |
377 | 379 | } |
378 | 380 | $fields[] = $this->mIndexField; // Pager needs this |