首页 > 解决方案 > PHP - ParseGeoPoint 上的 Parse SDK 查询无法正常工作

问题描述

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

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

我的步骤:

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

    距离:87 公里
    标记 LAT: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,但事实并非如此,因为如果我对关键字进行文本搜索,我可以找到广告。

标签: javascriptphpgoogle-maps-api-3parse-platform

解决方案


找到了解决方案,我发布它以防其他人在 Parse PHP SDK 上遇到此类问题,因为它自 2018 年初就存在。

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

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

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

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)
]

在 Parse Server 的开发人员解决此问题之前,这可能只是一个临时技巧。它有效,所以为什么不;)


推荐阅读