Index: trunk/extensions/GeoData/GeoData.sql |
— | — | @@ -2,6 +2,8 @@ |
3 | 3 | |
4 | 4 | -- Stores information about geographical coordinates in articles |
5 | 5 | CREATE TABLE /*_*/geo_tags ( |
| 6 | + -- Tag id, needed for selective replacement and paging |
| 7 | + gt_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, |
6 | 8 | -- page_id |
7 | 9 | gt_page_id int unsigned NOT NULL, |
8 | 10 | -- Name of planet or other astronomic body on which the coordinates reside |
Index: trunk/extensions/GeoData/GeoData.body.php |
— | — | @@ -17,21 +17,36 @@ |
18 | 18 | /** |
19 | 19 | * Returns primary coordinates of the given page, if any |
20 | 20 | * @param Title $title |
21 | | - * @return Coord: Coordinates or false |
| 21 | + * @return Coord|false: Coordinates or false |
22 | 22 | */ |
23 | 23 | public static function getPageCoordinates( Title $title ) { |
24 | | - $dbr = wfGetDB( DB_SLAVE ); |
25 | | - $row = $dbr->selectRow( 'geo_tags', |
26 | | - array( 'gt_lat', 'gt_lon' ), |
27 | | - array( 'gt_page_id' => $title->getArticleID(), 'gt_primary' => 1 ) |
28 | | - ); |
29 | | - if ( !$row ) { |
30 | | - return false; |
| 24 | + $coords = self::getAllCoordinates( $title->getArticleID(), array( 'gt_primary' => 1 ) ); |
| 25 | + if ( $coords ) { |
| 26 | + return $coords[0]; |
31 | 27 | } |
32 | | - return Coord::newFromRow( $row ); |
| 28 | + return false; |
33 | 29 | } |
34 | 30 | |
35 | 31 | /** |
| 32 | + * Retrieves all coordinates for the given page id |
| 33 | + * |
| 34 | + * @param int $pageId: ID of the page |
| 35 | + * @param Array $conds: Conditions for Database::select() |
| 36 | + * @param int $dbType: Database to select from DM_MASTER or DB_SLAVE |
| 37 | + * @return Array: Array of Coord objects |
| 38 | + */ |
| 39 | + public static function getAllCoordinates( $pageId, $conds = array(), $dbType = DB_SLAVE ) { |
| 40 | + $db = wfGetDB( $dbType ); |
| 41 | + $conds['gt_page_id'] = $pageId; |
| 42 | + $res = $db->select( 'geo_tags', array_values( Coord::$fieldMapping ), $conds, __METHOD__ ); |
| 43 | + $coords = array(); |
| 44 | + foreach ( $res as $row ) { |
| 45 | + $coords[] = Coord::newFromRow( $row ); |
| 46 | + } |
| 47 | + return $coords; |
| 48 | + } |
| 49 | + |
| 50 | + /** |
36 | 51 | * Parses coordinates |
37 | 52 | * See https://en.wikipedia.org/wiki/Template:Coord for sample inputs |
38 | 53 | * |
— | — | @@ -197,6 +212,7 @@ |
198 | 213 | class Coord { |
199 | 214 | public $lat, |
200 | 215 | $lon, |
| 216 | + $id, |
201 | 217 | $globe, |
202 | 218 | $primary = false, |
203 | 219 | $dim, |
— | — | @@ -224,7 +240,7 @@ |
225 | 241 | } |
226 | 242 | |
227 | 243 | /** |
228 | | - * Compares this coordinate with the given coordinate |
| 244 | + * Compares this coordinates with the given coordinates |
229 | 245 | * |
230 | 246 | * @param Coord $coord: Coordinate to compare with |
231 | 247 | * @param int $precision: Comparison precision |
— | — | @@ -235,6 +251,25 @@ |
236 | 252 | && round( $this->lon, $precision ) == round( $coord->lon, $precision ); |
237 | 253 | } |
238 | 254 | |
| 255 | + /** |
| 256 | + * Compares all the fields of this object with the given coordinates object |
| 257 | + * |
| 258 | + * @param Coord $coord: Coordinate to compare with |
| 259 | + * @param int $precision: Comparison precision |
| 260 | + * @return Boolean |
| 261 | + */ |
| 262 | + public function fullyEqualsTo( Coord $coord, $precision = 6 ) { |
| 263 | + return round( $this->lat, $precision ) == round( $coord->lat, $precision ) |
| 264 | + && round( $this->lon, $precision ) == round( $coord->lon, $precision ) |
| 265 | + && $this->globe == $coord->globe |
| 266 | + && $this->primary == $coord->primary |
| 267 | + && $this->dim == $coord->dim |
| 268 | + && $this->type == $coord->type |
| 269 | + && $this->name == $coord->name |
| 270 | + && $this->country == $coord->country |
| 271 | + && $this->region == $coord->region; |
| 272 | + } |
| 273 | + |
239 | 274 | public function getRow( $pageId = null ) { |
240 | 275 | $row = array( 'gt_page_id' => $pageId ); |
241 | 276 | foreach ( self::$fieldMapping as $field => $column ) { |
— | — | @@ -244,6 +279,7 @@ |
245 | 280 | } |
246 | 281 | |
247 | 282 | public static $fieldMapping = array( |
| 283 | + 'id' => 'gt_id', |
248 | 284 | 'lat' => 'gt_lat', |
249 | 285 | 'lon' => 'gt_lon', |
250 | 286 | 'globe' => 'gt_globe', |
Index: trunk/extensions/GeoData/GeoDataHooks.php |
— | — | @@ -157,21 +157,60 @@ |
158 | 158 | * @param LinksUpdate $linksUpdate |
159 | 159 | */ |
160 | 160 | public static function onLinksUpdate( &$linksUpdate ) { |
| 161 | + global $wgUseDumbLinkUpdate; |
161 | 162 | $out = $linksUpdate->mParserOutput; |
162 | | - //@todo: less dumb update |
163 | | - $dbw = wfGetDB( DB_MASTER ); |
164 | | - $dbw->delete( 'geo_tags', array( 'gt_page_id' => $linksUpdate->mId ), __METHOD__ ); |
| 163 | + $data = array(); |
165 | 164 | if ( isset( $out->geoData ) ) { |
166 | 165 | $geoData = $out->geoData; |
167 | | - $data = array(); |
168 | 166 | if ( $geoData['primary'] ) { |
169 | | - $data[] = $geoData['primary']->getRow( $linksUpdate->mId ); |
| 167 | + $data[] = $geoData['primary']; |
170 | 168 | } |
171 | | - foreach ( $geoData['secondary'] as $coord ) { |
172 | | - $data[] = $coord->getRow( $linksUpdate->mId ); |
173 | | - } |
174 | | - $dbw->insert( 'geo_tags', $data, __METHOD__ ); |
| 169 | + $data = array_merge( $data, $geoData['secondary'] ); |
175 | 170 | } |
| 171 | + if ( $wgUseDumbLinkUpdate || !count( $data ) ) { |
| 172 | + self::doDumbUpdate( $data, $linksUpdate->mId ); |
| 173 | + } else { |
| 174 | + self::doSmartUpdate( $data, $linksUpdate->mId ); |
| 175 | + } |
176 | 176 | return true; |
177 | 177 | } |
| 178 | + |
| 179 | + private static function doDumbUpdate( $coords, $pageId ) { |
| 180 | + $dbw = wfGetDB( DB_MASTER ); |
| 181 | + $dbw->delete( 'geo_tags', array( 'gt_page_id' => $pageId ), __METHOD__ ); |
| 182 | + $rows = array(); |
| 183 | + foreach ( $coords as $coord ) { |
| 184 | + $rows[] = $coord->getRow( $pageId ); |
| 185 | + } |
| 186 | + $dbw->insert( 'geo_tags', $data, __METHOD__ ); |
| 187 | + } |
| 188 | + |
| 189 | + private static function doSmartUpdate( $coords, $pageId ) { |
| 190 | + $prevCoords = GeoData::getAllCoordinates( $pageId, array(), DB_MASTER ); |
| 191 | + $add = array(); |
| 192 | + $delete = array(); |
| 193 | + foreach ( $prevCoords as $old ) { |
| 194 | + $delete[$old->id] = $old; |
| 195 | + } |
| 196 | + foreach ( $coords as $new ) { |
| 197 | + $match = false; |
| 198 | + foreach ( $delete as $id => $old ) { |
| 199 | + if ( $new->fullyEqualsTo( $old ) ) { |
| 200 | + unset( $delete[$id] ); |
| 201 | + $match = true; |
| 202 | + break; |
| 203 | + } |
| 204 | + } |
| 205 | + if ( !$match ) { |
| 206 | + $add[] = $new->getRow( $pageId ); |
| 207 | + } |
| 208 | + } |
| 209 | + $dbw = wfGetDB( DB_MASTER ); |
| 210 | + if ( count( $delete) ) { |
| 211 | + $dbw->delete( 'geo_tags', array( 'gt_id' => array_keys( $delete ) ), __METHOD__ ); |
| 212 | + } |
| 213 | + if ( count( $add ) ) { |
| 214 | + $dbw->insert( 'geo_tags', $add, __METHOD__ ); |
| 215 | + } |
| 216 | + } |
178 | 217 | } |