Add categorylinks table to separately list category relationships. Actual
authorBrion Vibber <brion@users.mediawiki.org>
Sat, 15 May 2004 00:29:39 +0000 (00:29 +0000)
committerBrion Vibber <brion@users.mediawiki.org>
Sat, 15 May 2004 00:29:39 +0000 (00:29 +0000)
_page_ links to category pages like [[:category:Some cat]] will stay in
links/brokenlinks and not be listed in the category page list anymore.

A link can optionally specify a sort key like this: [[category:cat|Sort me]].
The page will then be sorted in category lists according to the given text
instead of the page name; thus categories may be sorted arbitrarily, by
last name or whatever.

There is also a timestamp field included on gwicke's request; this is not
used yet. Also it will currently be updated at every edit of the page,
this can be changed by implementing differential updating for the cat links.

TODO:
* Make sure that automatic sort keys are updated on page rename.
* Make sure cateory pages get cache-invalidated and purged
* Use proper text sorting instead of raw binary sort
* Allow specification of the display style on category pages: comma list
  or bullet list or number list; by sortkey or by timestamp; etc

config/index.php
includes/Article.php
includes/LinkCache.php
includes/LinksUpdate.php
includes/Parser.php
maintenance/archives/patch-categorylinks.sql [new file with mode: 0644]
maintenance/archives/patch-list.txt
maintenance/tables.sql
maintenance/updaters.inc

