Index: trunk/phase3/includes/api/ApiQuery.php |
— | — | @@ -33,6 +33,7 @@ |
34 | 34 | |
35 | 35 | private $mPropModuleNames, $mListModuleNames, $mMetaModuleNames; |
36 | 36 | private $mPageSet; |
| 37 | + private $mValidNamespaces; |
37 | 38 | |
38 | 39 | private $mQueryPropModules = array ( |
39 | 40 | 'info' => 'ApiQueryInfo', |
— | — | @@ -69,6 +70,7 @@ |
70 | 71 | $this->mPropModuleNames = array_keys($this->mQueryPropModules); |
71 | 72 | $this->mListModuleNames = array_keys($this->mQueryListModules); |
72 | 73 | $this->mMetaModuleNames = array_keys($this->mQueryMetaModules); |
| 74 | + $this->mValidNamespaces = null; |
73 | 75 | |
74 | 76 | // Allow the entire list of modules at first, |
75 | 77 | // but during module instantiation check if it can be used as a generator. |
— | — | @@ -85,6 +87,19 @@ |
86 | 88 | return $this->mPageSet; |
87 | 89 | } |
88 | 90 | |
| 91 | + public function getValidNamespaces() { |
| 92 | + global $wgContLang; |
| 93 | + |
| 94 | + if (is_null($this->mValidNamespaces)) { |
| 95 | + $this->mValidNamespaces = array (); |
| 96 | + foreach (array_keys($wgContLang->getNamespaces()) as $ns) { |
| 97 | + if ($ns >= 0) |
| 98 | + $this->mValidNamespaces[] = $ns; // strval($ns); |
| 99 | + } |
| 100 | + } |
| 101 | + return $this->mValidNamespaces; |
| 102 | + } |
| 103 | + |
89 | 104 | /** |
90 | 105 | * Query execution happens in the following steps: |
91 | 106 | * #1 Create a PageSet object with any pages requested by the user |
Index: trunk/phase3/includes/api/ApiQueryRevisions.php |
— | — | @@ -76,7 +76,7 @@ |
77 | 77 | 'rev_text_id', |
78 | 78 | 'rev_minor_edit' |
79 | 79 | ); |
80 | | - $conds = array ( |
| 80 | + $where = array ( |
81 | 81 | 'rev_deleted' => 0 |
82 | 82 | ); |
83 | 83 | $options = array (); |
— | — | @@ -100,7 +100,7 @@ |
101 | 101 | break; |
102 | 102 | case 'content' : |
103 | 103 | $tables[] = 'text'; |
104 | | - $conds[] = 'rev_text_id=old_id'; |
| 104 | + $where[] = 'rev_text_id=old_id'; |
105 | 105 | $fields[] = 'old_id'; |
106 | 106 | $fields[] = 'old_text'; |
107 | 107 | $fields[] = 'old_flags'; |
— | — | @@ -136,13 +136,13 @@ |
137 | 137 | $after = ($dirNewer ? '>=' : '<='); |
138 | 138 | |
139 | 139 | if ($startid !== 0) |
140 | | - $conds[] = 'rev_id' . $after . intval($startid); |
| 140 | + $where[] = 'rev_id' . $after . intval($startid); |
141 | 141 | if ($endid !== 0) |
142 | | - $conds[] = 'rev_id' . $before . intval($endid); |
| 142 | + $where[] = 'rev_id' . $before . intval($endid); |
143 | 143 | if (isset ($start)) |
144 | | - $conds[] = 'rev_timestamp' . $after . $db->addQuotes($start); |
| 144 | + $where[] = 'rev_timestamp' . $after . $db->addQuotes($start); |
145 | 145 | if (isset ($end)) |
146 | | - $conds[] = 'rev_timestamp' . $before . $db->addQuotes($end); |
| 146 | + $where[] = 'rev_timestamp' . $before . $db->addQuotes($end); |
147 | 147 | |
148 | 148 | // must manually initialize unset limit |
149 | 149 | if (!isset ($limit)) |
— | — | @@ -151,19 +151,19 @@ |
152 | 152 | $this->validateLimit($this->encodeParamName('limit'), $limit, 1, $userMax, $botMax); |
153 | 153 | |
154 | 154 | // There is only one ID, use it |
155 | | - $conds['rev_page'] = array_pop(array_keys($pageSet->getGoodTitles())); |
| 155 | + $where['rev_page'] = array_pop(array_keys($pageSet->getGoodTitles())); |
156 | 156 | |
157 | 157 | } |
158 | 158 | elseif ($pageCount > 0) { |
159 | 159 | // When working in multi-page non-enumeration mode, |
160 | 160 | // limit to the latest revision only |
161 | 161 | $tables[] = 'page'; |
162 | | - $conds[] = 'page_id=rev_page'; |
163 | | - $conds[] = 'page_latest=rev_id'; |
| 162 | + $where[] = 'page_id=rev_page'; |
| 163 | + $where[] = 'page_latest=rev_id'; |
164 | 164 | $this->validateLimit('page_count', $pageCount, 1, $userMax, $botMax); |
165 | 165 | |
166 | 166 | // Get all page IDs |
167 | | - $conds['page_id'] = array_keys($pageSet->getGoodTitles()); |
| 167 | + $where['page_id'] = array_keys($pageSet->getGoodTitles()); |
168 | 168 | |
169 | 169 | $limit = $pageCount; // assumption testing -- we should never get more then $pageCount rows. |
170 | 170 | } |
— | — | @@ -171,7 +171,7 @@ |
172 | 172 | $this->validateLimit('rev_count', $revCount, 1, $userMax, $botMax); |
173 | 173 | |
174 | 174 | // Get all revision IDs |
175 | | - $conds['rev_id'] = array_keys($pageSet->getRevisionIDs()); |
| 175 | + $where['rev_id'] = array_keys($pageSet->getRevisionIDs()); |
176 | 176 | |
177 | 177 | $limit = $revCount; // assumption testing -- we should never get more then $revCount rows. |
178 | 178 | } else |
— | — | @@ -180,7 +180,7 @@ |
181 | 181 | $options['LIMIT'] = $limit +1; |
182 | 182 | |
183 | 183 | $this->profileDBIn(); |
184 | | - $res = $db->select($tables, $fields, $conds, __METHOD__, $options); |
| 184 | + $res = $db->select($tables, $fields, $where, __METHOD__, $options); |
185 | 185 | $this->profileDBOut(); |
186 | 186 | |
187 | 187 | $data = array (); |
Index: trunk/phase3/includes/api/ApiQueryAllpages.php |
— | — | @@ -42,7 +42,7 @@ |
43 | 43 | public function executeGenerator($resultPageSet) { |
44 | 44 | if ($resultPageSet->isResolvingRedirects()) |
45 | 45 | $this->dieUsage('Use "gapfilterredir=nonredirects" option instead of "redirects" when using allpages as a generator', 'params'); |
46 | | - |
| 46 | + |
47 | 47 | $this->run($resultPageSet); |
48 | 48 | } |
49 | 49 | |
— | — | @@ -55,11 +55,11 @@ |
56 | 56 | $where = array ( |
57 | 57 | 'page_namespace' => $namespace |
58 | 58 | ); |
59 | | - |
| 59 | + |
60 | 60 | if (isset ($from)) { |
61 | 61 | $where[] = 'page_title>=' . $db->addQuotes(ApiQueryBase :: titleToKey($from)); |
62 | 62 | } |
63 | | - |
| 63 | + |
64 | 64 | if ($filterredir === 'redirects') { |
65 | 65 | $where['page_is_redirect'] = 1; |
66 | 66 | } |
— | — | @@ -77,12 +77,14 @@ |
78 | 78 | $fields = $resultPageSet->getPageTableFields(); |
79 | 79 | } |
80 | 80 | |
81 | | - $this->profileDBIn(); |
82 | | - $res = $db->select('page', $fields, $where, __CLASS__ . '::' . __METHOD__, array ( |
| 81 | + $options = array ( |
83 | 82 | 'USE INDEX' => 'name_title', |
84 | 83 | 'LIMIT' => $limit +1, |
85 | 84 | 'ORDER BY' => 'page_namespace, page_title' |
86 | | - )); |
| 85 | + ); |
| 86 | + |
| 87 | + $this->profileDBIn(); |
| 88 | + $res = $db->select('page', $fields, $where, __METHOD__, $options); |
87 | 89 | $this->profileDBOut(); |
88 | 90 | |
89 | 91 | $data = array (); |
— | — | @@ -103,7 +105,10 @@ |
104 | 106 | |
105 | 107 | if (is_null($resultPageSet)) { |
106 | 108 | $id = intval($row->page_id); |
107 | | - $data[] = $id; // in generator mode, just assemble a list of page IDs. |
| 109 | + $data[$id] = array ( |
| 110 | + 'id' => $id, |
| 111 | + 'ns' => $title->getNamespace(), |
| 112 | + 'title' => $title->getPrefixedText()); |
108 | 113 | } else { |
109 | 114 | $resultPageSet->processDbRow($row); |
110 | 115 | } |
— | — | @@ -119,35 +124,25 @@ |
120 | 125 | |
121 | 126 | protected function getAllowedParams() { |
122 | 127 | |
123 | | - global $wgContLang; |
124 | | - $validNamespaces = array (); |
125 | | - foreach (array_keys($wgContLang->getNamespaces()) as $ns) { |
126 | | - if ($ns >= 0) |
127 | | - $validNamespaces[] = $ns; // strval($ns); |
128 | | - } |
129 | | - |
130 | 128 | return array ( |
131 | 129 | 'from' => null, |
132 | 130 | 'namespace' => array ( |
133 | 131 | ApiBase :: PARAM_DFLT => 0, |
134 | | - ApiBase :: PARAM_TYPE => $validNamespaces |
135 | | - ), |
| 132 | + ApiBase :: PARAM_TYPE => $this->getQuery()->getValidNamespaces()), |
136 | 133 | 'filterredir' => array ( |
137 | 134 | ApiBase :: PARAM_DFLT => 'all', |
138 | 135 | ApiBase :: PARAM_TYPE => array ( |
139 | 136 | 'all', |
140 | 137 | 'redirects', |
141 | 138 | 'nonredirects' |
142 | | - ) |
143 | | - ), |
| 139 | + )), |
144 | 140 | 'limit' => array ( |
145 | 141 | ApiBase :: PARAM_DFLT => 10, |
146 | 142 | ApiBase :: PARAM_TYPE => 'limit', |
147 | 143 | ApiBase :: PARAM_MIN => 1, |
148 | 144 | ApiBase :: PARAM_MAX1 => 500, |
149 | 145 | ApiBase :: PARAM_MAX2 => 5000 |
150 | | - ) |
151 | | - ); |
| 146 | + )); |
152 | 147 | } |
153 | 148 | |
154 | 149 | protected function getParamDescription() { |
Index: trunk/phase3/includes/api/ApiMain.php |
— | — | @@ -51,6 +51,9 @@ |
52 | 52 | $this->mResult = new ApiResult($this); |
53 | 53 | $this->mShowVersions = false; |
54 | 54 | $this->mEnableWrite = $enableWrite; |
| 55 | + |
| 56 | + // Initialize Error handler |
| 57 | + set_exception_handler( array($this, 'exceptionHandler') ); |
55 | 58 | } |
56 | 59 | |
57 | 60 | public function & getResult() { |
— | — | @@ -107,12 +110,7 @@ |
108 | 111 | $this->printResult(false); |
109 | 112 | |
110 | 113 | } catch (UsageException $e) { |
111 | | - |
112 | | - // Printer may not be initialized if the extractRequestParams() fails for the main module |
113 | | - if (!isset ($this->mPrinter)) |
114 | | - $this->mPrinter = new $this->mFormats[API_DEFAULT_FORMAT] ($this, API_DEFAULT_FORMAT); |
115 | | - $this->printResult(true); |
116 | | - |
| 114 | + $this->printError(); |
117 | 115 | } |
118 | 116 | $this->profileOut(); |
119 | 117 | } |
— | — | @@ -130,6 +128,13 @@ |
131 | 129 | $printer->closePrinter(); |
132 | 130 | $printer->profileOut(); |
133 | 131 | } |
| 132 | + |
| 133 | + private function printError() { |
| 134 | + // Printer may not be initialized if the extractRequestParams() fails for the main module |
| 135 | + if (!isset ($this->mPrinter)) |
| 136 | + $this->mPrinter = new $this->mFormats[API_DEFAULT_FORMAT] ($this, API_DEFAULT_FORMAT); |
| 137 | + $this->printResult(true); |
| 138 | + } |
134 | 139 | |
135 | 140 | protected function getDescription() { |
136 | 141 | return array ( |
— | — | @@ -141,22 +146,29 @@ |
142 | 147 | } |
143 | 148 | |
144 | 149 | public function mainDieUsage($description, $errorCode, $httpRespCode = 0) { |
145 | | - $this->mResult->Reset(); |
146 | 150 | if ($httpRespCode === 0) |
147 | 151 | header($errorCode, true); |
148 | 152 | else |
149 | 153 | header($errorCode, true, $httpRespCode); |
150 | 154 | |
| 155 | + $this->makeErrorMessage($description, $errorCode); |
| 156 | + |
| 157 | + throw new UsageException($description, $errorCode); |
| 158 | + } |
| 159 | + |
| 160 | + public function makeErrorMessage($description, $errorCode, $customContent = null) { |
| 161 | + $this->mResult->Reset(); |
151 | 162 | $data = array ( |
152 | 163 | 'code' => $errorCode, |
153 | 164 | 'info' => $description |
154 | 165 | ); |
155 | | - ApiResult :: setContent($data, $this->makeHelpMsg()); |
| 166 | + |
| 167 | + ApiResult :: setContent($data, |
| 168 | + is_null($customContent) ? $this->makeHelpMsg() : $customContent); |
| 169 | + |
156 | 170 | $this->mResult->addValue(null, 'error', $data); |
157 | | - |
158 | | - throw new UsageException($description, $errorCode); |
159 | 171 | } |
160 | | - |
| 172 | + |
161 | 173 | /** |
162 | 174 | * Override the parent to generate help messages for all available modules. |
163 | 175 | */ |
— | — | @@ -188,7 +200,54 @@ |
189 | 201 | |
190 | 202 | return $msg; |
191 | 203 | } |
| 204 | + |
| 205 | + /** |
| 206 | + * Exception handler which simulates the appropriate catch() handling: |
| 207 | + * |
| 208 | + * try { |
| 209 | + * ... |
| 210 | + * } catch ( MWException $e ) { |
| 211 | + * dieUsage() |
| 212 | + * } catch ( Exception $e ) { |
| 213 | + * echo $e->__toString(); |
| 214 | + * } |
| 215 | + * |
| 216 | + * |
| 217 | + * |
| 218 | + * |
| 219 | + * !!!!!!!!!!!!! REVIEW needed !!!!!!!!!!!!!!!!!! |
| 220 | + * |
| 221 | + * this method needs to be reviewed/cleaned up |
| 222 | + * |
| 223 | + * |
| 224 | + * |
| 225 | + */ |
| 226 | + public function exceptionHandler( $e ) { |
| 227 | + global $wgFullyInitialised; |
| 228 | + if ( is_a( $e, 'MWException' ) ) { |
| 229 | + try { |
| 230 | + $msg = "Exception Caught: {$e->getMessage()}"; |
| 231 | + $this->makeErrorMessage($msg, 'internal_error', "\n\n{$e->getTraceAsString()}\n\n"); |
| 232 | + $this->printError(); |
| 233 | + } catch (Exception $e2) { |
| 234 | + echo $e->__toString(); |
| 235 | + } |
| 236 | + } else { |
| 237 | + echo $e->__toString(); |
| 238 | + } |
192 | 239 | |
| 240 | + // Final cleanup, similar to wfErrorExit() |
| 241 | + if ( $wgFullyInitialised ) { |
| 242 | + try { |
| 243 | + wfLogProfilingData(); // uses $wgRequest, hence the $wgFullyInitialised condition |
| 244 | + } catch ( Exception $e ) {} |
| 245 | + } |
| 246 | + |
| 247 | + // Exit value should be nonzero for the benefit of shell jobs |
| 248 | + exit( 1 ); |
| 249 | + } |
| 250 | + |
| 251 | + |
193 | 252 | private $mIsBot = null; |
194 | 253 | public function isBot() { |
195 | 254 | if (!isset ($this->mIsBot)) { |