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 if( !$row ) { 00049 # Okay, there were no contents. Nothing to initialize. 00050 if ( $this->mTitle ) { 00051 # If there is a title object but no record in the category table, treat this as an empty category 00052 $this->mID = false; 00053 $this->mName = $this->mTitle->getDBKey(); 00054 $this->mPages = 0; 00055 $this->mSubcats = 0; 00056 $this->mFiles = 0; 00057 00058 return true; 00059 } else { 00060 return false; # Fail 00061 } 00062 } 00063 $this->mID = $row->cat_id; 00064 $this->mName = $row->cat_title; 00065 $this->mPages = $row->cat_pages; 00066 $this->mSubcats = $row->cat_subcats; 00067 $this->mFiles = $row->cat_files; 00068 00069 # (bug 13683) If the count is negative, then 1) it's obviously wrong 00070 # and should not be kept, and 2) we *probably* don't have to scan many 00071 # rows to obtain the correct figure, so let's risk a one-time recount. 00072 if( $this->mPages < 0 || $this->mSubcats < 0 || $this->mFiles < 0 ) { 00073 $this->refreshCounts(); 00074 } 00075 00076 return true; 00077 } 00078 00086 public static function newFromName( $name ) { 00087 $cat = new self(); 00088 $title = Title::makeTitleSafe( NS_CATEGORY, $name ); 00089 if( !is_object( $title ) ) { 00090 return false; 00091 } 00092 00093 $cat->mTitle = $title; 00094 $cat->mName = $title->getDBKey(); 00095 00096 return $cat; 00097 } 00098 00105 public static function newFromTitle( $title ) { 00106 $cat = new self(); 00107 00108 $cat->mTitle = $title; 00109 $cat->mName = $title->getDBKey(); 00110 00111 return $cat; 00112 } 00113 00120 public static function newFromID( $id ) { 00121 $cat = new self(); 00122 $cat->mID = intval( $id ); 00123 return $cat; 00124 } 00125 00136 public static function newFromRow( $row, $title = null ) { 00137 $cat = new self(); 00138 $cat->mTitle = $title; 00139 00140 00141 # NOTE: the row often results from a LEFT JOIN on categorylinks. This may result in 00142 # all the cat_xxx fields being null, if the category page exists, but nothing 00143 # was ever added to the category. This case should be treated linke an empty 00144 # category, if possible. 00145 00146 if ( $row->cat_title === null ) { 00147 if ( $title === null ) { 00148 # the name is probably somewhere in the row, for example as page_title, 00149 # but we can't know that here... 00150 return false; 00151 } else { 00152 $cat->mName = $title->getDBKey(); # if we have a title object, fetch the category name from there 00153 } 00154 00155 $cat->mID = false; 00156 $cat->mSubcats = 0; 00157 $cat->mPages = 0; 00158 $cat->mFiles = 0; 00159 } else { 00160 $cat->mName = $row->cat_title; 00161 $cat->mID = $row->cat_id; 00162 $cat->mSubcats = $row->cat_subcats; 00163 $cat->mPages = $row->cat_pages; 00164 $cat->mFiles = $row->cat_files; 00165 } 00166 00167 return $cat; 00168 } 00169 00171 public function getName() { return $this->getX( 'mName' ); } 00173 public function getID() { return $this->getX( 'mID' ); } 00175 public function getPageCount() { return $this->getX( 'mPages' ); } 00177 public function getSubcatCount() { return $this->getX( 'mSubcats' ); } 00179 public function getFileCount() { return $this->getX( 'mFiles' ); } 00180 00184 public function getTitle() { 00185 if( $this->mTitle ) return $this->mTitle; 00186 00187 if( !$this->initialize() ) { 00188 return false; 00189 } 00190 00191 $this->mTitle = Title::makeTitleSafe( NS_CATEGORY, $this->mName ); 00192 return $this->mTitle; 00193 } 00194 00202 public function getMembers( $limit = false, $offset = '' ) { 00203 $dbr = wfGetDB( DB_SLAVE ); 00204 00205 $conds = array( 'cl_to' => $this->getName(), 'cl_from = page_id' ); 00206 $options = array( 'ORDER BY' => 'cl_sortkey' ); 00207 if( $limit ) $options[ 'LIMIT' ] = $limit; 00208 if( $offset !== '' ) $conds[] = 'cl_sortkey > ' . $dbr->addQuotes( $offset ); 00209 00210 return TitleArray::newFromResult( 00211 $dbr->select( 00212 array( 'page', 'categorylinks' ), 00213 array( 'page_id', 'page_namespace','page_title', 'page_len', 00214 'page_is_redirect', 'page_latest' ), 00215 $conds, 00216 __METHOD__, 00217 $options 00218 ) 00219 ); 00220 } 00221 00223 private function getX( $key ) { 00224 if( !$this->initialize() ) { 00225 return false; 00226 } 00227 return $this->{$key}; 00228 } 00229 00235 public function refreshCounts() { 00236 if( wfReadOnly() ) { 00237 return false; 00238 } 00239 $dbw = wfGetDB( DB_MASTER ); 00240 $dbw->begin(); 00241 # Note, we must use names for this, since categorylinks does. 00242 if( $this->mName === null ) { 00243 if( !$this->initialize() ) { 00244 return false; 00245 } 00246 } else { 00247 # Let's be sure that the row exists in the table. We don't need to 00248 # do this if we got the row from the table in initialization! 00249 $dbw->insert( 00250 'category', 00251 array( 'cat_title' => $this->mName ), 00252 __METHOD__, 00253 'IGNORE' 00254 ); 00255 } 00256 00257 $cond1 = $dbw->conditional( 'page_namespace='.NS_CATEGORY, 1, 'NULL' ); 00258 $cond2 = $dbw->conditional( 'page_namespace='.NS_FILE, 1, 'NULL' ); 00259 $result = $dbw->selectRow( 00260 array( 'categorylinks', 'page' ), 00261 array( 'COUNT(*) AS pages', 00262 "COUNT($cond1) AS subcats", 00263 "COUNT($cond2) AS files" 00264 ), 00265 array( 'cl_to' => $this->mName, 'page_id = cl_from' ), 00266 __METHOD__, 00267 'LOCK IN SHARE MODE' 00268 ); 00269 $ret = $dbw->update( 00270 'category', 00271 array( 00272 'cat_pages' => $result->pages, 00273 'cat_subcats' => $result->subcats, 00274 'cat_files' => $result->files 00275 ), 00276 array( 'cat_title' => $this->mName ), 00277 __METHOD__ 00278 ); 00279 $dbw->commit(); 00280 00281 # Now we should update our local counts. 00282 $this->mPages = $result->pages; 00283 $this->mSubcats = $result->subcats; 00284 $this->mFiles = $result->files; 00285 00286 return $ret; 00287 } 00288 }