Lassen Sie uns zunächst einen Blick darauf werfen, wie Sie dies mit dem einfachen Abfrage-Generator tun. Dann besprechen wir, wie diese Abfrage mit Eloquent-Modellen ausgeführt wird:
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);
}
Die ST_Distance_Sphere()
Funktion berechnet eine Entfernung, nach der wir die Ergebnisse sortieren können. Laravels paginate()
-Methode führt für uns mithilfe der page
eine automatische Paginierung durch -Parameter, der über die Anforderungs-URL übergeben wird. Lesen Sie die Paginierungsdokumentation
für mehr Informationen. Mit der obigen Funktion können wir eine paginierte Ergebnismenge wie folgt abrufen:
$point = new Point($latitude, $longitude);
$sortedDishes = paginateDishesFromPoint($point, 15);
...wo Point
ist der Grimzy\LaravelMysqlSpatial\Types\Point
Klasse aus dem Paket
wir verwenden, und 15
ist die Anzahl der Ergebnisse pro Seite.
Versuchen wir dies nun mit Eloquent-Modellen. Wir verwenden einen lokalen Abfragebereich um die Logik zu kapseln, die benötigt wird, um den Teil der Abfrage zu erstellen, der die Reihenfolge ausführt:
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');
}
}
Diese Implementierung verwendet Metadaten in den Modellen, um die Tabellen- und Feldnamen zur Abfrage hinzuzufügen, sodass wir diese Methode nicht aktualisieren müssen, wenn sie sich ändern. Jetzt können wir den bestellten Satz mit dem Modell abrufen:
$point = new Point($latitude, $longitude);
$sortedDishes = Dish::orderByDistanceFrom($point)->paginate($pageSize);
$sortedDishes
ist eine Instanz von Laravels LengthAwarePaginator
die eine Collection
umschließt der Modelle. Wenn wir die Ergebnisse an eine Ansicht übergeben, können Sie sie wie folgt in einer Blade-Vorlage anzeigen:
<ul>
@foreach($sortedDishes as $dish)
<li>{{ $dish->name }} is {{ $dish->distance }} meters away.</li>
@endforeach
</ul>
<a href="{{ $sortedDishes->nextPageUrl() }}">Load more...</a>
Wie oben gezeigt, bietet der Paginator bequeme Methoden die wir verwenden können, um einfach zwischen Seitenergebnissen zu wechseln.
Alternativ könnten wir AJAX-Anfragen verwenden, um die Ergebnisse zu laden. Stellen Sie einfach sicher, dass Sie die aktuelle Seite + 1 übergeben auf der page
Parameter der Anfragedaten.