Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_Query.php |
— | — | @@ -44,7 +44,6 @@ |
45 | 45 | protected $m_inline; // query used inline? (required for finding right default parameters) |
46 | 46 | protected $m_concept; // query used in concept? (required for finding right default parameters) |
47 | 47 | protected $m_extraprintouts = array(); // SMWPrintoutRequest objects supplied outside querystring |
48 | | - protected $m_distance = 5; // default is 5 miles |
49 | 48 | |
50 | 49 | /** |
51 | 50 | * Constructor. |
— | — | @@ -155,15 +154,6 @@ |
156 | 155 | return $this->m_limit; |
157 | 156 | } |
158 | 157 | |
159 | | - public function setDistance($distance) { |
160 | | - $this->m_distance = $distance; |
161 | | - return $this->m_distance; |
162 | | - } |
163 | | - |
164 | | - public function getDistance() { |
165 | | - return $this->m_distance; |
166 | | - } |
167 | | - |
168 | 158 | /** |
169 | 159 | * Apply structural restrictions to the current description. |
170 | 160 | */ |
Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore2_Queries.php |
— | — | @@ -179,7 +179,6 @@ |
180 | 180 | $this->m_hierarchies = array(); |
181 | 181 | $this->m_querylog = array(); |
182 | 182 | $this->m_errors = array(); |
183 | | - $this->m_distance = $query->getDistance(); |
184 | 183 | SMWSQLStore2Query::$qnum = 0; |
185 | 184 | $this->m_sortkeys = $query->sortkeys; |
186 | 185 | |
— | — | @@ -596,7 +595,6 @@ |
597 | 596 | * Given an SMWDescription that is just a conjunction or disjunction of |
598 | 597 | * SMWValueDescription objects, create and return a plain WHERE condition |
599 | 598 | * string for it. |
600 | | - * @bug The geo distance code is not secure. Disabled for now. |
601 | 599 | */ |
602 | 600 | protected function compileAttributeWhere($query, SMWDescription $description, $proptable, $valueindex, $operator = 'AND') { |
603 | 601 | $where = ''; |
— | — | @@ -616,20 +614,16 @@ |
617 | 615 | case SMW_CMP_GEQ: $comp = '>='; break; |
618 | 616 | case SMW_CMP_NEQ: $comp = '!='; break; |
619 | 617 | case SMW_CMP_LIKE: |
620 | | - if ($dv->getTypeID() == '_geo') { ///FIXME Insecure code that uses DB contents unescaped in SQL. Disabled for now. |
621 | | -// $comp = '<='; |
622 | | -// $geoarray = explode(",", $value); |
623 | | -// if ((count($geoarray) == 2) && ($geoarray[0] != '') && ($geoarray[1] != '')) { |
624 | | -// $field = "ROUND(((ACOS( SIN($geoarray[0] * PI()/180 ) * SIN(SUBSTRING_INDEX($field, ',',1) * PI()/180 ) + COS($geoarray[0] * PI()/180 ) * COS(SUBSTRING_INDEX($field, ',',1) * PI()/180 ) * COS(($geoarray[1] - SUBSTRING_INDEX($field, ',',-1)) * PI()/180))*180/PI())*60*1.1515),6)"; |
625 | | -// } |
626 | | -// $value = $this->m_distance; |
627 | | - } elseif ( ($fieldtype == 't') || ($fieldtype == 'l') ) { // string data allows pattern matches |
| 618 | + /// TODO: explicitly excluding _geo here is a temporary workaround. Future versions will use peronalised comparators for extensions and not LIKE (requires synchronisation with SemanticMaps to work) |
| 619 | + if ( ($dv->getTypeID() != '_geo') && ( ($fieldtype == 't') || ($fieldtype == 'l') ) ) { // string data allows pattern matches |
628 | 620 | $comp = ' LIKE '; |
629 | 621 | $value = str_replace(array('%', '_', '*', '?'), array('\%', '\_', '%', '_'), $value); // translate pattern |
630 | 622 | } |
631 | 623 | break; |
632 | 624 | } |
633 | | - if ($comp != '') { |
| 625 | + if ($comp == '') { // allow extensions to define their own query conditions |
| 626 | + wfRunHooks( 'smwGetSQLConditionForValue', array(&$where, $description, $query->alias, $fieldname, $this->m_dbs) ); |
| 627 | + } else { |
634 | 628 | $where = "{$query->alias}.{$fieldname}{$comp}" . $this->m_dbs->addQuotes($value); |
635 | 629 | } |
636 | 630 | } |
Index: trunk/extensions/SemanticMediaWiki/includes/SMW_QueryProcessor.php |
— | — | @@ -22,27 +22,6 @@ |
23 | 23 | const CONCEPT_DESC = 2; // query for concept definition |
24 | 24 | |
25 | 25 | /** |
26 | | - * Handle the 'distance' parameter, used for location-based queries |
27 | | - */ |
28 | | - static function setQueryDistance($distance, &$query) { |
29 | | - $dist_components = explode(' ', $distance); |
30 | | - if (count($dist_components) != 2) return; |
31 | | - $dist_num = $dist_components[0]; //str_replace(",", "", $dist2[0]); |
32 | | - if (! is_numeric($dist_num) || $dist_num < 0) return; |
33 | | - $dist_unit = $dist_components[1]; |
34 | | - $metric_units = array("km", "kms", "kilometer", "kilometers", "kilometre", "kilometres", "KM", "KMS", "Kilometer", "Kilometers", "Kilometre", "Kilometres"); |
35 | | - $english_units = array("mile", "mi", "miles", "mis", "Mile", "Miles", "MI", "MIS"); |
36 | | - if (! in_array($dist_unit, $metric_units) && ! in_array($dist_unit, $english_units)) |
37 | | - return; |
38 | | - // if we're still here, set the distance - it's computed as |
39 | | - // a number of miles |
40 | | - if (in_array($dist_unit, $metric_units)) { |
41 | | - $dist_num *= .621371192; |
42 | | - } |
43 | | - $query->setDistance($dist_num); |
44 | | - } |
45 | | - |
46 | | - /** |
47 | 26 | * Parse a query string given in SMW's query language to create |
48 | 27 | * an SMWQuery. Parameters are given as key-value-pairs in the |
49 | 28 | * given array. The parameter $context defines in what context the |
— | — | @@ -134,11 +113,6 @@ |
135 | 114 | $orders = array(); |
136 | 115 | } |
137 | 116 | reset($orders); |
138 | | - // get distance to search for location-based queries |
139 | | - if ( array_key_exists('distance', $params) ) { |
140 | | - $distance = trim($params['distance']); |
141 | | - self::setQueryDistance( $distance, $query ); |
142 | | - } |
143 | 117 | |
144 | 118 | if ( array_key_exists('sort', $params) ) { |
145 | 119 | $query->sort = true; |
Index: trunk/extensions/SemanticMediaWiki/includes/SMW_GlobalFunctions.php |
— | — | @@ -90,16 +90,15 @@ |
91 | 91 | // The dot tells that the domain is not complete. It will be completed |
92 | 92 | // in the Export since we do not want to create a title object here when |
93 | 93 | // it is not needed in many cases. |
94 | | - if ($namespace === null) |
95 | | - { |
| 94 | + if ($namespace === null) { |
96 | 95 | $namespace = $wgServerName; |
97 | 96 | } |
98 | | - |
99 | 97 | if ( !$complete && ($smwgNamespace !== '') ) { |
100 | 98 | $smwgNamespace = '.' . $namespace; |
101 | 99 | } else { |
102 | 100 | $smwgNamespace = $namespace; |
103 | 101 | } |
| 102 | + |
104 | 103 | $wgExtensionFunctions[] = 'smwfSetupExtension'; |
105 | 104 | // FIXME: Can be removed when new style magic words are used (introduced in r52503) |
106 | 105 | $wgHooks['LanguageGetMagic'][] = 'smwfAddMagicWords'; // setup names for parser functions (needed here) |
— | — | @@ -107,6 +106,8 @@ |
108 | 107 | |
109 | 108 | $wgHooks['ParserTestTables'][] = 'smwfOnParserTestTables'; |
110 | 109 | $wgHooks['AdminLinks'][] = 'smwfAddToAdminLinks'; |
| 110 | + // this will move to Semantic Maps in future releases: |
| 111 | + $wgHooks['smwGetSQLConditionForValue'][] = 'smwfGetGeoProximitySQLCondition'; |
111 | 112 | |
112 | 113 | // Register special pages aliases file |
113 | 114 | $wgExtensionAliasesFiles['SemanticMediaWiki'] = $smwgIP . '/languages/SMW_Aliases.php'; |
— | — | @@ -328,6 +329,28 @@ |
329 | 330 | return true; |
330 | 331 | } |
331 | 332 | |
| 333 | +/** |
| 334 | + * Custom SQL query extension for matching geographic coordinates. |
| 335 | + * This hook will be moved to Semantic Maps in the next release. |
| 336 | + * @todo Parsing latitude and longitude from the DB key of the coordinates |
| 337 | + * value is cleary not a good approach. Instead, the geographic coordinate |
| 338 | + * value object should provide functions to access this data directly. |
| 339 | + */ |
| 340 | +function smwfGetGeoProximitySQLCondition(&$where, $description, $tablename, $fieldname, $dbs) { |
| 341 | + $where = ''; |
| 342 | + $dv = $description->getDatavalue(); |
| 343 | + if ( ($dv->getTypeID() != '_geo') || (!$dv->isValid()) || ($description->getComparator() != SMW_CMP_LIKE) ) return true; // only act on certain query conditions |
| 344 | + $keys = $dv->getDBkeys(); |
| 345 | + $geoarray = explode(",", $keys[0]); |
| 346 | + if ((count($geoarray) != 2) || ($geoarray[0] == '') || ($geoarray[1] == '')) return true; // something went wrong |
| 347 | + $latitude = $dbs->addQuotes($geoarray[0]); |
| 348 | + $longitude = $dbs->addQuotes($geoarray[1]); |
| 349 | + // compute distances in miles: |
| 350 | + $distance = "ROUND(((ACOS( SIN({$latitude} * PI()/180 ) * SIN(SUBSTRING_INDEX({$tablename}.{$fieldname}, ',',1) * PI()/180 ) + COS({$latitude} * PI()/180 ) * COS(SUBSTRING_INDEX({$tablename}.{$fieldname}, ',',1) * PI()/180 ) * COS(({$longitude} - SUBSTRING_INDEX({$tablename}.{$fieldname}, ',',-1)) * PI()/180))*180/PI())*60*1.1515),6)"; |
| 351 | + $where = "{$distance} <= " . $dbs->addQuotes("5"); |
| 352 | + return true; |
| 353 | +} |
| 354 | + |
332 | 355 | /**********************************************/ |
333 | 356 | /***** namespace settings *****/ |
334 | 357 | /**********************************************/ |