r107634 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r107633‎ | r107634 | r107635 >
Date:14:12, 30 December 2011
Author:maxsem
Status:ok (Comments)
Tags:
Comment:
First commit of new extension - GeoData, that allows to store and query page geographical coordinates. No i18n yet, not committing 2 API modules because they need to adapt to latest changes
Modified paths:
  • /trunk/extensions/GeoData (added) (history)
  • /trunk/extensions/GeoData/GeoData.body.php (added) (history)
  • /trunk/extensions/GeoData/GeoData.php (added) (history)
  • /trunk/extensions/GeoData/GeoData.sql (added) (history)
  • /trunk/extensions/GeoData/GeoDataHooks.php (added) (history)
  • /trunk/extensions/GeoData/GeoMath.php (added) (history)
  • /trunk/extensions/GeoData/tests (added) (history)
  • /trunk/extensions/GeoData/tests/GeoMathTest.php (added) (history)
  • /trunk/extensions/GeoData/tests/ParseCoordTest.php (added) (history)

Diff [purge]

Index: trunk/extensions/GeoData/GeoData.sql
@@ -0,0 +1,37 @@
 2+-- SQL schema for GeoData extension
 3+
 4+-- Stores information about geographical coordinates in articles
 5+CREATE TABLE /*_*/geo_tags (
 6+ -- page_id
 7+ gt_page_id int unsigned NOT NULL,
 8+ -- Whether this coordinate is primary (defines the principal location of article subject)
 9+ -- or secondary (just mentioned in text)
 10+ gt_primary bool NOT NULL,
 11+ -- Latitude of the point in degrees
 12+ gt_lat float NOT NULL,
 13+ -- Longitude of the point in degrees
 14+ gt_lon float NOT NULL,
 15+ -- Approximate viewing radius in meters, gives an idea how large the object is
 16+ gt_dim int default 1
 17+)/*$wgDBTableOptions*/;
 18+
 19+-- @todo
 20+CREATE INDEX /*i*/gt_page_id ON /*_*/geo_tags ( gt_page_id );
 21+CREATE INDEX /*i*/gt_lat_lon ON /*_*/geo_tags ( gt_lat, gt_lon );
 22+
 23+DELIMITER //
 24+-- Calculates distance in meters between two points
 25+-- See https://en.wikipedia.org/wiki/Haversine_formula
 26+CREATE FUNCTION /*_*/gd_distance( lat1 double, lon1 double, lat2 double, lon2 double )
 27+ RETURNS double DETERMINISTIC
 28+BEGIN
 29+ SET lat1 = radians( lat1 );
 30+ SET lon1 = radians( lon1 );
 31+ SET lat2 = radians( lat2 );
 32+ SET lon2 = radians( lon2 );
 33+ SET @sin1 = sin( ( lat2 - lat1 ) / 2 );
 34+ SET @sin2 = sin( ( lon2 - lon1 ) / 2 );
 35+ RETURN 2 * 6371010 * asin( sqrt( @sin1 * @sin1 + cos( lat1 ) * cos( lat2 ) * @sin2 * @sin2 ) );
 36+END//
 37+
 38+DELIMITER ;
