PHP - ParseGeoPoint 上的 Parse SDK 查询无法正常工作



我遇到了一个无法解决的问题,我已经试了好几个星期了,但我就是不知道我做错了什么,或者Parse PHP SDK中是否有问题。

我已经建立了一个以Parse Server为后端的网站,这是一个带有位置检测的列表网站,我正在使用Chrome(我也尝试过Firefox和Safari,我遇到了同样的问题)。

我的步骤:

  1. 当你进入主页时,浏览器会要求你允许位置检测,我允许
  2. 如果你点击位置按钮,你可以打开一个谷歌地图到一个模式,并放置针点击到所需的位置,你也可以通过移动滑块来设置距离范围。我选择英国伦敦
  3. 我在Chrome中得到了正确的控制台消息:

    距离:87公里
    标记纬度:51.522497992110246-标记LNG:-0.12863733794108612

问题来了,网站只显示一些发布的广告,那些我通过移动应用程序发布的广告(我自己的源代码也是,带有Parse iOS和Android SDK),它不显示我通过网站提交的广告。奇怪的是,如果我在网站上发布广告,打开手机应用程序,我就能看到它们!

如果我检查我的数据库,无论我是通过网站还是移动应用程序提交广告,我的广告的GeoPoint坐标都会正确存储。

最后,如果我用页面顶部的搜索栏按关键词进行搜索,我可以找到我在网站上发布的广告。所以,基本上,没有关键词,没有通过网站发布的广告。。。

以下是我查询广告的PHP代码(注意;以$ADS_开头的变量是在另一个文件中声明的简单字符串,例如$ADS_LOCATION="ads_location"等):

/*--- variables ---*/
$isFollowing = $_GET['isFollowing'];
$option = $_GET['option'];
$upObjID = $_GET['upObjID'];
$latitude = $_GET['lat'];   // 51.522497992110246
$longitude = $_GET['lng'];  // -0.12863733794108612
$dist = $_GET['distance'];
$distance = (int)$dist;     // 50
$category = $_GET['category'];
$sortBy = str_replace(' ', '', $_GET['sortBy']);
$keywords = preg_split('/s+/', $_GET['keywords']);
// query Ads
try {
$query = new ParseQuery($ADS_CLASS_NAME);
$query->equalTo($ADS_IS_REPORTED, false);
// it's following.php
if ($isFollowing == true) {
$currentUser = ParseUser::getCurrentUser();
$cuObjIdArr = array(); 
array_push($cuObjIdArr, $currentUser->getObjectId());
$query->containedIn($ADS_FOLLOWED_BY, $cuObjIdArr);
// it's User profile page
} else if ($upObjID != null) {
$userPointer = new ParseUser($USER_CLASS_NAME, $upObjID);
$userPointer->fetch();
$query->equalTo($ADS_SELLER_POINTER, $userPointer);
if ($option == 'selling'){ $query->equalTo($ADS_IS_SOLD, false);
} else if ($option == 'sold'){ $query->equalTo($ADS_IS_SOLD, true); 
} else if ($option == 'liked'){ $query->containedIn($ADS_LIKED_BY, array($userPointer->getObjectId())); }
// it's index.php
} else {
// nearby Ads
if ($latitude != null  &&  $longitude != null) {
$currentLocation = new ParseGeoPoint($latitude, $longitude);
$query->withinKilometers("location", $currentLocation, $distance);

// nearby DEFAULT LOCATION COORDINATES
} else { 
$defaultLocation = new ParseGeoPoint($DEFAULT_LOCATION_LATITUDE, $DEFAULT_LOCATION_LONGITUDE);
$query->withinKilometers($ADS_LOCATION, $defaultLocation, $DISTANCE_IN_KM); 
}
// keywords
if (count($keywords) != 0) { $query->containedIn($ADS_KEYWORDS, $keywords); }
// category
if ($category != "All") { $query->equalTo($ADS_CATEGORY, $category); }
// sort by
switch ($sortBy) {
case 'Newest': $query->descending("createdAt");
break;
case 'Price:lowtohigh': $query->ascending($ADS_PRICE);
break;
case 'Price:hightolow': $query->descending($ADS_PRICE);
break;
case 'MostLiked': $query->descending($ADS_LIKES);
break;
default: break;
}// ./ sort by
}// ./ If

// perform query
$adsArray = $query->find(); 
if (count($adsArray) != 0) {
for ($i = 0;  $i < count($adsArray); $i++) {
// Parse Obj
$adObj = $adsArray[$i];
// image 1
$adImg = $adObj->get($ADS_IMAGE1);
// title
$adTitle = substr ($adObj->get($ADS_TITLE), 0, 24).'...';
// currency
$adCurrency = $adObj->get($ADS_CURRENCY);
// price
$adPrice = $adObj->get($ADS_PRICE);
echo '
<!-- Ad card -->
<div class="col-lg-3 col-md-5 portfolio-item">
<div class="card">
';
// Sold badge
$isSold = $adObj->get($ADS_IS_SOLD);
if ($isSold) { echo '<div class="card-sold-badge"><img src="assets/images/sold-badge.png"></div>'; }
echo '
<a href="ad-info.php?adObjID='.$adObj->getObjectId().'"><img src="'.$adImg->getURL().'"></a>
<div class="card-body">
<p class="card-title"><a href="ad-info.php?adObjID='.$adObj->getObjectId().'">'.$adTitle.'</a></p>
<p class="card-price">'.$adCurrency.' '.$adPrice.'</p>
</div>
</div>
</div>
';
}// ./ For
// no ads
} else {
echo '
<div class="col-lg-12 col-md-12">
<div class="text-center" style="margin-top: 40px; font-weight: 600">No Ads found.</div>
</div>
';
}
// error
} catch (ParseException $e){ echo $e->getMessage(); }

