Localisation updates for core messages from Betawiki (2008-06-23 22:55 CEST)
[lhc/web/wiklou.git] / includes / Category.php
1 <?php
2 /**
3 * Category objects are immutable, strictly speaking. If you call methods that change the database, like to refresh link counts, the objects will be appropriately reinitialized. Member variables are lazy-initialized.
4 *
5 * TODO: Move some stuff from CategoryPage.php to here, and use that.
6 *
7 * @author Simetrical
8 */
9
10 class Category {
11 /** Name of the category, normalized to DB-key form */
12 private $mName = null;
13 private $mID = null;
14 /** Counts of membership (cat_pages, cat_subcats, cat_files) */
15 private $mPages = null, $mSubcats = null, $mFiles = null;
16
17 private function __construct() {}
18
19 /**
20 * Set up all member variables using a database query.
21 * @return bool True on success, false on failure.
22 */
23 protected function initialize() {
24 if( $this->mName === null && $this->mID === null ) {
25 throw new MWException( __METHOD__.' has both names and IDs null' );
26 }
27 $dbr = wfGetDB( DB_SLAVE );
28 if( $this->mID === null ) {
29 $where = array( 'cat_title' => $this->mName );
30 } elseif( $this->mName === null ) {
31 $where = array( 'cat_id' => $this->mID );
32 } else {
33 # Already initialized
34 return true;
35 }
36 $row = $dbr->selectRow(
37 'category',
38 array( 'cat_id', 'cat_title', 'cat_pages', 'cat_subcats',
39 'cat_files' ),
40 $where,
41 __METHOD__
42 );
43 if( !$row ) {
44 # Okay, there were no contents. Nothing to initialize.
45 return false;
46 }
47 $this->mID = $row->cat_id;
48 $this->mName = $row->cat_title;
49 $this->mPages = $row->cat_pages;
50 $this->mSubcats = $row->cat_subcats;
51 $this->mFiles = $row->cat_files;
52
53 # (bug 13683) If the count is negative, then 1) it's obviously wrong
54 # and should not be kept, and 2) we *probably* don't have to scan many
55 # rows to obtain the correct figure, so let's risk a one-time recount.
56 if( $this->mPages < 0 || $this->mSubcats < 0 ||
57 $this->mFiles < 0 ) {
58 $this->refreshCounts();
59 }
60
61 return true;
62 }
63
64 /**
65 * Factory function.
66 *
67 * @param array $name A category name (no "Category:" prefix). It need
68 * not be normalized, with spaces replaced by underscores.
69 * @return mixed Category, or false on a totally invalid name
70 */
71 public static function newFromName( $name ) {
72 $cat = new self();
73 $title = Title::newFromText( "Category:$name" );
74 if( !is_object( $title ) ) {
75 return false;
76 }
77 $cat->mName = $title->getDBKey();
78
79 return $cat;
80 }
81
82 /**
83 * Factory function.
84 *
85 * @param array $id A category id
86 * @return Category
87 */
88 public static function newFromID( $id ) {
89 $cat = new self();
90 $cat->mID = intval( $id );
91 return $cat;
92 }
93
94 /** @return mixed DB key name, or false on failure */
95 public function getName() { return $this->getX( 'mName' ); }
96 /** @return mixed Category ID, or false on failure */
97 public function getID() { return $this->getX( 'mID' ); }
98 /** @return mixed Total number of member pages, or false on failure */
99 public function getPageCount() { return $this->getX( 'mPages' ); }
100 /** @return mixed Number of subcategories, or false on failure */
101 public function getSubcatCount() { return $this->getX( 'mSubcats' ); }
102 /** @return mixed Number of member files, or false on failure */
103 public function getFileCount() { return $this->getX( 'mFiles' ); }
104
105 /**
106 * @return mixed The Title for this category, or false on failure.
107 */
108 public function getTitle() {
109 if( !$this->initialize() ) {
110 return false;
111 }
112 return Title::makeTitleSafe( NS_CATEGORY, $this->mName );
113 }
114
115 /** Generic accessor */
116 private function getX( $key ) {
117 if( !$this->initialize() ) {
118 return false;
119 }
120 return $this->{$key};
121 }
122
123 /**
124 * Refresh the counts for this category.
125 *
126 * @return bool True on success, false on failure
127 */
128 public function refreshCounts() {
129 if( wfReadOnly() ) {
130 return false;
131 }
132 $dbw = wfGetDB( DB_MASTER );
133 $dbw->begin();
134 # Note, we must use names for this, since categorylinks does.
135 if( $this->mName === null ) {
136 if( !$this->initialize() ) {
137 return false;
138 }
139 } else {
140 # Let's be sure that the row exists in the table. We don't need to
141 # do this if we got the row from the table in initialization!
142 $dbw->insert(
143 'category',
144 array( 'cat_title' => $this->mName ),
145 __METHOD__,
146 'IGNORE'
147 );
148 }
149
150 $cond1 = $dbw->conditional( 'page_namespace='.NS_CATEGORY, 1, 'NULL' );
151 $cond2 = $dbw->conditional( 'page_namespace='.NS_IMAGE, 1, 'NULL' );
152 $result = $dbw->selectRow(
153 array( 'categorylinks', 'page' ),
154 array( 'COUNT(*) AS pages',
155 "COUNT($cond1) AS subcats",
156 "COUNT($cond2) AS files"
157 ),
158 array( 'cl_to' => $this->mName, 'page_id = cl_from' ),
159 __METHOD__,
160 'LOCK IN SHARE MODE'
161 );
162 $ret = $dbw->update(
163 'category',
164 array(
165 'cat_pages' => $result->pages,
166 'cat_subcats' => $result->subcats,
167 'cat_files' => $result->files
168 ),
169 array( 'cat_title' => $this->mName ),
170 __METHOD__
171 );
172 $dbw->commit();
173
174 # Now we should update our local counts.
175 $this->mPages = $result->pages;
176 $this->mSubcats = $result->subcats;
177 $this->mFiles = $result->files;
178
179 return $ret;
180 }
181 }