Laten we eerst eens kijken hoe we dit kunnen doen met de basisquerybuilder. Vervolgens bespreken we hoe u deze query kunt uitvoeren met Eloquent-modellen:
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);
}
De ST_Distance_Sphere()
functie berekent een afstand waarop we resultaten kunnen sorteren. Laravel's paginate()
methode voert automatische paginering voor ons uit met behulp van de page
parameter doorgegeven via de aanvraag-URL. Lees de pagination docs
voor meer informatie. Met de bovenstaande functie kunnen we als volgt een gepagineerde resultatenset ophalen:
$point = new Point($latitude, $longitude);
$sortedDishes = paginateDishesFromPoint($point, 15);
...waar Point
is de Grimzy\LaravelMysqlSpatial\Types\Point
class van het pakket
we gebruiken, en 15
is het aantal resultaten per pagina.
Laten we dit nu proberen met Eloquent-modellen. We gebruiken een lokaal zoekbereik om de logica in te kapselen die nodig is om het deel van de query te maken dat de bestelling uitvoert:
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');
}
}
Deze implementatie gebruikt metadata op de modellen om de tabel- en veldnamen aan de query toe te voegen, dus we hoeven deze methode niet bij te werken als ze veranderen. Nu kunnen we de bestelde set ophalen met het model:
$point = new Point($latitude, $longitude);
$sortedDishes = Dish::orderByDistanceFrom($point)->paginate($pageSize);
$sortedDishes
is een instantie van Laravel's LengthAwarePaginator
die een Collection
omhult van de modellen. Als we de resultaten doorgeven aan een weergave, kunt u ze als volgt weergeven in een Blade-sjabloon:
<ul>
@foreach($sortedDishes as $dish)
<li>{{ $dish->name }} is {{ $dish->distance }} meters away.</li>
@endforeach
</ul>
<a href="{{ $sortedDishes->nextPageUrl() }}">Load more...</a>
Zoals hierboven weergegeven, biedt de paginator gemaksmethoden die we kunnen gebruiken om gemakkelijk tussen paginaresultaten te schakelen.
Als alternatief kunnen we AJAX-verzoeken gebruiken om de resultaten te laden. Zorg ervoor dat u de huidige pagina + 1 doorgeeft op de page
parameter van de verzoekgegevens.