Index: trunk/phase3/includes/Category.php |
— | — | @@ -11,6 +11,8 @@ |
12 | 12 | /** Name of the category, normalized to DB-key form */ |
13 | 13 | private $mName = null; |
14 | 14 | private $mID = null; |
| 15 | + /** Category page title */ |
| 16 | + private $mTitle = null; |
15 | 17 | /** Counts of membership (cat_pages, cat_subcats, cat_files) */ |
16 | 18 | private $mPages = null, $mSubcats = null, $mFiles = null; |
17 | 19 | |
— | — | @@ -21,11 +23,12 @@ |
22 | 24 | * @return bool True on success, false on failure. |
23 | 25 | */ |
24 | 26 | protected function initialize() { |
| 27 | + if ( $this->mName === null && $this->mTitle ) |
| 28 | + $this->mName = $title->getDBKey(); |
| 29 | + |
25 | 30 | if( $this->mName === null && $this->mID === null ) { |
26 | 31 | throw new MWException( __METHOD__.' has both names and IDs null' ); |
27 | | - } |
28 | | - $dbr = wfGetDB( DB_SLAVE ); |
29 | | - if( $this->mID === null ) { |
| 32 | + } elseif( $this->mID === null ) { |
30 | 33 | $where = array( 'cat_title' => $this->mName ); |
31 | 34 | } elseif( $this->mName === null ) { |
32 | 35 | $where = array( 'cat_id' => $this->mID ); |
— | — | @@ -33,6 +36,7 @@ |
34 | 37 | # Already initialized |
35 | 38 | return true; |
36 | 39 | } |
| 40 | + $dbr = wfGetDB( DB_SLAVE ); |
37 | 41 | $row = $dbr->selectRow( |
38 | 42 | 'category', |
39 | 43 | array( 'cat_id', 'cat_title', 'cat_pages', 'cat_subcats', |
— | — | @@ -70,10 +74,12 @@ |
71 | 75 | */ |
72 | 76 | public static function newFromName( $name ) { |
73 | 77 | $cat = new self(); |
74 | | - $title = Title::newFromText( "Category:$name" ); |
| 78 | + $title = Title::makeTitleSafe( NS_CATEGORY, $name ); |
75 | 79 | if( !is_object( $title ) ) { |
76 | 80 | return false; |
77 | 81 | } |
| 82 | + |
| 83 | + $cat->mTitle = $title; |
78 | 84 | $cat->mName = $title->getDBKey(); |
79 | 85 | |
80 | 86 | return $cat; |
— | — | @@ -82,6 +88,21 @@ |
83 | 89 | /** |
84 | 90 | * Factory function. |
85 | 91 | * |
| 92 | + * @param array $title Title for the category page |
| 93 | + * @return mixed Category, or false on a totally invalid name |
| 94 | + */ |
| 95 | + public static function newFromTitle( $title ) { |
| 96 | + $cat = new self(); |
| 97 | + |
| 98 | + $cat->mTitle = $title; |
| 99 | + $cat->mName = $title->getDBKey(); |
| 100 | + |
| 101 | + return $cat; |
| 102 | + } |
| 103 | + |
| 104 | + /** |
| 105 | + * Factory function. |
| 106 | + * |
86 | 107 | * @param array $id A category id |
87 | 108 | * @return Category |
88 | 109 | */ |
— | — | @@ -91,6 +112,50 @@ |
92 | 113 | return $cat; |
93 | 114 | } |
94 | 115 | |
| 116 | + /** |
| 117 | + * Factory function, for constructing a Category object from a result set |
| 118 | + * |
| 119 | + * @param $row result set row, must contain the cat_xxx fields. If the fields are null, |
| 120 | + * the resulting Category object will represent an empty category if a title object |
| 121 | + * was given. If the fields are null and no title was given, this method fails and returns false. |
| 122 | + * @param $title optional title object for the category represented by the given row. |
| 123 | + * May be provided if it is already known, to avoid having to re-create a title object later. |
| 124 | + * @return Category |
| 125 | + */ |
| 126 | + public static function newFromRow( $row, $title = null ) { |
| 127 | + $cat->mTitle = $title; |
| 128 | + |
| 129 | + $cat = new self(); |
| 130 | + |
| 131 | + # NOTE: the row often results from a LEFT JOIN on categorylinks. This may result in |
| 132 | + # all the cat_xxx fields being null, if the category page exists, but nothing |
| 133 | + # was ever added to the category. This case should be treated linke an empty |
| 134 | + # category, if possible. |
| 135 | + |
| 136 | + if ( $row->cat_title === null ) { |
| 137 | + if ( $title === null ) { |
| 138 | + # the name is probably somewhere in the row, for example as page_title, |
| 139 | + # but we can't know that here... |
| 140 | + return false; |
| 141 | + } else { |
| 142 | + $cat->mName = $title->getDBKey(); # if we have a title object, fetch the category name from there |
| 143 | + } |
| 144 | + |
| 145 | + $cat->mID = false; |
| 146 | + $cat->mSubcats = 0; |
| 147 | + $cat->mPages = 0; |
| 148 | + $cat->mFiles = 0; |
| 149 | + } else { |
| 150 | + $cat->mName = $row->cat_title; |
| 151 | + $cat->mID = $row->cat_id; |
| 152 | + $cat->mSubcats = $row->cat_subcats; |
| 153 | + $cat->mPages = $row->cat_pages; |
| 154 | + $cat->mFiles = $row->cat_files; |
| 155 | + } |
| 156 | + |
| 157 | + return $cat; |
| 158 | + } |
| 159 | + |
95 | 160 | /** @return mixed DB key name, or false on failure */ |
96 | 161 | public function getName() { return $this->getX( 'mName' ); } |
97 | 162 | /** @return mixed Category ID, or false on failure */ |
— | — | @@ -106,10 +171,14 @@ |
107 | 172 | * @return mixed The Title for this category, or false on failure. |
108 | 173 | */ |
109 | 174 | public function getTitle() { |
| 175 | + if( $this->mTitle ) return $this->mTitle; |
| 176 | + |
110 | 177 | if( !$this->initialize() ) { |
111 | 178 | return false; |
112 | 179 | } |
113 | | - return Title::makeTitleSafe( NS_CATEGORY, $this->mName ); |
| 180 | + |
| 181 | + $this->mTitle = Title::makeTitleSafe( NS_CATEGORY, $this->mName ); |
| 182 | + return $this->mTitle; |
114 | 183 | } |
115 | 184 | |
116 | 185 | /** Generic accessor */ |
Index: trunk/phase3/includes/CategoryPage.php |
— | — | @@ -135,8 +135,17 @@ |
136 | 136 | } |
137 | 137 | |
138 | 138 | /** |
139 | | - * Add a subcategory to the internal lists |
| 139 | + * Add a subcategory to the internal lists, using a Category object |
140 | 140 | */ |
| 141 | + function addSubcategoryObject( $cat, $sortkey, $pageLength ) { |
| 142 | + $title = $cat->getTitle(); |
| 143 | + $this->addSubcategory( $title, $sortkey, $pageLength ); |
| 144 | + } |
| 145 | + |
| 146 | + /** |
| 147 | + * Add a subcategory to the internal lists, using a title object |
| 148 | + * @deprectated kept for compatibility, please use addSubcategoryObject instead |
| 149 | + */ |
141 | 150 | function addSubcategory( $title, $sortkey, $pageLength ) { |
142 | 151 | global $wgContLang; |
143 | 152 | // Subcategory; strip the 'Category' namespace from the link text. |
— | — | @@ -213,17 +222,17 @@ |
214 | 223 | $this->flip = false; |
215 | 224 | } |
216 | 225 | $res = $dbr->select( |
217 | | - array( 'page', 'categorylinks' ), |
218 | | - array( 'page_title', 'page_namespace', 'page_len', 'page_is_redirect', 'cl_sortkey' ), |
| 226 | + array( 'page', 'categorylinks', 'category' ), |
| 227 | + array( 'page_title', 'page_namespace', 'page_len', 'page_is_redirect', 'cl_sortkey', |
| 228 | + 'cat_id', 'cat_title', 'cat_subcats', 'cat_pages', 'cat_files' ), |
219 | 229 | array( $pageCondition, |
220 | | - 'cl_from = page_id', |
221 | | - 'cl_to' => $this->title->getDBkey()), |
222 | | - #'page_is_redirect' => 0), |
223 | | - #+ $pageCondition, |
| 230 | + 'cl_to' => $this->title->getDBkey() ), |
224 | 231 | __METHOD__, |
225 | 232 | array( 'ORDER BY' => $this->flip ? 'cl_sortkey DESC' : 'cl_sortkey', |
226 | | - 'USE INDEX' => 'cl_sortkey', |
227 | | - 'LIMIT' => $this->limit + 1 ) ); |
| 233 | + 'USE INDEX' => array( 'categorylinks' => 'cl_sortkey' ), |
| 234 | + 'LIMIT' => $this->limit + 1 ), |
| 235 | + array( 'categorylinks' => array( 'INNER JOIN', 'cl_from = page_id' ), |
| 236 | + 'category' => array( 'LEFT JOIN', 'cat_title = page_title AND page_namespace = ' . NS_CATEGORY ) ) ); |
228 | 237 | |
229 | 238 | $count = 0; |
230 | 239 | $this->nextPage = null; |
— | — | @@ -238,7 +247,8 @@ |
239 | 248 | $title = Title::makeTitle( $x->page_namespace, $x->page_title ); |
240 | 249 | |
241 | 250 | if( $title->getNamespace() == NS_CATEGORY ) { |
242 | | - $this->addSubcategory( $title, $x->cl_sortkey, $x->page_len ); |
| 251 | + $cat = Category::newFromRow( $x, $title ); |
| 252 | + $this->addSubcategoryObject( $cat, $x->cl_sortkey, $x->page_len ); |
243 | 253 | } elseif( $this->showGallery && $title->getNamespace() == NS_IMAGE ) { |
244 | 254 | $this->addImage( $title, $x->cl_sortkey, $x->page_len, $x->page_is_redirect ); |
245 | 255 | } else { |