00001 <?php 00012 class Category { 00014 private $mName = null; 00015 private $mID = null; 00017 private $mTitle = null; 00019 private $mPages = null, $mSubcats = null, $mFiles = null; 00020 00021 private function __construct() { } 00022 00027 protected function initialize() { 00028 if ( $this->mName === null && $this->mTitle ) 00029 $this->mName = $title->getDBkey(); 00030 00031 if ( $this->mName === null && $this->mID === null ) { 00032 throw new MWException( __METHOD__ . ' has both names and IDs null' ); 00033 } elseif ( $this->mID === null ) { 00034 $where = array( 'cat_title' => $this->mName ); 00035 } elseif ( $this->mName === null ) { 00036 $where = array( 'cat_id' => $this->mID ); 00037 } else { 00038 # Already initialized 00039 return true; 00040 } 00041 $dbr = wfGetDB( DB_SLAVE ); 00042 $row = $dbr->selectRow( 00043 'category', 00044 array( 'cat_id', 'cat_title', 'cat_pages', 'cat_subcats', 'cat_files' ), 00045 $where, 00046 __METHOD__ 00047 ); 00048 00049 if ( !$row ) { 00050 # Okay, there were no contents. Nothing to initialize. 00051 if ( $this->mTitle ) { 00052 # If there is a title object but no record in the category table, treat this as an empty category 00053 $this->mID = false; 00054 $this->mName = $this->mTitle->getDBkey(); 00055 $this->mPages = 0; 00056 $this->mSubcats = 0; 00057 $this->mFiles = 0; 00058 00059 return true; 00060 } else { 00061 return false; # Fail 00062 } 00063 } 00064 00065 $this->mID = $row->cat_id; 00066 $this->mName = $row->cat_title; 00067 $this->mPages = $row->cat_pages; 00068 $this->mSubcats = $row->cat_subcats; 00069 $this->mFiles = $row->cat_files; 00070 00071 # (bug 13683) If the count is negative, then 1) it's obviously wrong 00072 # and should not be kept, and 2) we *probably* don't have to scan many 00073 # rows to obtain the correct figure, so let's risk a one-time recount. 00074 if ( $this->mPages < 0 || $this->mSubcats < 0 || $this->mFiles < 0 ) { 00075 $this->refreshCounts(); 00076 } 00077 00078 return true; 00079 } 00080 00088 public static function newFromName( $name ) { 00089 $cat = new self(); 00090 $title = Title::makeTitleSafe( NS_CATEGORY, $name ); 00091 00092 if ( !is_object( $title ) ) { 00093 return false; 00094 } 00095 00096 $cat->mTitle = $title; 00097 $cat->mName = $title->getDBkey(); 00098 00099 return $cat; 00100 } 00101 00108 public static function newFromTitle( $title ) { 00109 $cat = new self(); 00110 00111 $cat->mTitle = $title; 00112 $cat->mName = $title->getDBkey(); 00113 00114 return $cat; 00115 } 00116 00123 public static function newFromID( $id ) { 00124 $cat = new self(); 00125 $cat->mID = intval( $id ); 00126 return $cat; 00127 } 00128 00139 public static function newFromRow( $row, $title = null ) { 00140 $cat = new self(); 00141 $cat->mTitle = $title; 00142 00143 # NOTE: the row often results from a LEFT JOIN on categorylinks. This may result in 00144 # all the cat_xxx fields being null, if the category page exists, but nothing 00145 # was ever added to the category. This case should be treated linke an empty 00146 # category, if possible. 00147 00148 if ( $row->cat_title === null ) { 00149 if ( $title === null ) { 00150 # the name is probably somewhere in the row, for example as page_title, 00151 # but we can't know that here... 00152 return false; 00153 } else { 00154 $cat->mName = $title->getDBkey(); # if we have a title object, fetch the category name from there 00155 } 00156 00157 $cat->mID = false; 00158 $cat->mSubcats = 0; 00159 $cat->mPages = 0; 00160 $cat->mFiles = 0; 00161 } else { 00162 $cat->mName = $row->cat_title; 00163 $cat->mID = $row->cat_id; 00164 $cat->mSubcats = $row->cat_subcats; 00165 $cat->mPages = $row->cat_pages; 00166 $cat->mFiles = $row->cat_files; 00167 } 00168 00169 return $cat; 00170 } 00171 00173 public function getName() { return $this->getX( 'mName' ); } 00174 00176 public function getID() { return $this->getX( 'mID' ); } 00177 00179 public function getPageCount() { return $this->getX( 'mPages' ); } 00180 00182 public function getSubcatCount() { return $this->getX( 'mSubcats' ); } 00183 00185 public function getFileCount() { return $this->getX( 'mFiles' ); } 00186 00190 public function getTitle() { 00191 if ( $this->mTitle ) return $this->mTitle; 00192 00193 if ( !$this->initialize() ) { 00194 return false; 00195 } 00196 00197 $this->mTitle = Title::makeTitleSafe( NS_CATEGORY, $this->mName ); 00198 return $this->mTitle; 00199 } 00200 00208 public function getMembers( $limit = false, $offset = '' ) { 00209 $dbr = wfGetDB( DB_SLAVE ); 00210 00211 $conds = array( 'cl_to' => $this->getName(), 'cl_from = page_id' ); 00212 $options = array( 'ORDER BY' => 'cl_sortkey' ); 00213 00214 if ( $limit ) { 00215 $options[ 'LIMIT' ] = $limit; 00216 } 00217 00218 if ( $offset !== '' ) { 00219 $conds[] = 'cl_sortkey > ' . $dbr->addQuotes( $offset ); 00220 } 00221 00222 return TitleArray::newFromResult( 00223 $dbr->select( 00224 array( 'page', 'categorylinks' ), 00225 array( 'page_id', 'page_namespace', 'page_title', 'page_len', 00226 'page_is_redirect', 'page_latest' ), 00227 $conds, 00228 __METHOD__, 00229 $options 00230 ) 00231 ); 00232 } 00233 00235 private function getX( $key ) { 00236 if ( !$this->initialize() ) { 00237 return false; 00238 } 00239 return $this-> { $key } ; 00240 } 00241 00247 public function refreshCounts() { 00248 if ( wfReadOnly() ) { 00249 return false; 00250 } 00251 $dbw = wfGetDB( DB_MASTER ); 00252 $dbw->begin(); 00253 # Note, we must use names for this, since categorylinks does. 00254 if ( $this->mName === null ) { 00255 if ( !$this->initialize() ) { 00256 return false; 00257 } 00258 } else { 00259 # Let's be sure that the row exists in the table. We don't need to 00260 # do this if we got the row from the table in initialization! 00261 $seqVal = $dbw->nextSequenceValue( 'category_cat_id_seq' ); 00262 $dbw->insert( 00263 'category', 00264 array( 00265 'cat_id' => $seqVal, 00266 'cat_title' => $this->mName 00267 ), 00268 __METHOD__, 00269 'IGNORE' 00270 ); 00271 } 00272 00273 $cond1 = $dbw->conditional( 'page_namespace=' . NS_CATEGORY, 1, 'NULL' ); 00274 $cond2 = $dbw->conditional( 'page_namespace=' . NS_FILE, 1, 'NULL' ); 00275 $result = $dbw->selectRow( 00276 array( 'categorylinks', 'page' ), 00277 array( 'COUNT(*) AS pages', 00278 "COUNT($cond1) AS subcats", 00279 "COUNT($cond2) AS files" 00280 ), 00281 array( 'cl_to' => $this->mName, 'page_id = cl_from' ), 00282 __METHOD__, 00283 'LOCK IN SHARE MODE' 00284 ); 00285 $ret = $dbw->update( 00286 'category', 00287 array( 00288 'cat_pages' => $result->pages, 00289 'cat_subcats' => $result->subcats, 00290 'cat_files' => $result->files 00291 ), 00292 array( 'cat_title' => $this->mName ), 00293 __METHOD__ 00294 ); 00295 $dbw->commit(); 00296 00297 # Now we should update our local counts. 00298 $this->mPages = $result->pages; 00299 $this->mSubcats = $result->subcats; 00300 $this->mFiles = $result->files; 00301 00302 return $ret; 00303 } 00304 }