上面的代码来自一个名为query-ads.php的单独文件,它显示在div:中

<div class="row" id="adsGrid"></div>

我执行AJAX函数来调用query-ads.php:

function queryAds(catName, keywords) {
// category
if (catName == null) { catName = "All"; }
document.getElementById("categoryName").innerHTML = '<h5 id="categoryName"><strong>' + catName + '</strong></h5>';
// keywords
if (keywords == null) { keywords = ''; }
// console.log('KEYWORDS: ' + keywords);
// console.log('LAT: ' + latitude + ' -- LNG: ' + longitude);
console.log('DISTANCE: ' + distance + ' Km');
// console.log('SORT BY: ' + sortBy);
$.ajax({
url:'query-ads.php',
data: 'lat=' + latitude + '&lng=' + longitude + '&distance=' + distance + '&category=' + catName + '&keywords=' + keywords + '&sortBy=' + sortBy,
type: 'GET',
success:function(data) {
document.getElementById("adsGrid").innerHTML = data;
}, 
// error
error: function(xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
swal(err.Message);
}});
}

这也是我的JavaScript代码:

var cityStateButton=document.getElementById("cityState");

/*--- variables --*/
// localStorage.clear();
var latitude = localStorage.getItem('latitude');
var longitude = localStorage.getItem('longitude');
var distance = localStorage.getItem('distance');
if (distance == null) { distance = 50; }
var map;
var markers = [];
var geocoder;
var sortBy = document.getElementById('sortByBtn').innerHTML;
console.log("1st LATITUDE: " + latitude + " -- 1st LONGITUDE: " + longitude + ' -- 1st DISTANCE: ' + distance + ' -- 1st SORT BY: ' + sortBy);

// Call functions
if (latitude == null) { getCurrentLocation();
} else { getAddress(); }

