/**
  * Get button information to link to Special:Nearby to find articles
  * (geographically) related to this
  * @return array A map of the button's friendly name, "nearby", to its spec
  *   if the button can be displayed.
  */
 public function getNearbyButton()
 {
     $skin = $this->getSkin();
     $title = $skin->getTitle();
     if (!$skin->getMFConfig()->get('MFNearby') || !class_exists('GeoData') || !GeoData::getPageCoordinates($title)) {
         return array();
     }
     return array('nearby' => array('attributes' => array('href' => SpecialPage::getTitleFor('Nearby')->getLocalUrl() . '#/page/' . $title->getText(), 'class' => 'nearby-button'), 'label' => wfMessage('mobile-frontend-nearby-sectiontext')->text()));
 }
Beispiel #2
0
 /**
  * @dataProvider getCases
  */
 public function testParseCoordinates($parts, $result, $globe = 'earth')
 {
     $formatted = '"' . implode($parts, '|') . '"';
     $s = GeoData::parseCoordinates($parts, $globe);
     $val = $s->value;
     if ($result === false) {
         $this->assertFalse($s->isGood(), "Parsing of {$formatted} was expected to fail");
     } else {
         $msg = $s->isGood() ? '' : $s->getWikiText();
         $this->assertTrue($s->isGood(), "Parsing of {$formatted} was expected to succeed, but it failed: {$msg}");
         $this->assertTrue($val->equalsTo($result), "Parsing of {$formatted} was expected to yield something close to" . " ({$result->lat}, {$result->lon}), but yielded ({$val->lat}, {$val->lon})");
     }
 }
 /**
  * #coordinates parser function callback
  * 
  * @param Parser $parser
  * @param PPFrame $frame
  * @param Array $args
  * @return Mixed
  */
 public function coordinates($parser, $frame, $args)
 {
     if ($parser != $this->parser) {
         throw new MWException(__METHOD__ . '() called by wrong parser');
     }
     $this->output = $parser->getOutput();
     if (!isset($this->output->geoData)) {
         $this->output->geoData = new CoordinatesOutput();
     }
     $this->unnamed = array();
     $this->named = array();
     $first = trim($frame->expand(array_shift($args)));
     $this->addArg($first);
     foreach ($args as $arg) {
         $bits = $arg->splitArg();
         $value = trim($frame->expand($bits['value']));
         if ($bits['index'] === '') {
             $this->named[trim($frame->expand($bits['name']))] = $value;
         } else {
             $this->addArg($value);
         }
     }
     $this->parseTagArgs();
     $status = GeoData::parseCoordinates($this->unnamed, $this->named['globe']);
     if ($status->isGood()) {
         $coord = $status->value;
         $status = $this->applyTagArgs($coord);
         if ($status->isGood()) {
             $status = $this->applyCoord($coord);
             if ($status->isGood()) {
                 return '';
             }
         }
     }
     $parser->addTrackingCategory('geodata-broken-tags-category');
     $errorText = $this->errorText($status);
     if ($errorText == '<>') {
         // Error that doesn't require a message,
         // can't think of a better way to pass this condition
         return '';
     }
     return array("<span class=\"error\">{$errorText}</span>", 'noparse' => false);
 }
 /**
  * @param ApiPageSet $resultPageSet
  * @return
  */
 private function run($resultPageSet = null)
 {
     $params = $this->extractRequestParams();
     $exclude = false;
     $this->requireOnlyOneParameter($params, 'coord', 'page');
     if (isset($params['coord'])) {
         $arr = explode('|', $params['coord']);
         if (count($arr) != 2 || !GeoData::validateCoord($arr[0], $arr[1], $params['globe'])) {
             $this->dieUsage('Invalid coordinate provided', '_invalid-coord');
         }
         $lat = $arr[0];
         $lon = $arr[1];
     } elseif (isset($params['page'])) {
         $t = Title::newFromText($params['page']);
         if (!$t || !$t->canExist()) {
             $this->dieUsage("Invalid page title ``{$params['page']}'' provided", '_invalid-page');
         }
         if (!$t->exists()) {
             $this->dieUsage("Page ``{$params['page']}'' does not exist", '_nonexistent-page');
         }
         $coord = GeoData::getPageCoordinates($t);
         if (!$coord) {
             $this->dieUsage('Page coordinates unknown', '_no-coordinates');
         }
         $lat = $coord->lat;
         $lon = $coord->lon;
         $exclude = $t->getArticleID();
     }
     $lat = floatval($lat);
     $lon = floatval($lon);
     $radius = intval($params['radius']);
     $rect = GeoMath::rectAround($lat, $lon, $radius);
     $dbr = wfGetDB(DB_SLAVE);
     $this->addTables(array('page', 'geo_tags'));
     $this->addFields(array('gt_lat', 'gt_lon', 'gt_primary'));
     // retrieve some fields only if page set needs them
     if (is_null($resultPageSet)) {
         $this->addFields(array('page_id', 'page_namespace', 'page_title'));
     } else {
         $this->addFields(WikiPage::selectFields());
     }
     foreach ($params['prop'] as $prop) {
         if (isset(Coord::$fieldMapping[$prop])) {
             $this->addFields(Coord::$fieldMapping[$prop]);
         }
     }
     $this->addWhereFld('gt_globe', $params['globe']);
     $this->addWhereFld('gt_lat_int', self::intRange($rect["minLat"], $rect["maxLat"]));
     $this->addWhereFld('gt_lon_int', self::intRange($rect["minLon"], $rect["maxLon"]));
     $this->addWhereRange('gt_lat', 'newer', $rect["minLat"], $rect["maxLat"], false);
     if ($rect["minLon"] > $rect["maxLon"]) {
         $this->addWhere("gt_lon < {$rect['maxLon']} OR gt_lon > {$rect['minLon']}");
     } else {
         $this->addWhereRange('gt_lon', 'newer', $rect["minLon"], $rect["maxLon"], false);
     }
     $this->addWhereFld('page_namespace', $params['namespace']);
     $this->addWhere('gt_page_id = page_id');
     if ($exclude) {
         $this->addWhere("gt_page_id <> {$exclude}");
     }
     if (isset($params['maxdim'])) {
         $this->addWhere('gt_dim < ' . intval($params['maxdim']));
     }
     $primary = array_flip($params['primary']);
     $this->addWhereIf(array('gt_primary' => 1), isset($primary['yes']) && !isset($primary['no']));
     $this->addWhereIf(array('gt_primary' => 0), !isset($primary['yes']) && isset($primary['no']));
     $this->addOption('USE INDEX', 'gt_spatial');
     $limit = $params['limit'];
     $res = $this->select(__METHOD__);
     $rows = array();
     foreach ($res as $row) {
         $row->dist = GeoMath::distance($lat, $lon, $row->gt_lat, $row->gt_lon);
         $rows[] = $row;
     }
     // sort in PHP because sorting via SQL involves a filesort
     usort($rows, 'ApiQueryGeoSearch::compareRows');
     $result = $this->getResult();
     foreach ($rows as $row) {
         if (!$limit--) {
             break;
         }
         if (is_null($resultPageSet)) {
             $title = Title::newFromRow($row);
             $vals = array('pageid' => intval($row->page_id), 'ns' => intval($title->getNamespace()), 'title' => $title->getPrefixedText(), 'lat' => floatval($row->gt_lat), 'lon' => floatval($row->gt_lon), 'dist' => round($row->dist, 1));
             if ($row->gt_primary) {
                 $vals['primary'] = '';
             }
             foreach ($params['prop'] as $prop) {
                 if (isset(Coord::$fieldMapping[$prop]) && isset($row->{Coord::$fieldMapping[$prop]})) {
                     $field = Coord::$fieldMapping[$prop];
                     $vals[$prop] = $row->{$field};
                 }
             }
             $fit = $result->addValue(array('query', $this->getModuleName()), null, $vals);
             if (!$fit) {
                 break;
             }
         } else {
             $resultPageSet->processDbRow($row);
         }
     }
     if (is_null($resultPageSet)) {
         $result->setIndexedTagName_internal(array('query', $this->getModuleName()), $this->getModulePrefix());
     }
 }
 /**
  * @param $resultPageSet ApiPageSet
  * @return
  */
 private function run($resultPageSet = null)
 {
     $params = $this->extractRequestParams();
     $exclude = false;
     $this->requireOnlyOneParameter($params, 'coord', 'page');
     if (isset($params['coord'])) {
         $arr = explode('|', $params['coord']);
         if (count($arr) != 2 || !GeoData::validateCoord($arr[0], $arr[1], $params['globe'])) {
             $this->dieUsage('Invalid coordinate provided', '_invalid-coord');
         }
         $lat = $arr[0];
         $lon = $arr[1];
     } elseif (isset($params['page'])) {
         $t = Title::newFromText($params['page']);
         if (!$t || !$t->canExist()) {
             $this->dieUsage("Invalid page title ``{$params['page']}'' provided", '_invalid-page');
         }
         if (!$t->exists()) {
             $this->dieUsage("Page ``{$params['page']}'' does not exist", '_nonexistent-page');
         }
         $coord = GeoData::getPageCoordinates($t);
         if (!$coord) {
             $this->dieUsage('Page coordinates unknown', '_no-coordinates');
         }
         $lat = $coord->lat;
         $lon = $coord->lon;
         $exclude = $t->getArticleID();
     }
     $lat = floatval($lat);
     $lon = floatval($lon);
     $radius = intval($params['radius']);
     $rect = GeoMath::rectAround($lat, $lon, $radius);
     $dbr = wfGetDB(DB_SLAVE);
     $this->addTables(array('geo_tags', 'page'));
     $this->addFields(array('gt_lat', 'gt_lon', 'gt_primary', "{$dbr->tablePrefix()}gd_distance( {$lat}, {$lon}, gt_lat, gt_lon ) AS dist"));
     // retrieve some fields only if page set needs them
     if (is_null($resultPageSet)) {
         $this->addFields(array('page_id', 'page_namespace', 'page_title'));
     } else {
         $this->addFields(array("{$dbr->tableName('page')}.*"));
     }
     foreach ($params['prop'] as $prop) {
         if (isset(Coord::$fieldMapping[$prop])) {
             $this->addFields(Coord::$fieldMapping[$prop]);
         }
     }
     $this->addWhereFld('gt_globe', $params['globe']);
     $this->addWhereRange('gt_lat', 'newer', $rect["minLat"], $rect["maxLat"], false);
     $this->addWhereRange('gt_lon', 'newer', $rect["minLon"], $rect["maxLon"], false);
     //$this->addWhere( 'dist < ' . intval( $radius ) ); hasta be in HAVING, not WHERE
     $this->addWhereFld('page_namespace', $params['namespace']);
     $this->addWhere('gt_page_id = page_id');
     if ($exclude) {
         $this->addWhere("gt_page_id <> {$exclude}");
     }
     if (isset($params['maxdim'])) {
         $this->addWhere('gt_dim < ' . intval($params['maxdim']));
     }
     $primary = array_flip($params['primary']);
     $this->addWhereIf(array('gt_primary' => 1), isset($primary['yes']) && !isset($primary['no']));
     $this->addWhereIf(array('gt_primary' => 0), !isset($primary['yes']) && isset($primary['no']));
     $this->addOption('ORDER BY', 'dist');
     $limit = $params['limit'];
     $this->addOption('LIMIT', $limit);
     $res = $this->select(__METHOD__);
     $result = $this->getResult();
     foreach ($res as $row) {
         if (is_null($resultPageSet)) {
             $title = Title::newFromRow($row);
             $vals = array('pageid' => intval($row->page_id), 'ns' => intval($title->getNamespace()), 'title' => $title->getPrefixedText(), 'lat' => floatval($row->gt_lat), 'lon' => floatval($row->gt_lon), 'dist' => round($row->dist, 1));
             if ($row->gt_primary) {
                 $vals['primary'] = '';
             }
             foreach ($params['prop'] as $prop) {
                 if (isset(Coord::$fieldMapping[$prop]) && isset($row->{$field})) {
                     $field = Coord::$fieldMapping[$prop];
                     $vals[$prop] = $row->{$field};
                 }
             }
             $fit = $result->addValue(array('query', $this->getModuleName()), null, $vals);
             if (!$fit) {
                 break;
             }
         } else {
             $resultPageSet->processDbRow($row);
         }
     }
 }
 private static function doSmartUpdate($coords, $pageId)
 {
     $prevCoords = GeoData::getAllCoordinates($pageId, array(), DB_MASTER);
     $add = array();
     $delete = array();
     foreach ($prevCoords as $old) {
         $delete[$old->id] = $old;
     }
     foreach ($coords as $new) {
         $match = false;
         foreach ($delete as $id => $old) {
             if ($new->fullyEqualsTo($old)) {
                 unset($delete[$id]);
                 $match = true;
                 break;
             }
         }
         if (!$match) {
             $add[] = $new->getRow($pageId);
         }
     }
     $dbw = wfGetDB(DB_MASTER);
     if (count($delete)) {
         $dbw->delete('geo_tags', array('gt_id' => array_keys($delete)), __METHOD__);
     }
     if (count($add)) {
         $dbw->insert('geo_tags', $add, __METHOD__);
     }
 }