Property changes on: trunk/extensions/GeoData/GeoData.sql
___________________________________________________________________
Added: svn:eol-style
139 + native
Index: trunk/extensions/GeoData/tests/ParseCoordTest.php
@@ -0,0 +1,62 @@
 2+<?php
 3+
 4+/**
 5+ * @group GeoData
 6+ */
 7+class ParseCoordTest extends MediaWikiTestCase {
 8+ /**
 9+ * @dataProvider getCases
 10+ */
 11+ public function testParseCoordinates( $parts, $result ) {
 12+ $formatted = '"' . implode( $parts, '|' ) . '"';
 13+ $s = GeoData::parseCoordinates( $parts );
 14+ $val = $s->value;
 15+ if ( $result === false ) {
 16+ $this->assertFalse( $s->isGood(), "Parsing of $formatted was expected to fail" );
 17+ } else {
 18+ $this->assertTrue( $s->isGood(), "Parsing of $formatted was expected to suceed, but it failed" );
 19+ $this->assertTrue( $val->equalsTo( $result ),
 20+ "Parsing of $formatted was expected to yield something close to"
 21+ . " ({$result->lat}, {$result->lon}), but yielded ({$val->lat}, {$val->lon})"
 22+ );
 23+ }
 24+ }
 25+
 26+ public function getCases() {
 27+ return array(
 28+ // basics
 29+ array( array( 0, 0 ), new Coord( 0, 0 ) ),
 30+ array( array( 75, 25 ), new Coord( 75, 25 ) ),
 31+ array( array( '20.0', '-15.5' ), new Coord( 20, -15.5 ) ),
 32+ array( array( -20, 30, 40, 45 ), new Coord( -20.5, 40.75 ) ),
 33+ array( array( 20, 30, 40, 40, 45, 55 ), new Coord( 20.511111111111, 40.765277777778 ) ),
 34+ // NESW
 35+ array( array( 20, 'N', 30, 'E' ), new Coord( 20, 30 ) ),
 36+ array( array( 20, 'N', 30, 'W' ), new Coord( 20, -30 ) ),
 37+ array( array( 20, 'S', 30, 'E' ), new Coord( -20, 30 ) ),
 38+ array( array( 20, 'S', 30, 'W' ), new Coord( -20, -30 ) ),
 39+ array( array( 20, 30, 40, 'S', 40, 45, 55, 'E' ), new Coord( -20.511111111111, 40.765277777778 ) ),
 40+ array( array( 20, 30, 40, 'N', 40, 45, 55, 'W' ), new Coord( 20.511111111111, -40.765277777778 ) ),
 41+ array( array( 20, 'E', 30, 'W' ), false ),
 42+ array( array( 20, 'S', 30, 'N' ), false ),
 43+ array( array( -20, 'S', 30, 'E' ), false ),
 44+ array( array( 20, 'S', -30, 'W' ), false ),
 45+ // wrong number of parameters
 46+ array( array(), false ),
 47+ array( array( 1 ), false ),
 48+ array( array( 1, 2, 3 ), false ),
 49+ array( array( 1, 2, 3, 4, 5 ), false ),
 50+ array( array( 1, 2, 3, 4, 5, 6, 7 ), false ),
 51+ array( array( 1, 2, 3, 4, 5, 6, 7, 8, 9 ), false ),
 52+ array( array( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ), false ),
 53+ // unbalanced NESW
 54+ array( array( 'N', 'E' ), false ),
 55+ array( array( 12, 'N', 'E' ), false ),
 56+ array( array( 'N', 15, 'E' ), false ),
 57+ array( array( 1, 2, 3, 'N', 1, 'E' ), false ),
 58+ array( array( 1, 2, 3, 'N', 'E' ), false ),
 59+ array( array( 1, 2, 3, 'N', 1, 'E' ), false ),
 60+ array( array( 1, 2, 3, 'N', 1, 2, 'E' ), false ),
 61+ );
 62+ }
 63+}
\ No newline at end of file
Property changes on: trunk/extensions/GeoData/tests/ParseCoordTest.php
___________________________________________________________________
Added: svn:eol-style
164 + native
Index: trunk/extensions/GeoData/tests/GeoMathTest.php
@@ -0,0 +1,30 @@
 2+<?php
 3+
 4+/**
 5+ * @group GeoData
 6+ */
 7+class GeoMathTest extends MediaWikiTestCase {
 8+ /**
 9+ * @dataProvider getDistanceData
 10+ */
 11+ public function testDistance( $lat1, $lon1, $lat2, $lon2, $dist, $name ) {
 12+ $this->assertEquals( $dist, GeoMath::distance( $lat1, $lon1, $lat2, $lon2 ), "testDistance(): $name", $dist / 1000 );
 13+ }
 14+
 15+ public function getDistanceData() {
 16+ // just run against a few values from teh internets...
 17+ return array(
 18+ array( 55.75, 37.6167, 59.95, 30.3167, 635000, 'Moscow to St. Bumtown' ),
 19+ array( 51.5, -0.1167, 52.35, 4.9167, 357520, 'London to Amsterdam' ),
 20+ array( 40.7142, -74.0064, 37.775, -122.418, 4125910, 'New York to San Francisco' ),
 21+ );
 22+ }
 23+
 24+ public function testRectAround() {
 25+ for ( $i = 0; $i < 90; $i += 5 ) {
 26+ $r = GeoMath::rectAround( $i, $i, 5000 );
 27+ $this->assertEquals( 10000, GeoMath::distance( $i, $r['minLon'], $i, $r['maxLon'] ), 'rectAround(): test longitude', 1 );
 28+ $this->assertEquals( 10000, GeoMath::distance( $r['minLat'], $i, $r['maxLat'], $i ), 'rectAround(): test latitude', 1 );
 29+ }
 30+ }
 31+}