index 907856a..2c189a4 100644 (file)
@@ -403,6 +403,7 @@ if( $conf->posted && ( 0 == count( $errs ) ) ) {
                        do_user_real_name_update(); flush();
                        do_querycache_update(); flush();
                        do_objectcache_update(); flush();
+                       do_categorylinks_update(); flush();
                        initialiseMessages(); flush();
                        chdir( "config" );
                        
index dd1b38d..6ccdb7b 100644 (file)
@@ -1282,6 +1282,9 @@ class Article {
                $sql = "DELETE FROM brokenlinks WHERE bl_from={$id}";
                wfQuery( $sql, DB_WRITE, $fname );
                
+               $sql = "DELETE FROM categorylinks WHERE cl_from={$id}";
+               wfQuery( $sql, DB_WRITE, $fname );
+               
                $log = new LogPage( wfMsg( "dellogpage" ), wfMsg( "dellogpagetext" ) );
                $art = $this->mTitle->getPrefixedText();
                $log->addEntry( wfMsg( "deletedarticle", $art ), $reason );
index 0c50c7d..8f41ccc 100644 (file)
@@ -9,10 +9,10 @@ define ('LINKCACHE_IMAGE', 2);
 class LinkCache {      
        // Increment $mClassVer whenever old serialized versions of this class
        // becomes incompatible with the new version.
-       /* private */ var $mClassVer = 1; 
+       /* private */ var $mClassVer = 2;
 
        /* private */ var $mGoodLinks, $mBadLinks, $mActive;
-       /* private */ var $mImageLinks
+       /* private */ var $mImageLinks, $mCategoryLinks;
        /* private */ var $mPreFilled, $mOldGoodLinks, $mOldBadLinks;
        
        /* private */ function getKey( $title ) {
@@ -27,6 +27,7 @@ class LinkCache {
                $this->mGoodLinks = array();
                $this->mBadLinks = array();
                $this->mImageLinks = array();
+               $this->mCategoryLinks = array();
                $this->mOldGoodLinks = array();
                $this->mOldBadLinks = array();
        }
@@ -68,6 +69,14 @@ class LinkCache {
        {
                if ( $this->mActive ) { $this->mImageLinks[$nt->getDBkey()] = 1; }
        }
+       
+       function addCategoryLink( $title, $sortkey ) {
+               if ( $this->mActive ) { $this->mCategoryLinks[$title] = $sortkey; }
+       }
+       
+       function addCategoryLinkObj( &$nt, $sortkey ) {
+               $this->addCategoryLink( $nt->getDBkey(), $sortkey );
+       }
 
        function clearBadLink( $title )
        {
@@ -87,6 +96,7 @@ class LinkCache {
        function getGoodLinks() { return $this->mGoodLinks; }
        function getBadLinks() { return array_keys( $this->mBadLinks ); }
        function getImageLinks() { return $this->mImageLinks; }
+       function getCategoryLinks() { return $this->mCategoryLinks; }
 
        function addLink( $title )
        {
index fe39d36..104e442 100644 (file)
@@ -16,7 +16,7 @@ class LinksUpdate {
        function doUpdate()
        {
                global $wgUseBetterLinksUpdate, $wgLinkCache, $wgDBtransactions;
-               global $wgEnablePersistentLC;
+               global $wgEnablePersistentLC, $wgUseCategoryMagic;
 
                /* Update link tables with outgoing links from an updated article */
                /* Relies on the 'link cache' to be filled out */
@@ -133,6 +133,36 @@ class LinksUpdate {
                }
                if ( "" != $sql ) { wfQuery( $sql, DB_WRITE, $fname ); }
 
+               #------------------------------------------------------------------------------
+               # Category links
+               if( $wgUseCategoryMagic ) {
+                       $sql = "DELETE FROM categorylinks WHERE cl_from='{$this->mId}'";
+                       wfQuery( $sql, DB_WRITE, $fname );
+                       
+                       # Get addition list
+                       $add = $wgLinkCache->getCategoryLinks();
+                       
+                       # Do the insertion
+                       $sql = "";
+                       if ( 0 != count ( $add ) ) {
+                               $sql = "INSERT INTO categorylinks (cl_from,cl_to,cl_sortkey) VALUES ";
+                               $first = true;
+                               foreach( $add as $cname => $sortkey ) {
+                                       # FIXME: Change all this to avoid unnecessary duplication
+                                       $nt = Title::makeTitle( NS_CATEGORY, $cname );
+                                       if( !$nt ) continue;
+                                       $nt->invalidateCache();
+       
+                                       if ( ! $first ) { $sql .= ","; }
+                                       $first = false;
+       
+                                       $sql .= "({$this->mId},'" . wfStrencode( $cname ) .
+                                               "','" . wfStrencode( $sortkey ) . "')";
+                               }
+                       }
+                       if ( "" != $sql ) { wfQuery( $sql, DB_WRITE, $fname ); }
+               }
+               
                $this->fixBrokenLinks();
 
                if( $wgDBtransactions ) {
@@ -147,7 +177,7 @@ class LinksUpdate {
                # Old inefficient update function
                # Used for rebuilding the link table
                
-               global $wgLinkCache, $wgDBtransactions;
+               global $wgLinkCache, $wgDBtransactions, $wgUseCategoryMagic;
                $fname = "LinksUpdate::doDumbUpdate";
                wfProfileIn( $fname );
 
@@ -209,6 +239,33 @@ class LinksUpdate {
                }
                if ( "" != $sql ) { wfQuery( $sql, DB_WRITE, $fname ); }
 
+               if( $wgUseCategoryMagic ) {
+                       $sql = "DELETE FROM categorylinks WHERE cl_from='{$this->mId}'";
+                       wfQuery( $sql, DB_WRITE, $fname );
+                       
+                       # Get addition list
+                       $add = $wgLinkCache->getCategoryLinks();
+                       
+                       # Do the insertion
+                       $sql = "";
+                       if ( 0 != count ( $add ) ) {
+                               $sql = "INSERT INTO categorylinks (cl_from,cl_to,cl_sortkey) VALUES ";
+                               $first = true;
+                               foreach( $add as $cname => $sortkey ) {
+                                       # FIXME: Change all this to avoid unnecessary duplication
+                                       $nt = Title::makeTitle( NS_CATEGORY, $cname );
+                                       if( !$nt ) continue;
+                                       $nt->invalidateCache();
+       
+                                       if ( ! $first ) { $sql .= ","; }
+                                       $first = false;
+       
+                                       $sql .= "({$this->mId},'" . wfStrencode( $cname ) .
+                                               "','" . wfStrencode( $sortkey ) . "')";
+                               }
+                       }
+                       if ( "" != $sql ) { wfQuery( $sql, DB_WRITE, $fname ); }
+               }
                $this->fixBrokenLinks();
 
                if( $wgDBtransactions ) {
index e292278..c345e28 100644 (file)
@@ -316,18 +316,11 @@ class Parser
                $data = array () ;
                $id = $this->mTitle->getArticleID() ;
 
-               # For existing categories
-               if( $id ) {
-                       $sql = "SELECT DISTINCT cur_title,cur_namespace FROM cur,links WHERE l_to={$id} AND l_from=cur_id";
-                       $res = wfQuery ( $sql, DB_READ ) ;
-                       while ( $x = wfFetchObject ( $res ) ) $data[] = $x ;
-               } else {
-                       # For non-existing categories
-                       $t = wfStrencode( $this->mTitle->getPrefixedDBKey() );
-                       $sql = "SELECT DISTINCT cur_title,cur_namespace FROM cur,brokenlinks WHERE bl_to='$t' AND bl_from=cur_id" ;
-                       $res = wfQuery ( $sql, DB_READ ) ;
-                       while ( $x = wfFetchObject ( $res ) ) $data[] = $x ;
-               }
+               # FIXME: add limits
+               $t = wfStrencode( $this->mTitle->getDBKey() );
+               $sql = "SELECT DISTINCT cur_title,cur_namespace FROM cur,categorylinks WHERE cl_to='$t' AND cl_from=cur_id ORDER BY cl_sortkey" ;
+               $res = wfQuery ( $sql, DB_READ ) ;
+               while ( $x = wfFetchObject ( $res ) ) $data[] = $x ;
 
                # For all pages that link to this category
                foreach ( $data AS $x )
@@ -345,18 +338,14 @@ class Parser
                wfFreeResult ( $res ) ;
 
                # Showing subcategories
-               if ( count ( $children ) > 0 )
-               {
-                       asort ( $children ) ;
+               if ( count ( $children ) > 0 ) {
                        $r .= "<h2>".wfMsg("subcategories")."</h2>\n" ;
                        $r .= implode ( ", " , $children ) ;
                }
 
                # Showing pages in this category
-               if ( count ( $articles ) > 0 )
-               {
+               if ( count ( $articles ) > 0 ) {
                        $ti = $this->mTitle->getText() ;
-                       asort ( $articles ) ;
                        $h =  wfMsg( "category_header", $ti );
                        $r .= "<h2>{$h}</h2>\n" ;
                        $r .= implode ( ", " , $articles ) ;
@@ -570,9 +559,9 @@ class Parser
                $text = $sk->transformContent( $text );
 
                if ( !isset ( $this->categoryMagicDone ) ) {
-                  $text .= $this->categoryMagic () ;
-                  $this->categoryMagicDone = true ;
-                  }
+                       $text .= $this->categoryMagic () ;
+                       $this->categoryMagicDone = true ;
+               }
 
                wfProfileOut( $fname );
                return $text;
@@ -1021,7 +1010,8 @@ class Parser
                } else {
                        $link = substr( $m[1], 1 );
                }
-               if( "" == $text )
+               $wasblank = ( "" == $text );
+               if( $wasblank )
                        $text = $link;
 
                $nt = Title::newFromText( $link );
@@ -1045,7 +1035,13 @@ class Parser
                        if ( $ns == $category ) {
                                $t = $nt->getText() ;
                                $nnt = Title::newFromText ( Namespace::getCanonicalName($category).":".$t ) ;
+                               
+                               $wgLinkCache->suspend(); # Don't save in links/brokenlinks
                                $t = $sk->makeLinkObj( $nnt, $t, "", "" , $prefix );
+                               $wgLinkCache->resume();
+                               
+                               $sortkey = $wasblank ? $this->mTitle->getPrefixedText() : $text;
+                               $wgLinkCache->addCategoryLinkObj( $nt, $sortkey );
                                $this->mOutput->mCategoryLinks[] = $t ;
                                $s .= $prefix . $trail ;
                                return $s ;
diff --git a/maintenance/archives/patch-categorylinks.sql b/maintenance/archives/patch-categorylinks.sql
new file mode 100644 (file)
index 0000000..962a0ad
--- /dev/null
@@ -0,0 +1,15 @@
+--
+-- Track category inclusions *used inline*
+-- cl_from keys to cur_id, cl_to keys to cur_title of the category page.
+-- cl_sortkey is the title of the linking page or an optional override
+-- cl_timestamp marks when the link was last added
+--
+CREATE TABLE categorylinks (
+  cl_from int(8) unsigned NOT NULL default '0',
+  cl_to varchar(255) binary NOT NULL default '',
+  cl_sortkey varchar(255) binary NOT NULL default '',
+  cl_timestamp timestamp NOT NULL,
+  UNIQUE KEY cl_from(cl_from,cl_to),
+  KEY cl_sortkey(cl_to,cl_sortkey(128)),
+  KEY cl_timestamp(cl_to,cl_timestamp)
+);
index 2585672..93a63bf 100644 (file)
@@ -177,3 +177,6 @@ patch-user-realname.sql
        object cache to cover some slow operations w/o memcached.
 patch-querycache.sql
 patch-objectcache.sql
+
+* 2004-05-14: Add categorylinks table for handling category membership
+patch-categorylinks.sql
index 3e15e1d..d149298 100644 (file)
@@ -104,6 +104,22 @@ CREATE TABLE imagelinks (
   KEY (il_to)
 );
 
+--
+-- Track category inclusions *used inline*
+-- cl_from keys to cur_id, cl_to keys to cur_title of the category page.
+-- cl_sortkey is the title of the linking page or an optional override
+-- cl_timestamp marks when the link was last added
+--
+CREATE TABLE categorylinks (
+  cl_from int(8) unsigned NOT NULL default '0',
+  cl_to varchar(255) binary NOT NULL default '',
+  cl_sortkey varchar(255) binary NOT NULL default '',
+  cl_timestamp timestamp NOT NULL,
+  UNIQUE KEY cl_from(cl_from,cl_to),
+  KEY cl_sortkey(cl_to,cl_sortkey(128)),
+  KEY cl_timestamp(cl_to,cl_timestamp)
+);
+
 --
 -- Stores (possibly gzipped) serialized objects with
 -- cache arrays to reduce database load slurping up
index 9509c0a..d557ebb 100644 (file)
@@ -156,4 +156,15 @@ function do_objectcache_update() {
        }
 }
 
+function do_categorylinks_update() {
+       global $wgDatabase;
+       if( $wgDatabase->tableExists( "categorylinks" ) ) {
+               echo "...have categorylinks table.\n";
+       } else {
+               echo "Adding categorylinks table for category management... ";
+               dbsource( "maintenance/archives/patch-categorylinks.sql", $wgDatabase );
+               echo "ok\n";
+       }
+}
+
 ?>
\ No newline at end of file