Najpierw przyjrzyjmy się, jak to zrobić za pomocą podstawowego konstruktora zapytań. Następnie omówimy, jak wykonać to zapytanie za pomocą modeli Eloquent:
Funkcjafunction paginateDishesFromPoint(Point $point, $pageSize)
{
$distanceField = "ST_Distance_Sphere(locations.coordinates, "
. "ST_GeomFromText('{$point->toWKT()}') AS distance";
return DB::table('dishes')
->select('dishes.*', DB::raw($distanceField))
->join('dish_locations', 'dish_locations.dish_id', '=', 'dishes.id')
->join('locations', 'locations.id', '=', 'dish_locations.location_id')
->orderBy('distance')
->paginate($pageSize);
}
ST_Distance_Sphere()
funkcja oblicza odległość, według której możemy sortować wyniki. paginate()
Laravela metoda wykonuje dla nas automatyczną paginację za pomocą page
parametr przekazany przez adres URL żądania. Przeczytaj dokumentację podziału na strony
po więcej informacji. Za pomocą powyższej funkcji możemy pobrać zestaw wyników z podziałem na strony w następujący sposób:
$point = new Point($latitude, $longitude);
$sortedDishes = paginateDishesFromPoint($point, 15);
...gdzie Point
to Grimzy\LaravelMysqlSpatial\Types\Point
klasa z pakietu
używamy i 15
to liczba wyników na stronie.
Teraz spróbujmy to zrobić z modelami Eloquent. Użyjemy lokalnego zakresu zapytań aby zawrzeć logikę potrzebną do utworzenia części zapytania, która wykonuje kolejność:
class Dish extends Model
{
...
public function locations()
{
return $this->belongsToMany(App\Location::class);
}
public function scopeOrderByDistanceFrom($query, Point $point)
{
$relation = $this->locations();
$locationsTable = $relation->getRelated()->getTable();
$distanceField = "ST_Distance_Sphere($locationsTable.coordinates, "
. "ST_GeomFromText('{$point->toWKT()}') AS distance";
return $query
->select($this->getTable() . '.*', DB::raw($distanceField))
->join(
$relation->getTable(),
$relation->getQualifiedForeignKeyName(),
'=',
$relation->getQualifiedParentKeyName()
)
->join(
$locationsTable,
$relation->getRelated()->getQualifiedKeyName(),
'=',
$relation->getQualifiedRelatedKeyName()
)
->orderBy('distance');
}
}
Ta implementacja używa metadanych w modelach, aby dodać nazwy tabel i pól do zapytania, więc nie musimy aktualizować tej metody, jeśli ulegną zmianie. Teraz możemy pobrać zamówiony zestaw za pomocą modelu:
$point = new Point($latitude, $longitude);
$sortedDishes = Dish::orderByDistanceFrom($point)->paginate($pageSize);
$sortedDishes
jest instancją LengthAwarePaginator
Laravela która otacza Collection
modeli. Jeśli przekażemy wyniki do widoku, oto jak wyświetlić je w szablonie Blade:
<ul>
@foreach($sortedDishes as $dish)
<li>{{ $dish->name }} is {{ $dish->distance }} meters away.</li>
@endforeach
</ul>
<a href="{{ $sortedDishes->nextPageUrl() }}">Load more...</a>
Jak pokazano powyżej, paginator zapewnia wygodne metody które możemy wykorzystać do łatwego przemieszczania się między stronami wyników.
Alternatywnie możemy użyć żądań AJAX do załadowania wyników. Pamiętaj tylko, aby przekazać bieżącą stronę + 1 na page
parametr danych żądania.