Property changes on: trunk/extensions/GeoData/tests/GeoMathTest.php
___________________________________________________________________
Added: svn:eol-style
132 + native
Index: trunk/extensions/GeoData/GeoData.body.php
@@ -0,0 +1,211 @@
 2+<?php
 3+
 4+class GeoData {
 5+ /**
 6+ *
 7+ * @param type $lat
 8+ * @param type $lon
 9+ * @return Boolean: Whether the coordinate is valid
 10+ */
 11+ public static function validateCoord( $lat, $lon ) {
 12+ return is_numeric( $lat )
 13+ && is_numeric( $lon )
 14+ && abs( $lat ) <= 90
 15+ && abs( $lon ) <= 180;
 16+ }
 17+
 18+ public static function getPageCoordinates( Title $title ) {
 19+ $dbr = wfGetDB( DB_SLAVE );
 20+ $row = $dbr->selectRow( 'geo_tags',
 21+ array( 'gt_lat', 'gt_lon' ),
 22+ array( 'gt_page_id' => $title->getArticleID(), 'gt_primary' => 1 )
 23+ );
 24+ if ( !$row ) {
 25+ return false;
 26+ }
 27+ return Coord::newFromRow( $row );
 28+ }
 29+
 30+ /**
 31+ * Parses coordinates
 32+ * See https://en.wikipedia.org/wiki/Template:Coord for sample inputs
 33+ *
 34+ * @param String $str:
 35+ * @returns Status: Status object, in case of success its value is a Coord object.
 36+ */
 37+ public static function parseCoordinates( $parts ) {
 38+ global $wgContLang;
 39+
 40+ $count = count( $parts );
 41+ if ( !is_array( $parts ) || $count < 2 || $count > 8 || ( $count % 2 ) ) {
 42+ return Status::newFatal( 'geodata-bad-input' );
 43+ }
 44+ list( $latArr, $lonArr ) = array_chunk( $parts, $count / 2 );
 45+ $coordInfo = self::getCoordInfo();
 46+
 47+ $lat = self::parseOneCoord( $latArr, $coordInfo['lat'] );
 48+ if ( $lat === false ) {
 49+ return Status::newFatal( 'geodata-bad-latitude' );
 50+ }
 51+ $lon = self::parseOneCoord( $lonArr, $coordInfo['lon'] );
 52+ if ( $lon === false ) {
 53+ return Status::newFatal( 'geodata-bad-longitude' );
 54+ }
 55+ return Status::newGood( new Coord( $lat, $lon ) );
 56+ }
 57+
 58+ private static function parseOneCoord( $parts, $coordInfo ) {
 59+ global $wgContLang;
 60+
 61+ $count = count( $parts );
 62+ $multiplier = 1;
 63+ $value = 0;
 64+
 65+ for ( $i = 0; $i < $count; $i++ ) {
 66+ $part = $parts[$i];
 67+ if ( $i > 0 && $i == $count - 1 ) {
 68+ $suffix = self::parseSuffix( $part, $coordInfo );
 69+ if ( $suffix ) {
 70+ if ( $value < 0 ) {
 71+ return false; // "-60°S sounds weird, isn't it?
 72+ }
 73+ $value *= $suffix;
 74+ break;
 75+ } elseif ( $i == 3 ) {
 76+ return false;
 77+ }
 78+ }
 79+ $part = $wgContLang->parseFormattedNumber( $part );
 80+ $min = $i == 0 ? -$coordInfo['range'] : 0;
 81+ $max = $i == 0 ? $coordInfo['range'] : 59.999999;
 82+ if ( !is_numeric( $part )
 83+ || $part < $min
 84+ || $part > $max ) {
 85+ return false;
 86+ }
 87+ $value += $part * $multiplier * GeoMath::sign( $value );
 88+ $multiplier /= 60;
 89+ }
 90+ if ( abs( $value ) > $coordInfo['range'] ) {
 91+ return false;
 92+ }
 93+ return $value;
 94+ }
 95+
 96+ /**
 97+ * Parses coordinate suffix such as N, S, E or W
 98+ *
 99+ * @param String $str: String to test
 100+ * @param Array $coordInfo
 101+ * @return int: Sign modifier or 0 if not a suffix
 102+ */
 103+ private static function parseSuffix( $str, $coordInfo ) {
 104+ global $wgContLang;
 105+ $str = $wgContLang->uc( trim( $str ) );
 106+ foreach ( $coordInfo['-'] as $suffix ) {
 107+ if ( $suffix == $str ) {
 108+ return -1;
 109+ }
 110+ }
 111+ foreach ( $coordInfo['+'] as $suffix ) {
 112+ if ( $suffix == $str ) {
 113+ return 1;
 114+ }
 115+ }
 116+ return 0;
 117+ }
 118+
 119+ /**
 120+ *
 121+ * @param Coord $coord
 122+ * @param Array $args
 123+ */
 124+ public static function parseTagArgs( Coord $coord, $args ) {
 125+ $result = $args;
 126+ // fear not of overwriting stuff we've just received from the geohack param, it has minimum precedence
 127+ if ( isset( $args['geohack'] ) ) {
 128+ $result = array_merge( self::parseGeoHackArgs( $args['geohack'] ), $result );
 129+ }
 130+ if ( isset( $args['dim'] ) && is_numeric( $args['dim'] ) && $args['dim'] > 0 ) {
 131+ $coord->dim = $args['dim'];
 132+ } else {
 133+ $coord->dim = null;
 134+ }
 135+ $coord->primary = isset( $args['primary'] );
 136+ return Status::newGood( $result );
 137+ }
 138+
 139+ public static function parseGeoHackArgs( $str ) {
 140+ $result = array();
 141+ $parts = explode( '_', $str );
 142+ foreach ( $parts as $arg ) {
 143+ if ( !preg_match( '/(\\S+?):(.*)/', $arg, $matches ) ) {
 144+ continue;
 145+ }
 146+ $key = $m[1];
 147+ $value = $m[2];
 148+ if ( $key == 'dim' ) {
 149+ $result['dim'] = $value;
 150+ }
 151+ }
 152+ return $result;
 153+ }
 154+
 155+ private static function getCoordInfo() {
 156+ //@todo: internationalisation?
 157+ return array(
 158+ 'lat' => array(
 159+ 'range' => 90,
 160+ '+' => array( 'N' ),
 161+ '-' => array( 'S' ),
 162+ ),
 163+ 'lon' => array(
 164+ 'range' => 180,
 165+ '+' => array( 'E' ),
 166+ '-' => array( 'W' ),
 167+ ),
 168+ );
 169+ }
 170+}
 171+
 172+/**
 173+ * CLass representing one coordinate
 174+ */
 175+class Coord {
 176+ public $lat,
 177+ $lon,
 178+ $primary,
 179+ $dim,
 180+ $params;
 181+
 182+ public function __construct( $lat, $lon ) {
 183+ $this->lat = $lat;
 184+ $this->lon = $lon;
 185+ }
 186+
 187+ public static function newFromRow( $row ) {
 188+ return new Coord( $row->gt_lat, $row->gt_lon );
 189+ }
 190+
 191+ /**
 192+ * Compares this coordinate with the given coordinate
 193+ *
 194+ * @param Coord $coord: Coordinate to compare with
 195+ * @param int $precision: Comparison precision
 196+ * @return Boolean
 197+ */
 198+ public function equalsTo( Coord $coord, $precision = 6 ) {
 199+ return round( $this->lat, $precision ) == round( $coord->lat, $precision )
 200+ && round( $this->lon, $precision ) == round( $coord->lon, $precision );
 201+ }
 202+
 203+ public function getRow( $pageId = null ) {
 204+ return array(
 205+ 'gt_page_id' => $pageId,
 206+ 'gt_primary' => $this->primary,
 207+ 'gt_lat' => $this->lat,
 208+ 'gt_lon' => $this->lon,
 209+ 'gt_dim' => $this->dim,
 210+ );
 211+ }
 212+}
