Где воздух гор - там тишина снегов, молчание камней и дремлет сила

Программирование Web

Laravel 5 и Google Maps: используем Gmaps API для построение специализированного поиска

2019-10-18 09:25:25







Google Maps API очень мощный инструмент, который позволяет получать массу информации, нужно только немного его изучить. Лучше всего это попробовать на примере. Давайте напишем проект, который будет получать информацию с карт об объектах и выводить ее в виде результата. Предположим, нам нужно будет получать информацию о рейтингах.

Создадим стандартный проект на Laravel 5. Получим Google API Key и поместим в файл .env Далее напишем контроллер SearchController.php и запрос для валидации SearchRequest. Валидатор будет использоваться в нашей форме поиска.


<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class SearchRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [

'query' => 'required |min:3|max:25',

];
}


public function messages()
{
return [

'query.required' => 'Enter the search request',


];
}



}


Далее следует код котролера:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\User;
use Illuminate\Support\Facades\Auth;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
use App\Http\Requests\SearchRequest;


class GMSearchController extends Controller
{


public function __construct()
{
$this->middleware('auth');
}


public function index(){

return view('search.index');

}



}





Мы подключаем пакет GuzzleHttp\Client, который является реализацией cURL для Laravel. Он будет использоваться для вызова http запросов.


Метод index будет загружать форму поиска и больше ничего. Вот его исходный код:


@extends('layouts.app')
@section('title', 'Index')
@section('content')
<div class="container">
<div class="row text-center">
<h2>Search:</h2>
<div class="form-group">
<form class="typeahead" role="search" method="GET" action= "{{ url('search') }}">
<div class="form-group">
@if ($errors->has('query'))
<span class="help-block">
<strong>{{ $errors->first('query') }}</strong>
</span>
@endif
<input type="search" name="query" id="query" placeholder="restaurants amsterdam" type="search">
</div>
<div class="form-group">
<input id="btn-submit" class="btn btn-send-message btn-md" value="Search" type="submit">
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection


Как видите, ничего сложного. Далее у нас главный метод поиска:


public function search(SearchRequest $request) {

$query = $request->get('query');
$request = urlencode($query);

$client = new \GuzzleHttp\Client();

$response = $client->get('https://maps.googleapis.com/maps/api/place/textsearch/json?query='.$query.'&key='.env('GOOGLE_API_KEY'));


$searches = $response->getBody()->getContents();
$info = json_decode($searches, true);

return view('search.search')->with('query',$query)->with('info',$info);


}



Давайте разберем его детально. В первых двух строках мы получаем запрос из формы и перекодируем его в удобный формат. Затем создаем объект класса GuzzleHttp\Client и отправляем запрос к Google Maps API в формате json. После мы получаем ответ, декодируем и сохраняем в переменной, чтобы передать в файл представления, вместе с поисковым запросом.

Основную работу будет исполнять обработчик вместе со JS скрипт в представлении:


@extends('layouts.app')
@section('title', 'Search results')
@section('content')
<div class="container">
<div class="row text-center">
<h2>Search:</h2>
<div class="form-group">
<form class="typeahead" role="search" method="GET" action="{{ url('search') }}">
<div class="form-group">
@if ($errors->has('query'))
<span class="help-block">
<strong>{{ $errors->first('query') }}</strong>
</span>
@endif
<input type="search" name="query" id="query" placeholder="restaurants amsterdam" type="search">
</div>
<div class="form-group">
<input id="btn-submit" class="btn btn-send-message btn-md" value="Search" type="submit">
</button>
</div>
</form>


В начале мы снова выводим уже известную нам поисковую форму. Далее у нас отображается строка запроса.


<div class="container">

<h4>Query:
<i>{{$query}} </i>
</h4>

<style>

#map {
width: 600px;
height: 500px;
}

#infor {
display: flex;
flex-wrap: wrap;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(450px, 1fr));
}
</style>



Здесь, в этом divе у нас будет отображаться карта


<div id="map" style="height: 600px; width: 500px;"></div>


Теперь самый главный элемент проекта, JS скрпит, в который мы добавили РНР код.

<script type="text/javascript">
function initMap() {
var locations = [
@foreach ( $info['results'] as $loc)
["{!! $loc['rating']!!}",
{!! $loc['geometry']['location']['lat']!!},
{!! $loc['geometry']['location']['lng']!!},
],
@endforeach
];

Первым делом мы передаем начальную точку поиска в массив locations, это географические координаты, а также данные о рейтинге. Другой массив loc с координатами служит для заполнения массива объектов маркеров.



var loc = {
lat: {!! $info['results'][0]['geometry']['location']['lat'] !!},
lng: {!! $info['results'][0]['geometry']['location']['lng'] !!}
};
Эти маркеры служат для создания списка нестандартных маркеров, содержимое которых мы заполним далее. Эти маркеры будут в виде кругов на карте, разного цвета, в зависимости от рейтинга. Если рейтинг от 1 до 2.5, то маркер будет красного цвета, если от 2.6 до 3.2, то желтого и так далее. Максимальный рейтинг равен 5.

var map = new google.maps.Map(document.getElementById('map'), {
zoom: 12,
center: loc,
mapTypeId: google.maps.MapTypeId.ROADMAP
});

var infowindow = new google.maps.InfoWindow;

var marker, i;
var mtitle = "@php echo $query; @endphp";
for (i = 0; i < locations.length; i++) {
var сolor = "";
if (locations[i][0] >=1 && locations[i][0] <= 2.5) {
color= "red";
} else if (locations[i][0] >=2.6 && locations[i][0] <= 3.2) {
color= "yellow";

} else if (locations[i][0] >=3.3 && locations[i][0] <= 4) {
color= "orange";
} else if (locations[i][0] >=4.1 && locations[i][0] <= 5) {
color= "green";
}
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map,
label: locations[i][0],
title: mtitle,
icon: {
fillColor: color,
fillOpacity: 0.5,
path: google.maps.SymbolPath.CIRCLE,
scale: 26,
strokeColor: "#000099",
strokeWeight: 1.0
}

});

После этого мы заполняем объект окна InfoWindow, помещаем туда данные из массива locations.

google.maps.event.addListener(marker, 'click', (function (marker, i) {
return function () {
map.setCenter(marker.getPosition());
infowindow.setContent(locations[i][0]);
infowindow.open(map, marker);
}
})(marker, i));
}

}

</script>

<script src="https://maps.googleapis.com/maps/api/js?key={{ env('GOOGLE_API_KEY')}}&callback=initMap&libraries=places"
async defer></script>






И на конец, выводим список полученных объектов с такой информацией: адресом, название, общим числом отзывов, средним рейтингом и ссылкой на фото от посетителя.




@foreach ( $info['results'] as $data)
<div id="info">
<b>Address:{!! $data['formatted_address']!!}<br>
Name:{!! $data['name']!!} <br>
Total User Rating: {!! $data['user_ratings_total']!!}
<br>User Rating <h5>{!! $data['rating']!!} <br>
Photo Reference: {!! $data['photos']['0']['html_attributions']['0']!!}
<br>
</b>
</h5>


@endforeach




@endsection


Как видите, получилось интересно и относительно просто. На этом все.

Здесь нет комментариев


Новый комментарий:
























Яндекс.Метрика