Enable new category sort by default
authorAryeh Gregor <simetrical@users.mediawiki.org>
Tue, 3 Aug 2010 20:50:01 +0000 (20:50 +0000)
committerAryeh Gregor <simetrical@users.mediawiki.org>
Tue, 3 Aug 2010 20:50:01 +0000 (20:50 +0000)
Patch best viewed with whitespace changes ignored.  This will doubtless
introduce a bunch of bugs.  Please report any so I can fix them.  If
they're big enough and the fix isn't obvious, please revert.

includes/CategoryPage.php
includes/DefaultSettings.php
includes/LinksUpdate.php
includes/installer/MysqlUpdater.php
maintenance/archives/patch-categorylinks-better-collation.sql
maintenance/updateCollation.php
maintenance/updaters.inc

index 2b6a4c1..b12c13f 100644 (file)
@@ -51,17 +51,12 @@ class CategoryPage extends Article {
        }
 
        function closeShowCategory() {
-               global $wgOut, $wgRequest, $wgExperimentalCategorySort;
+               global $wgOut, $wgRequest;
 
-               if ( $wgExperimentalCategorySort ) {
-                       $from = $until = array();
-                       foreach ( array( 'page', 'subcat', 'file' ) as $type ) {
-                               $from[$type] = $wgRequest->getVal( "{$type}from" );
-                               $until[$type] = $wgRequest->getVal( "{$type}until" );
-                       }
-               } else {
-                       $from = $wgRequest->getVal( 'from' );
-                       $until = $wgRequest->getVal( 'until' );
+               $from = $until = array();
+               foreach ( array( 'page', 'subcat', 'file' ) as $type ) {
+                       $from[$type] = $wgRequest->getVal( "{$type}from" );
+                       $until[$type] = $wgRequest->getVal( "{$type}until" );
                }
 
                $viewer = new CategoryViewer( $this->mTitle, $from, $until, $wgRequest->getValues() );
@@ -184,7 +179,7 @@ class CategoryViewer {
        * else use sortkey...
        */
        function getSubcategorySortChar( $title, $sortkey ) {
-               global $wgContLang, $wgExperimentalCategorySort;
+               global $wgContLang;
 
                if ( $title->getPrefixedText() == $sortkey ) {
                        $word = $title->getDBkey();
@@ -192,11 +187,7 @@ class CategoryViewer {
                        $word = $sortkey;
                }
 
-               if ( $wgExperimentalCategorySort ) {
-                       $firstChar = $wgContLang->firstLetterForLists( $word );
-               } else {
-                       $firstChar = $wgContLang->firstChar( $word );
-               }
+               $firstChar = $wgContLang->firstLetterForLists( $word );
 
                return $wgContLang->convert( $firstChar );
        }
@@ -206,12 +197,7 @@ class CategoryViewer {
         */
        function addImage( Title $title, $sortkey, $pageLength, $isRedirect = false ) {
                if ( $this->showGallery ) {
-                       global $wgExperimentalCategorySort;
-                       if ( $wgExperimentalCategorySort ) {
-                               $flip = $this->flip['file'];
-                       } else {
-                               $flip = $this->flip;
-                       }
+                       $flip = $this->flip['file'];
                        if ( $flip ) {
                                $this->gallery->insert( $title );
                        } else {
@@ -226,7 +212,7 @@ class CategoryViewer {
         * Add a miscellaneous page
         */
        function addPage( $title, $sortkey, $pageLength, $isRedirect = false ) {
-               global $wgContLang, $wgExperimentalCategorySort;
+               global $wgContLang;
                $this->articles[] = $isRedirect
                        ? '<span class="redirect-in-category">' .
                                $this->getSkin()->link(
@@ -238,29 +224,22 @@ class CategoryViewer {
                                ) . '</span>'
                        : $this->getSkin()->link( $title );
 
-               if ( $wgExperimentalCategorySort ) {
-                       $this->articles_start_char[] = $wgContLang->convert( $wgContLang->firstLetterForLists( $sortkey ) );
-               } else {
-                       $this->articles_start_char[] = $wgContLang->convert( $wgContLang->firstChar( $sortkey ) );
-               }
+               $this->articles_start_char[] = $wgContLang->convert( $wgContLang->firstLetterForLists( $sortkey ) );
        }
 
        function finaliseCategoryState() {
-               global $wgExperimentalCategorySort;
-               if ( ( !$wgExperimentalCategorySort && $this->flip )
-                 || ( $wgExperimentalCategorySort && $this->flip['subcat'] ) ) {
+               if ( $this->flip['subcat'] ) {
                        $this->children            = array_reverse( $this->children );
                        $this->children_start_char = array_reverse( $this->children_start_char );
                }
-               if ( ( !$wgExperimentalCategorySort && $this->flip )
-                 || ( $wgExperimentalCategorySort && $this->flip['page'] ) ) {
+               if ( $this->flip['page'] ) {
                        $this->articles            = array_reverse( $this->articles );
                        $this->articles_start_char = array_reverse( $this->articles_start_char );
                }
        }
 
        function doCategoryQuery() {
-               global $wgExperimentalCategorySort, $wgContLang;
+               global $wgContLang;
 
                $dbr = wfGetDB( DB_SLAVE, 'category' );
 
@@ -276,107 +255,56 @@ class CategoryViewer {
                $joins = array( 'categorylinks'  => array( 'INNER JOIN', 'cl_from = page_id' ),
                        'category' => array( 'LEFT JOIN', 'cat_title = page_title AND page_namespace = ' . NS_CATEGORY ) );
 
-               if ( $wgExperimentalCategorySort ) {
-                       # Copy-pasted from below, but that's okay, because the stuff below
-                       # will be deleted when this becomes the default.
-                       $this->nextPage = array(
-                               'page' => null,
-                               'subcat' => null,
-                               'file' => null,
-                       );
-                       $this->flip = array( 'page' => false, 'subcat' => false, 'file' => false );
-
-                       foreach ( array( 'page', 'subcat', 'file' ) as $type ) {
-                               # Get the sortkeys for start/end, if applicable.  Note that if
-                               # the collation in the database differs from the one
-                               # $wgContLang is using, pagination might go totally haywire.
-                               $extraConds = array( 'cl_type' => $type );
-                               if ( $this->from[$type] !== null ) {
-                                       $extraConds[] = 'cl_sortkey >= '
-                                               . $dbr->addQuotes( $wgContLang->convertToSortkey( $this->from[$type] ) );
-                               } elseif ( $this->until[$type] !== null ) {
-                                       $extraConds[] = 'cl_sortkey < '
-                                               . $dbr->addQuotes( $wgContLang->convertToSortkey( $this->until[$type] ) );
-                                       $this->flip[$type] = true;
-                               }
-
-                               $res = $dbr->select(
-                                       $tables,
-                                       array_merge( $fields, array( 'cl_sortkey_prefix' ) ),
-                                       $conds + $extraConds,
-                                       __METHOD__,
-                                       $opts + array( 'ORDER BY' => $this->flip[$type] ? 'cl_sortkey DESC' : 'cl_sortkey' ),
-                                       $joins
-                               );
-
-                               $count = 0;
-                               foreach ( $res as $row ) {
-                                       $title = Title::newFromRow( $row );
-                                       $rawSortkey = $title->getCategorySortkey( $row->cl_sortkey_prefix );
-
-                                       if ( ++$count > $this->limit ) {
-                                               # We've reached the one extra which shows that there
-                                               # are additional pages to be had. Stop here...
-                                               $this->nextPage[$type] = $rawSortkey;
-                                               break;
-                                       }
-
-                                       if ( $title->getNamespace() == NS_CATEGORY ) {
-                                               $cat = Category::newFromRow( $row, $title );
-                                               $this->addSubcategoryObject( $cat, $rawSortkey, $row->page_len );
-                                       } elseif ( $this->showGallery && $title->getNamespace() == NS_FILE ) {
-                                               $this->addImage( $title, $rawSortkey, $row->page_len, $row->page_is_redirect );
-                                       } else {
-                                               $this->addPage( $title, $rawSortkey, $row->page_len, $row->page_is_redirect );
-                                       }
-                               }
-                       }
-
-                       return;
-               }
-
-               # Non-$wgExperimentalCategorySort stuff
-
-               if ( $this->from != '' ) {
-                       $pageCondition = 'cl_sortkey >= ' . $dbr->addQuotes( $this->from );
-                       $this->flip = false;
-               } elseif ( $this->until != '' ) {
-                       $pageCondition = 'cl_sortkey < ' . $dbr->addQuotes( $this->until );
-                       $this->flip = true;
-               } else {
-                       $pageCondition = '1 = 1';
-                       $this->flip = false;
-               }
-
-               $res = $dbr->select(
-                       $tables,
-                       $fields,
-                       $conds + array( $pageCondition ),
-                       __METHOD__,
-                       $opts + array( 'ORDER BY' => $this->flip ? 'cl_sortkey DESC' : 'cl_sortkey' ),
-                       $joins
+               $this->nextPage = array(
+                       'page' => null,
+                       'subcat' => null,
+                       'file' => null,
                );
+               $this->flip = array( 'page' => false, 'subcat' => false, 'file' => false );
+
+               foreach ( array( 'page', 'subcat', 'file' ) as $type ) {
+                       # Get the sortkeys for start/end, if applicable.  Note that if
+                       # the collation in the database differs from the one
+                       # $wgContLang is using, pagination might go totally haywire.
+                       $extraConds = array( 'cl_type' => $type );
+                       if ( $this->from[$type] !== null ) {
+                               $extraConds[] = 'cl_sortkey >= '
+                                       . $dbr->addQuotes( $wgContLang->convertToSortkey( $this->from[$type] ) );
+                       } elseif ( $this->until[$type] !== null ) {
+                               $extraConds[] = 'cl_sortkey < '
+                                       . $dbr->addQuotes( $wgContLang->convertToSortkey( $this->until[$type] ) );
+                               $this->flip[$type] = true;
+                       }
 
-               $count = 0;
-               $this->nextPage = null;
+                       $res = $dbr->select(
+                               $tables,
+                               array_merge( $fields, array( 'cl_sortkey_prefix' ) ),
+                               $conds + $extraConds,
+                               __METHOD__,
+                               $opts + array( 'ORDER BY' => $this->flip[$type] ? 'cl_sortkey DESC' : 'cl_sortkey' ),
+                               $joins
+                       );
 
-               foreach ( $res as $row ) {
-                       if ( ++$count > $this->limit ) {
-                               // We've reached the one extra which shows that there are
-                               // additional pages to be had. Stop here...
-                               $this->nextPage = $row->cl_sortkey;
-                               break;
-                       }
+                       $count = 0;
+                       foreach ( $res as $row ) {
+                               $title = Title::newFromRow( $row );
+                               $rawSortkey = $title->getCategorySortkey( $row->cl_sortkey_prefix );
 
-                       $title = Title::newFromRow( $row );
+                               if ( ++$count > $this->limit ) {
+                                       # We've reached the one extra which shows that there
+                                       # are additional pages to be had. Stop here...
+                                       $this->nextPage[$type] = $rawSortkey;
+                                       break;
+                               }
 
-                       if ( $title->getNamespace() == NS_CATEGORY ) {
-                               $cat = Category::newFromRow( $row, $title );
-                               $this->addSubcategoryObject( $cat, $row->cl_sortkey, $row->page_len );
-                       } elseif ( $this->showGallery && $title->getNamespace() == NS_FILE ) {
-                               $this->addImage( $title, $row->cl_sortkey, $row->page_len, $row->page_is_redirect );
-                       } else {
-                               $this->addPage( $title, $row->cl_sortkey, $row->page_len, $row->page_is_redirect );
+                               if ( $title->getNamespace() == NS_CATEGORY ) {
+                                       $cat = Category::newFromRow( $row, $title );
+                                       $this->addSubcategoryObject( $cat, $rawSortkey, $row->page_len );
+                               } elseif ( $this->showGallery && $title->getNamespace() == NS_FILE ) {
+                                       $this->addImage( $title, $rawSortkey, $row->page_len, $row->page_is_redirect );
+                               } else {
+                                       $this->addPage( $title, $rawSortkey, $row->page_len, $row->page_is_redirect );
+                               }
                        }
                }
        }
@@ -460,10 +388,6 @@ class CategoryViewer {
         * @return String: HTML output, possibly empty if there are no other pages
         */
        private function getSectionPagingLinks( $type ) {
-               global $wgExperimentalCategorySort;
-               if ( !$wgExperimentalCategorySort ) {
-                       return '';
-               }
                if ( $this->until[$type] !== null ) {
                        return $this->pagingLinks( $this->nextPage[$type], $this->until[$type], $type );
                } elseif ( $this->nextPage[$type] !== null || $this->from[$type] !== null ) {
@@ -474,18 +398,7 @@ class CategoryViewer {
        }
 
        function getCategoryBottom() {
-               global $wgExperimentalCategorySort;
-               if ( $wgExperimentalCategorySort ) {
-                       # We have per-section paging links, no global ones.
-                       return '';
-               }
-               if ( $this->until != '' ) {
-                       return $this->pagingLinks( $this->nextPage, $this->until );
-               } elseif ( $this->nextPage != '' || $this->from != '' ) {
-                       return $this->pagingLinks( $this->from, $this->nextPage );
-               } else {
-                       return '';
-               }
+               return '';
        }
 
        /**
index e60d817..9191402 100644 (file)
@@ -4472,16 +4472,6 @@ $wgCategoryPagingLimit = 200;
  */
 $wgCategoryPrefixedDefaultSortkey = true;
 
-/**
- * Enable experimental support for non-braindead collation on category pages.
- * For this to work, you need to alter your categorylinks table by applying
- * maintenance/archives/patch-categorylinks-better-collation.sql, then keep
- * up-to-date with changes that are made to that file (they won't be
- * automatically applied).  You should also set $wgUseDumbLinkUpdate = true and
- * run maintenance/refreshLinks.php.
- */
-$wgExperimentalCategorySort = false;
-
 /**
  * A version indicator for collations that will be stored in cl_collation for
  * all new rows.  Used when the collation algorithm changes: a script checks
index b7ad29c..5fb7c05 100644 (file)
@@ -426,57 +426,48 @@ class LinksUpdate {
         * @private
         */
        function getCategoryInsertions( $existing = array() ) {
-               global $wgContLang, $wgExperimentalCategorySort, $wgCollationVersion;
+               global $wgContLang, $wgCollationVersion;
                $diffs = array_diff_assoc( $this->mCategories, $existing );
                $arr = array();
                foreach ( $diffs as $name => $sortkey ) {
                        $nt = Title::makeTitleSafe( NS_CATEGORY, $name );
                        $wgContLang->findVariantLink( $name, $nt, true );
 
-                       if ( $wgExperimentalCategorySort ) {
-                               if ( $this->mTitle->getNamespace() == NS_CATEGORY ) {
-                                       $type = 'subcat';
-                               } elseif ( $this->mTitle->getNamespace() == NS_FILE ) {
-                                       $type = 'file';
-                               } else {
-                                       $type = 'page';
-                               }
-
-                               # TODO: This is kind of wrong, because someone might set a sort
-                               # key prefix that's the same as the default sortkey for the
-                               # title.  This should be fixed by refactoring code to replace
-                               # $sortkey in this array by a prefix, but it's basically harmless
-                               # (Title::moveTo() has had the same issue for a long time).
-                               if ( $this->mTitle->getCategorySortkey() == $sortkey ) {
-                                       $prefix = '';
-                                       $sortkey = $wgContLang->convertToSortkey( $sortkey );
-                               } else {
-                                       # Treat custom sortkeys as a prefix, so that if multiple
-                                       # things are forced to sort as '*' or something, they'll
-                                       # sort properly in the category rather than in page_id
-                                       # order or such.
-                                       $prefix = $sortkey;
-                                       $sortkey = $wgContLang->convertToSortkey(
-                                               $this->mTitle->getCategorySortkey( $prefix ) );
-                               }
+                       if ( $this->mTitle->getNamespace() == NS_CATEGORY ) {
+                               $type = 'subcat';
+                       } elseif ( $this->mTitle->getNamespace() == NS_FILE ) {
+                               $type = 'file';
+                       } else {
+                               $type = 'page';
+                       }
 
-                               $arr[] = array(
-                                       'cl_from'    => $this->mId,
-                                       'cl_to'      => $name,
-                                       'cl_sortkey' => $sortkey,
-                                       'cl_timestamp' => $this->mDb->timestamp(),
-                                       'cl_sortkey_prefix' => $prefix,
-                                       'cl_collation' => $wgCollationVersion,
-                                       'cl_type' => $type,
-                               );
+                       # TODO: This is kind of wrong, because someone might set a sort
+                       # key prefix that's the same as the default sortkey for the
+                       # title.  This should be fixed by refactoring code to replace
+                       # $sortkey in this array by a prefix, but it's basically harmless
+                       # (Title::moveTo() has had the same issue for a long time).
+                       if ( $this->mTitle->getCategorySortkey() == $sortkey ) {
+                               $prefix = '';
+                               $sortkey = $wgContLang->convertToSortkey( $sortkey );
                        } else {
-                               $arr[] = array(
-                                       'cl_from'    => $this->mId,
-                                       'cl_to'      => $name,
-                                       'cl_sortkey' => $sortkey,
-                                       'cl_timestamp' => $this->mDb->timestamp()
-                               );
+                               # Treat custom sortkeys as a prefix, so that if multiple
+                               # things are forced to sort as '*' or something, they'll
+                               # sort properly in the category rather than in page_id
+                               # order or such.
+                               $prefix = $sortkey;
+                               $sortkey = $wgContLang->convertToSortkey(
+                                       $this->mTitle->getCategorySortkey( $prefix ) );
                        }
+
+                       $arr[] = array(
+                               'cl_from'    => $this->mId,
+                               'cl_to'      => $name,
+                               'cl_sortkey' => $sortkey,
+                               'cl_timestamp' => $this->mDb->timestamp(),
+                               'cl_sortkey_prefix' => $prefix,
+                               'cl_collation' => $wgCollationVersion,
+                               'cl_type' => $type,
+                       );
                }
                return $arr;
        }
index 03b2dfd..3111ae5 100644 (file)
@@ -158,6 +158,8 @@ class MysqlUpdater extends DatabaseUpdater {
                                array( 'add_field', 'interwiki',     'iw_api',           'patch-iw_api_and_wikiid.sql' ),
                                array( 'drop_index_if_exists', 'iwlinks', 'iwl_prefix',  'patch-kill-iwl_prefix.sql' ),
                                array( 'drop_index_if_exists', 'iwlinks', 'iwl_prefix_from_title', 'patch-kill-iwl_pft.sql' ),
+                               array( 'add_field', 'categorylinks', 'cl_collation', 'patch-categorylinks-better-collation.sql' ),
+                               array( 'do_collation_update' ),
                        ),
                );
        }
index 5722a33..ad41f08 100644 (file)
@@ -1,12 +1,7 @@
 --
 -- patch-categorylinks-better-collation.sql
 --
--- Bugs 164, 1211, 23682.  This is currently experimental and subject to
--- change.  You need to set $wgExperimentalCategorySort = true; to use this.
--- You also need to manually apply any changes that are made to this file,
--- since they will not be automatically applied.  This patch is only intended
--- to work for MySQL for now, without table prefixes, possibly other random
--- limitations.
+-- Bugs 164, 1211, 23682.
 ALTER TABLE categorylinks
        ADD COLUMN cl_sortkey_prefix varchar(255) binary NOT NULL default '',
        ADD COLUMN cl_collation tinyint NOT NULL default 0,
index 60578ce..c41d95c 100644 (file)
@@ -37,7 +37,7 @@ TEXT;
                        __METHOD__
                );
 
-               $this->output( "Fixing around $count rows (estimate might be wrong).\n" );
+               $this->output( "Fixing collation for around $count rows (estimate might be wrong).\n" );
 
                $count = 0;
                do {
index 7efe3a6..748d46f 100644 (file)
@@ -1086,6 +1086,21 @@ function do_populate_rev_len() {
        $task->execute();
 }
 
+function do_collation_update() {
+       global $wgDatabase, $wgCollationVersion;
+       if ( $wgDatabase->selectField(
+               'categorylinks',
+               'COUNT(*)',
+               'cl_collation != ' . $wgDatabase->addQuotes( $wgCollationVersion ),
+               __FUNCTION__
+       ) == 0 ) {
+               wfOut( "...collations up-to-date.\n" );
+       }
+       require_once( 'updateCollation.php' );
+       $task = new UpdateCollation();
+       $task->execute();
+}
+
 function sqlite_initial_indexes() {
        global $wgDatabase;
        // initial-indexes.sql fails if the indexes are already present, so we perform a quick check if our database is newer.