\ No newline at end of file
Property changes on: trunk/extensions/GeoData/GeoData.body.php
___________________________________________________________________
Added: svn:eol-style
1213 + native
Index: trunk/extensions/GeoData/GeoData.php
@@ -0,0 +1,36 @@
 2+<?php
 3+/**
 4+ * API sandbox extension. Initial author Max Semenik
 5+ * License: WTFPL 2.0
 6+ */
 7+$wgExtensionCredits['other'][] = array(
 8+ 'path' => __FILE__,
 9+ 'name' => 'GeoData',
 10+ 'author' => array( 'Max Semenik' ),
 11+ 'url' => 'https://mediawiki.org/wiki/Extension:GeoData',
 12+ 'descriptionmsg' => 'geodata-desc',
 13+);
 14+
 15+$dir = dirname( __FILE__ );
 16+
 17+$wgAutoloadClasses['Coord'] = "$dir/GeoData.body.php";
 18+$wgAutoloadClasses['GeoData'] = "$dir/GeoData.body.php";
 19+$wgAutoloadClasses['GeoDataHooks'] = "$dir/GeoDataHooks.php";
 20+$wgAutoloadClasses['GeoMath'] = "$dir/GeoMath.php";
 21+$wgAutoloadClasses['ApiQueryGeoSearch'] = "$dir/ApiQueryGeoSearch.php";
 22+$wgAutoloadClasses['ApiQueryCoordinates'] = "$dir/ApiQueryCoordinates.php";
 23+
 24+$wgAPIListModules['geosearch'] = 'ApiQueryGeoSearch';
 25+$wgAPIPropModules['coordinates'] = 'ApiQueryCoordinates';
 26+
 27+$wgHooks['ParserFirstCallInit'][] = 'GeoDataHooks::onParserFirstCallInit';
 28+$wgHooks['UnitTestsList'][] = 'GeoDataHooks::onUnitTestsList';
 29+$wgHooks['LanguageGetMagic'][] = 'GeoDataHooks::onLanguageGetMagic';
 30+$wgHooks['ArticleDeleteComplete'][] = 'GeoDataHooks::onArticleDeleteComplete';
 31+$wgHooks['LinksUpdate'][] = 'GeoDataHooks::onLinksUpdate';
 32+
 33+/**
 34+ * Maximum radius for geospatial searches.
 35+ * The greater this variable is, the louder your server ouches.
 36+ */
 37+$wgMaxGeoSearchRadius = 10000; // 10km
