Nejprve se podívejme, jak to udělat pomocí základního tvůrce dotazů. Poté probereme, jak provést tento dotaz pomocí modelů Eloquent:
function 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()
funkce vypočítá vzdálenost, podle které můžeme výsledky seřadit. Laravelova paginate()
metoda za nás provádí automatické stránkování pomocí page
parametr předaný přes adresu URL požadavku. Přečtěte si dokumentaci stránkování
Pro více informací. Pomocí výše uvedené funkce můžeme načíst stránkovanou sadu výsledků následovně:
$point = new Point($latitude, $longitude);
$sortedDishes = paginateDishesFromPoint($point, 15);
...kde Point
je Grimzy\LaravelMysqlSpatial\Types\Point
třídy z balíčku
používáme, a 15
je počet výsledků na stránku.
Nyní to zkusme udělat s modely Eloquent. Použijeme místní rozsah dotazu k zapouzdření logiky potřebné k vytvoření části dotazu, která provádí řazení:
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');
}
}
Tato implementace používá metadata na modelech k přidání názvů tabulek a polí do dotazu, takže pokud se změní, nemusíme tuto metodu aktualizovat. Nyní můžeme získat objednanou sadu pomocí modelu:
$point = new Point($latitude, $longitude);
$sortedDishes = Dish::orderByDistanceFrom($point)->paginate($pageSize);
$sortedDishes
je instancí Laravelova LengthAwarePaginator
který obaluje Collection
modelů. Pokud výsledky předáme pohledu, zde je návod, jak je zobrazit v šabloně 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 je uvedeno výše, stránkovač poskytuje pohodlné metody které můžeme použít ke snadnému pohybu mezi stránkovanými výsledky.
Případně bychom mohli k načtení výsledků použít požadavky AJAX. Nezapomeňte předat aktuální stránku + 1 na page
parametr dat požadavku.