/** * 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())); }
/** * @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__); } }