Property changes on: trunk/extensions/GeoData/GeoData.php
___________________________________________________________________
Added: svn:eol-style
138 + native
Index: trunk/extensions/GeoData/GeoMath.php
@@ -0,0 +1,75 @@
 2+<?php
 3+
 4+/**
 5+ * Class that performs basic coordinate calculations
 6+ * Note that the formulas are useful only for our specific purposes, some of them may be
 7+ * inaccurate for long distances. Oh well.
 8+ *
 9+ * All the functions that accept coordinates assume that they're in degrees, not radians.
 10+ */
 11+/* static */class GeoMath {
 12+ const EARTH_RADIUS = 6371010;
 13+
 14+ /**
 15+ * Calculates distance between two coordinates
 16+ * See https://en.wikipedia.org/wiki/Haversine_formula
 17+ *
 18+ * @param float $lat1
 19+ * @param float $lon1
 20+ * @param float $lat2
 21+ * @param float $lon2
 22+ * @return float Distance in meters
 23+ */
 24+ public static function distance( $lat1, $lon1, $lat2, $lon2 ) {
 25+ $lat1 = deg2rad( $lat1 );
 26+ $lon1 = deg2rad( $lon1 );
 27+ $lat2 = deg2rad( $lat2 );
 28+ $lon2 = deg2rad( $lon2 );
 29+ $sin1 = sin( ( $lat2 - $lat1 ) / 2 );
 30+ $sin2 = sin( ( $lon2 - $lon1 ) / 2 );
 31+ return 2 * self::EARTH_RADIUS * asin( sqrt( $sin1 * $sin1 + cos( $lat1 ) * cos( $lat2 ) * $sin2 * $sin2 ) );
 32+ }
 33+
 34+ /**
 35+ * Returns a bounding rectangle around a given point
 36+ *
 37+ * @param float $lat
 38+ * @param float $lon
 39+ * @param float $radius
 40+ * @return Array
 41+ */
 42+ public static function rectAround( $lat, $lon, $radius ) {
 43+ if ( !$radius ) {
 44+ return array(
 45+ 'minLat' => $lat, 'maxLat' => $lat,
 46+ 'minLon' => $lon, 'maxLon' => $lon
 47+ );
 48+ }
 49+ $r2lat = rad2deg( $radius / self::EARTH_RADIUS );
 50+ // @todo: doesn't work around poles, should we care?
 51+ if ( abs( $lat ) < 89.9 ) {
 52+ $r2lon = rad2deg( $radius / cos( deg2rad( $lat ) ) / self::EARTH_RADIUS );
 53+ } else {
 54+ $r2lon = 0.1;
 55+ }
 56+ return array(
 57+ 'minLat' => $lat - $r2lat,
 58+ 'maxLat' => $lat + $r2lat,
 59+ 'minLon' => $lon - $r2lon,
 60+ 'maxLon' => $lon + $r2lon
 61+ );
 62+ }
 63+
 64+ /**
 65+ * Sign function
 66+ *
 67+ * @param Float $x: Value to get sinng of
 68+ * @return int
 69+ */
 70+ public static function sign( $x ) {
 71+ if ( $x >= 0 ) {
 72+ return 1;
 73+ }
 74+ return -1;
 75+ }
 76+}