// ------------------------------------------------
// MARK: - GET CURRENT LOCATION
// ------------------------------------------------
function getCurrentLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(getPosition, showError);
} else { 
swal("Geolocation is not supported by this browser.");
// set default location coordinates
latitude =  <?php echo $DEFAULT_LOCATION_LATITUDE ?>;
longitude = <?php echo $DEFAULT_LOCATION_LONGITUDE ?>;
getAddress();
}
}
function getPosition(position) {
latitude = position.coords.latitude;
longitude = position.coords.longitude;
getAddress();
}
function showError(error) {
switch(error.code) {
case error.PERMISSION_DENIED:
swal("You have denied your current Location detection.");
break;
case error.POSITION_UNAVAILABLE:
swal("Location information is unavailable.");
break;            
case error.TIMEOUT:
swal("The request to get your current location timed out.");
break;
case error.UNKNOWN_ERROR:
swal("An unknown error occurred.");
break;
}
// set default location
latitude = <?php echo $DEFAULT_LOCATION_LATITUDE ?>;
longitude = <?php echo $DEFAULT_LOCATION_LONGITUDE ?>;
getAddress();
}
function getAddress () {   
// geocoding API
var geocodingAPI = "https://maps.googleapis.com/maps/api/geocode/json?latlng=" + latitude + "," + longitude + "&key=<?php echo $GOOGLE_MAP_API_KEY ?>";
$.getJSON(geocodingAPI, function (json) {
if (json.status == "OK") {
var result = json.results[0];
var city = "";
var state = "";
for (var i = 0, len = result.address_components.length; i < len; i++) {
var ac = result.address_components[i];
if (ac.types.indexOf("locality") >= 0) { city = ac.short_name; }
if (ac.types.indexOf("country") >= 0) { state = ac.short_name; }
}// ./ For
// show city, state
cityStateButton.innerHTML = '<i class="fas fa-location-arrow"></i> &nbsp;' + city + ', ' + state;
// call query
queryAds();
// save gps coordinates
localStorage.setItem('latitude', latitude);
localStorage.setItem('longitude', longitude);
// console.log("LAT (getAddress): " + latitude + " -- LNG (getAddress): " + longitude);
// call function
initMap();
}// ./ If
});
}

//---------------------------------
// MARK - INIT GOOGLE MAP
//---------------------------------
var mapZoom = 12;
function initMap() {  
var location = new google.maps.LatLng(latitude, longitude);
map = new google.maps.Map(document.getElementById('map'), {
zoom: mapZoom,
center: location,
mapTypeId: 'roadmap',
disableDefaultUI: true,
mapTypeControl: false,
scaleControl: false,
zoomControl: false
});
// call addMarker() when the map is clicked.
map.addListener('click', function(event) {
addMarker(event.latLng);
});
// Add a marker in the center of the map.
addMarker(location);
}

function addMarker(location) {
clearMarkers();
var marker = new google.maps.Marker({
position: location,
map: map
});
markers.push(marker);
// set lat & lng based on marker's coordinates
latitude = marker.getPosition().lat();
longitude = marker.getPosition().lng();
console.log("MARKER LAT: " + latitude + " - MARKER LNG: " + longitude);
// zoom & center map based on pin
metersPerPx = 156543.03392 * Math.cos(latitude * Math.PI / 180) / Math.pow(2, mapZoom)
map.setZoom(metersPerPx/2.6);
map.setCenter(marker.getPosition());        
}
function setMapOnAll(map) {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(map);
}// ./ For
}
// Removes the markers from the map, but keeps them in the array.
function clearMarkers() { 
setMapOnAll(null);
markers = [];
}

//---------------------------------
// MARK - GET GPS COORDS FROM ADDRESS
//---------------------------------
function getCoordsFromAddress(address) {   
geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == 'OK') {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
markers.push(marker);
// set coordinates
latitude = results[0].geometry.location.lat();
longitude = results[0].geometry.location.lng();
// save gps coordinates
localStorage.setItem('latitude', latitude);
localStorage.setItem('longitude', longitude);
// console.log("SEARCH LOCATION LAT: " + latitude + " - SEARCH LOCATION LNG: " + longitude);
initMap();
// error
} else { swal('Geocode was not successful for the following reason: ' + status); 
}});
}

我以为这是ParseGeoPoint的问题,但事实并非如此,因为如果我用文本搜索关键词,我可以找到广告。

找到了解决方案,我发布它只是为了防止其他人在Parse PHP SDK上遇到这样的问题,因为它从2018年初就开始了。

在我将广告保存在数据库中的脚本中,我根据提交项目的描述和标题存储小写关键字:

$kStr = $description. " " .$title. " " .$currentUser->getUsername();
$keywords = explode( " ", strtolower($kStr) );

这很好,但由于带有关键字过滤器的PHPParseQuery在关键字数组中至少需要一个空项,我不得不在上面的代码下面添加这一行:

array_push($keywords, "");

通过这种方式,数据库存储所有正确的关键字+一个空关键字:">,下面是数据库中关键字Arrat类型字段的示例:

[
"lorem",
"ad",
"ipsum",
"johndoe",
"" <-- this is the empty item that the SDK needs to properly perform a query in case of additional filters (in my case, a ParseGeopoint one)
]

在ParseServer的开发人员解决这个问题之前,这可能只是一个临时的技巧。它有效,为什么不呢?)

最新更新