【问题标题】:PHP - Parse SDK query on ParseGeoPoint doesn't work properlyPHP - ParseGeoPoint 上的 Parse SDK 查询无法正常工作
【发布时间】:2019-01-17 14:36:24
【问题描述】:

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

我已经建立了一个以 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 的问题,但事实并非如此,因为如果我对关键字进行文本搜索,我可以找到广告。

【问题讨论】:

  • 您的代码不是最小的,不能按原样用于重现问题。我们没有您的任何数据,我们不知道您尝试调试什么。 $ADS_LOCATION 是什么?它在哪里定义?网站仅显示一些已发布的广告 ...为什么?哪些被退回?哪些不是?事实上,这个问题应该被关闭。
  • 好吧,也许结束这个问题太多了,在提出改进这个问题的建议后停下来会更好:) 这就是让世界变得更美好的原因
  • $ADS_LOCATION 只是在另一个php文件中声明的字符串,它是“位置”,当你构建Parse Server查询时,你需要将你的数据库的列名设置为第一个参数
  • 我知道它应该是什么。这就是为什么我要问里面有什么。尽管如此,我们没有您的数据,所以我想不出任何人可以提供帮助,但我可能错了......我的意思是应该关闭它,因为我会投票关闭它,但赏金问题无法关闭。问题应该包含MCVE 而这个没有。
  • @MrUpsidown 我理解你的意思,也许问题应该只是:“ParseGeoPoint 查询在 Parse Server 的 PHP SDK 上工作正常吗?”。因为,正如我在问题中所解释的,数据库显示了所有正确的数据,所以如果我通过网站发布广告,它会显示在移动应用程序中,但不会显示在 wesbite 中。反之亦然,如果我从移动应用发布广告,它会显示在网站上(当然还有应用):(

标签: javascript php google-maps-api-3 parse-platform


【解决方案1】:

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

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

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

这工作正常,但由于带有关键字过滤器的 PHP ParseQuery 至少需要关键字数组中的一个空项,我不得不在上面的代码下面添加这个简单的行:

array_push($keywords, "");

这样,数据库存储所有正确的关键字+一个空的:“”,这里是关键字Arrat-type字段在数据库中的示例:

[
  "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 的开发人员修复此问题之前,这可能只是一个临时技巧。它有效,为什么不呢;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    相关资源
    最近更新 更多