Първо, нека да разгледаме как да направите това с основния конструктор на заявки. След това ще обсъдим как да изпълним тази заявка с моделите 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()
функцията изчислява разстояние, по което можем да сортираме резултатите. paginate()
на Laravel методът извършва автоматично разделяне на страници вместо нас с помощта на page
параметър, предаден през URL адреса на заявката. Прочетете документите за пагинация
за повече информация. С функцията по-горе можем да извлечем набор от резултати с пагинация, както следва:
$point = new Point($latitude, $longitude);
$sortedDishes = paginateDishesFromPoint($point, 15);
...където Point
е Grimzy\LaravelMysqlSpatial\Types\Point
клас от пакета
ние използваме, и 15
е броят на резултатите на страница.
Сега, нека се опитаме да направим това с моделите Eloquent. Ще използваме локален обхват на заявката за да капсулирате логиката, необходима за създаване на частта от заявката, която изпълнява подреждането:
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');
}
}
Тази реализация използва метаданни за моделите, за да добави имената на таблицата и полетата към заявката, така че не е необходимо да актуализираме този метод, ако се променят. Сега можем да извлечем поръчания комплект с помощта на модела:
$point = new Point($latitude, $longitude);
$sortedDishes = Dish::orderByDistanceFrom($point)->paginate($pageSize);
$sortedDishes
е екземпляр на LengthAwarePaginator
на Laravel който обвива Collection
на моделите. Ако предадем резултатите на изглед, ето как да ги покажем в Blade шаблон:
<ul>
@foreach($sortedDishes as $dish)
<li>{{ $dish->name }} is {{ $dish->distance }} meters away.</li>
@endforeach
</ul>
<a href="{{ $sortedDishes->nextPageUrl() }}">Load more...</a>
Както е показано по-горе, пагинаторът предоставя удобни методи които можем да използваме за лесно придвижване между страниците с резултати.
Като алтернатива можем да използваме AJAX заявки за зареждане на резултатите. Просто не забравяйте да предадете текущата страница + 1 в page
параметър на данните за заявката.