web-dev-qa-db-fra.com

Trouver tous les résultats de la base de données dans un rayon de 500 km de la latitude et de la longitude données

Je suis coincé dans ce problème où la principale exigence est de trouver tous les résultats de la base de données qui se trouvent dans un rayon de 500 miles de la latitude et de la longitude données. J'ai stocké les lati et longi dans le post_meta avec le code postal de ces latitude et longitude. L'idée est que, chaque fois que l'utilisateur recherche un code postal et sélectionne les miles dans le menu déroulant, tous les résultats correspondant à cette requête doivent être recherchés. exemple.

L'utilisateur fait une requête comme celle-ci

500 mi de 51310

La requête doit renvoyer tous les résultats situés à moins de 500 km du code postal 51310.

Voici ce que j'ai fait jusqu'à présent. C'est la fonction principale qui effectue la requête à la base de données.

if (isset($_GET['s']) && !empty($_GET['s'])) {

        $searchterm = isset($q->query_vars['s']) ? sanitize_text_field($q->query_vars['s']) : '';

        // we have to remove the "s" parameter from the query, because it will prevent the posts from being found
        $q->query_vars['s'] = '';

        if ($searchterm != '') {

            $search_radius = $this->geocode($searchterm);

            if (!$search_radius) {
                return false;
            }

            $lat = $search_radius['lat']; // get the lat of the requested address
            $lng = $search_radius['lng']; // get the lng of the requested address
            // we'll want everything within, say, 30km distance
            $distance = isset($_GET['within']) && !empty($_GET['within']) ? floatval($_GET['within']) : 50;

            // earth's radius in km = ~6371
            $radius = auto_listings_metric() == 'yes' ? 6371 : 3950;

            // latitude boundaries
            $maxlat = $lat + rad2deg($distance / $radius);
            $minlat = $lat - rad2deg($distance / $radius);

            // longitude boundaries (longitude gets smaller when latitude increases)
            $maxlng = $lng + rad2deg($distance / $radius / cos(deg2rad($lat)));
            $minlng = $lng - rad2deg($distance / $radius / cos(deg2rad($lat)));

            // build the meta query array
            $radius_array = array(
                'relation' => 'AND',
            );

            $radius_array[] = array(
                'key' => '_al_listing_lat',
                'value' => array($minlat, $maxlat),
                'type' => 'DECIMAL(10,5)',
                'compare' => 'BETWEEN',
            );
            $radius_array[] = array(
                'key' => '_al_listing_lng',
                'value' => array($minlng, $maxlng),
                'type' => 'DECIMAL(10,5)',
                'compare' => 'BETWEEN',
            );

            return apply_filters('auto_listings_search_radius_args', $radius_array);

Et pour trouver le géocode, j'ai écrit cette fonction.

$address = urlencode(esc_html($address));

    // google map geocode api url
    $url = auto_listings_google_geocode_maps_url($address);

    $arrContextOptions = array(
        "ssl" => array(
            "verify_peer" => false,
            "verify_peer_name" => false,
        ),
    );

    // get the json response
    $resp_json = file_get_contents($url, false, stream_context_create($arrContextOptions));

    // decode the json
    $resp = json_decode($resp_json, true);

    //pp( $resp );
    // response status will be 'OK', if able to geocode given address 
    if ($resp['status'] == 'OK') {

        // get the lat and lng
        $lat = $resp['results'][0]['geometry']['location']['lat'];
        $lng = $resp['results'][0]['geometry']['location']['lng'];

        // verify if data is complete
        if ($lat && $lng) {

            return array(
                'lat' => $lat,
                'lng' => $lng,
            );
        } else {
            return false;
        }
    } else {
        return false;
    }

Si je ne sélectionne pas le champ intérieur, ce code renvoie les résultats exacts de ce code postal particulier, ce qui est bon, mais lorsque je sélectionne ce champ, il n’affiche rien. Quelqu'un peut-il me dire ce que je fais mal dans ce code?.

2
Mohsin

Le problème était que lorsque j'envoyais la requête à la base de données, le niveau de mon tableau était modifié, mais la valeur 's' n'était pas vide, ce qui empêchait l'extraction de mes enregistrements. Le troisième et le plus important était le chemin Je faisais ma requête en changeant ma fonction a résolu mon problème.

Voici le code mis à jour pour cette logique au cas où quelqu'un d'autre aurait besoin de créer une telle fonctionnalité.

La fonction principale où toutes les données sont collectées et interrogées

public function pre_get_posts($q) {

    // check if the user is requesting an admin page 
    if (is_admin() || !$q->is_main_query())
        return;

    if (!is_post_type_archive('auto-listing'))
        return;

    if (!is_search())
        return;

    $meta_query = array();

    $year_query[] = $this->year_query();
    $model_query[] = $this->model_query();
    $condition_query[] = $this->condition_query();
    $odometer_query[] = $this->odometer_query();
    $price_query[] = $this->price_meta_query();
    $body_type_query = $this->body_type_query();
    $country_query = $this->country_query();
    $transmission_query = $this->transmission_query();
    $radius_query[] = $this->radius_query($q);

    $query_1 = array_merge($country_query, $year_query, $model_query, $condition_query, $price_query, $odometer_query, $transmission_query);
    // if our radius query fails, fall back to keyword searching
    // will fail with no map API key
    if (empty($radius_query[0]) || !$radius_query[0]) {
        $keyword_query[] = $this->keyword_query($q);
        $query_2 = $keyword_query;
    } else {
        $query_2 = $radius_query;
    }

    // if no keyword
    if (empty($_GET['s'])) {
        $query_1['relation'] = 'AND';
        $meta_query[] = $query_1;
    }

    // if keyword
    if (!empty($_GET['s'])) {
        $query_2['relation'] = 'OR';
        $meta_query[] = $query_1;
        $meta_query[] = $query_2;
        $meta_query['relation'] = 'AND';
    }

    $q->set('meta_query', $meta_query);

    $q->set('tax_query', $body_type_query);

    $q->set('post_type', 'auto-listing');

}

Fonction de requête de rayon qui faisait réellement la magie

public function radius_query($q) {

    if (isset($_GET['s']) && !empty($_GET['s'])) {

        $searchterm = isset($q->query_vars['s']) ? sanitize_text_field($q->query_vars['s']) : '';

        // we have to remove the "s" parameter from the query, because it will prevent the posts from being found
        $q->query_vars['s'] = '';

        if ($searchterm != '') {

            $search_radius = $this->geocode($searchterm);

            if (!$search_radius)
                return false;

            $lat = $search_radius['lat']; // get the lat of the requested address
            $lng = $search_radius['lng']; // get the lng of the requested address
            // we'll want everything within, say, 30km distance
            $distance = isset($_GET['within']) && !empty($_GET['within']) ? floatval($_GET['within']) : 0.1;

            // earth's radius in km = ~6371
            $radius = auto_listings_metric() == 'yes' ? 6371 : 3950;

            // latitude boundaries
            $maxlat = $lat + rad2deg($distance / $radius);
            $minlat = $lat - rad2deg($distance / $radius);

            // longitude boundaries (longitude gets smaller when latitude increases)
            $maxlng = $lng + rad2deg($distance / $radius / cos(deg2rad($lat)));
            $minlng = $lng - rad2deg($distance / $radius / cos(deg2rad($lat)));

            // build the meta query array
            $radius_array = array(
                'relation' => 'AND',
            );

            $radius_array[] = array(
                'key' => '_al_listing_lat',
                'value' => array($minlat, $maxlat),
                'type' => 'DECIMAL(10,5)',
                'compare' => 'BETWEEN',
            );
            $radius_array[] = array(
                'key' => '_al_listing_lng',
                'value' => array($minlng, $maxlng),
                'type' => 'DECIMAL(10,5)',
                'compare' => 'BETWEEN',
            );

            return apply_filters('auto_listings_search_radius_args', $radius_array);
        }
    }
}

Et maintenant, la dernière fonction qui va chercher le long et long du code postal dans lequel l'utilisateur entre

private function geocode($address) {
    // url encode the address
    $address = urlencode(esc_html($address));

    // google map geocode api url
    $url = auto_listings_google_geocode_maps_url($address);

    $arrContextOptions = array(
        "ssl" => array(
            "verify_peer" => false,
            "verify_peer_name" => false,
        ),
    );

    // get the json response
    $resp_json = file_get_contents($url, false, stream_context_create($arrContextOptions));

    // decode the json
    $resp = json_decode($resp_json, true);

    //pp( $resp );
    // response status will be 'OK', if able to geocode given address 
    if ($resp['status'] == 'OK') {

        // get the lat and lng
        $lat = $resp['results'][0]['geometry']['location']['lat'];
        $lng = $resp['results'][0]['geometry']['location']['lng'];

        // verify if data is complete
        if ($lat && $lng) {

            return array(
                'lat' => $lat,
                'lng' => $lng,
            );
        } else {
            return false;
        }
    } else {
        return false;
    }
}

Pour trouver la publication sur la base de cette réponse, le code postal doit être stocké dans la table post_meta pour extraire le lati et le longi, et la formule indiquée dans le code pour rechercher les limites max et min obtiendra le lat et le lng. J'espère avoir donné la réponse en détail, sinon n'hésitez pas à écrire des commentaires.

0
Mohsin