Property changes on: trunk/extensions/GeoData/GeoMath.php
___________________________________________________________________
Added: svn:eol-style
177 + native
Index: trunk/extensions/GeoData/GeoDataHooks.php
@@ -0,0 +1,154 @@
 2+<?php
 3+
 4+class GeoDataHooks {
 5+ public static function onUnitTestsList( &$files ) {
 6+ $dir = dirname( __FILE__ ) . "/tests";
 7+ $files[] = "$dir/ParseCoordTest.php";
 8+ $files[] = "$dir/GeoMathTest.php";
 9+ return true;
 10+ }
 11+
 12+ /**
 13+ * ParserFirstCallInit hook handler
 14+ * @see: https://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit
 15+ * @param Parser $parser
 16+ */
 17+ public static function onParserFirstCallInit( &$parser ) {
 18+ $parser->setFunctionHook( 'coordinate', 'GeoDataHooks::coordinateHandler', SFH_OBJECT_ARGS );
 19+ return true;
 20+ }
 21+
 22+ /**
 23+ * LanguageGetMagic hook handler
 24+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic
 25+ * @param Array $magicWords
 26+ * @param String $langCode
 27+ */
 28+ public static function onLanguageGetMagic( &$magicWords, $langCode ) {
 29+ $magicWords['coordinate'] = array( 0, 'coordinate' );
 30+ return true;
 31+ }
 32+
 33+ /**
 34+ * Handler for the #coordinate parser function
 35+ *
 36+ * @param Parser $parser
 37+ * @param PPFrame $frame
 38+ * @param Array $args
 39+ * @return Mixed
 40+ */
 41+ public static function coordinateHandler( $parser, $frame, $args ) {
 42+ $output = $parser->getOutput();
 43+ self::prepareOutput( $output );
 44+
 45+ $unnamed = array();
 46+ $named = array();
 47+ $first = trim( $frame->expand( array_shift( $args ) ) );
 48+ if ( $first !== '' ) {
 49+ $unnamed[] = $first;
 50+ }
 51+ foreach ( $args as $arg ) {
 52+ $bits = $arg->splitArg();
 53+ $value = trim( $frame->expand( $bits['value'] ) );
 54+ if ( $bits['index'] === '' ) {
 55+ $named[trim( $frame->expand( $bits['name'] ) )] = $value;
 56+ } else {
 57+ $unnamed[] = $value;
 58+ }
 59+ }
 60+ $status = GeoData::parseCoordinates( $unnamed );
 61+ if ( $status->isGood() ) {
 62+ $coord = $status->value;
 63+ $status = GeoData::parseTagArgs( $coord, $named );
 64+ if ( $status->isGood() ) {
 65+ $status = self::applyCoord( $output, $coord, $status->value );
 66+ if ( $status->isGood() ) {
 67+ return '';
 68+ }
 69+ }
 70+ }
 71+ // Apply tracking category
 72+ if ( !$output->geoData['failures'] ) {
 73+ $output->geoData['failures'] = true;
 74+ $output->addCategory(
 75+ wfMessage( 'geodata-broken-tags-category' )->inContentLanguage()->text(),
 76+ $parser->getTitle()->getText()
 77+ );
 78+ }
 79+ return array( "<span class=\"error\">{$status->getWikiText()}</span>", 'noparse' => false );
 80+ }
 81+
 82+ /**
 83+ * Make sure that parser output has our storage array
 84+ * @param ParserOutput $output
 85+ */
 86+ private static function prepareOutput( ParserOutput $output ) {
 87+ if ( !isset( $output->geoData ) ) {
 88+ $output->geoData = array(
 89+ 'primary' => false,
 90+ 'secondary' => array(),
 91+ 'failures' => false,
 92+ );
 93+ }
 94+ }
 95+
 96+ /**
 97+ * Applies a coordinate to parser output
 98+ *
 99+ * @param ParserOutput $output
 100+ * @param Coord $coord
 101+ * @return Status: whether save went OK
 102+ */
 103+ private static function applyCoord( ParserOutput $output, Coord $coord ) {
 104+ if ( $coord->primary ) {
 105+ if ( $output->geoData['primary'] ) {
 106+ $output->geoData['secondary'][] = $coord;
 107+ return Status::newFatal( 'geodata-multiple-primary' );
 108+ } else {
 109+ $output->geoData['primary'] = $coord;
 110+ }
 111+ } else {
 112+ $output->geoData['secondary'][] = $coord;
 113+ }
 114+ return Status::newGood();
 115+ }
 116+
 117+ /**
 118+ * ArticleDeleteComplete hook handler
 119+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/ArticleDeleteComplete
 120+ *
 121+ * @param Article $article
 122+ * @param User $user
 123+ * @param String $reason
 124+ * @param int $id
 125+ */
 126+ public static function onArticleDeleteComplete( &$article, User &$user, $reason, $id ) {
 127+ $dbw = wfGetDB( DB_MASTER );
 128+ $dbw->delete( 'geo_tags', array( 'gt_page_id' => $id ), __METHOD__ );
 129+ return true;
 130+ }
 131+
 132+ /**
 133+ * LinksUpdate hook handler
 134+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/LinksUpdate
 135+ * @param LinksUpdate $linksUpdate
 136+ */
 137+ public static function onLinksUpdate( &$linksUpdate ) {
 138+ $out = $linksUpdate->mParserOutput;
 139+ //@todo: less dumb update
 140+ $dbw = wfGetDB( DB_MASTER );
 141+ $dbw->delete( 'geo_tags', array( 'gt_page_id' => $linksUpdate->mId ), __METHOD__ );
 142+ if ( isset( $out->geoData ) ) {
 143+ $geoData = $out->geoData;
 144+ $data = array();
 145+ if ( $geoData['primary'] ) {
 146+ $data[] = $geoData['primary']->getRow( $linksUpdate->mId );
 147+ }
 148+ foreach ( $geoData['secondary'] as $coord ) {
 149+ $data[] = $coord->getRow( $linksUpdate->mId );
 150+ }
 151+ $dbw->insert( 'geo_tags', $data, __METHOD__ );
 152+ }
 153+ return true;
 154+ }
 155+}
Property changes on: trunk/extensions/GeoData/GeoDataHooks.php
___________________________________________________________________
Added: svn:eol-style
1156 + native

Comments

#Comment by Nikerabbit (talk | contribs)   10:09, 5 January 2012

Who wants this and why? How is this extension used? Is it compatible with SMW?

#Comment by MaxSem (talk | contribs)   11:13, 5 January 2012

This extension is needed by the mobile team that currently relies on third-party tools for geolocation. SMW is a whaladon that is not going to run on our cluster any time soon, unlike this lightweight extension designed with WMF use in mind.

Status & tagging log