Pertama, mari kita lihat bagaimana melakukan ini dengan pembuat kueri dasar. Kemudian, kita akan membahas cara mengeksekusi kueri ini dengan 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()
fungsi menghitung jarak yang kita dapat mengurutkan hasil. paginate()
Laravel's metode melakukan pagination otomatis untuk kami menggunakan page
parameter melewati URL permintaan. Baca dokumen pagination
untuk informasi lebih lanjut. Dengan fungsi di atas, kita dapat mengambil set hasil paginasi sebagai berikut:
$point = new Point($latitude, $longitude);
$sortedDishes = paginateDishesFromPoint($point, 15);
...di mana Point
adalah Grimzy\LaravelMysqlSpatial\Types\Point
kelas dari paket
yang kami gunakan, dan 15
adalah jumlah hasil per halaman.
Sekarang, mari kita coba melakukan ini dengan model Eloquent. Kami akan menggunakan cakupan kueri lokal untuk merangkum logika yang diperlukan untuk membuat bagian kueri yang melakukan pengurutan:
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');
}
}
Implementasi ini menggunakan metadata pada model untuk menambahkan nama tabel dan bidang ke kueri sehingga kami tidak perlu memperbarui metode ini jika berubah. Sekarang kita dapat mengambil himpunan terurut menggunakan model:
$point = new Point($latitude, $longitude);
$sortedDishes = Dish::orderByDistanceFrom($point)->paginate($pageSize);
$sortedDishes
adalah turunan dari LengthAwarePaginator
Laravel yang membungkus Collection
dari model. Jika kita meneruskan hasilnya ke tampilan, berikut cara menampilkannya dalam template Blade:
<ul>
@foreach($sortedDishes as $dish)
<li>{{ $dish->name }} is {{ $dish->distance }} meters away.</li>
@endforeach
</ul>
<a href="{{ $sortedDishes->nextPageUrl() }}">Load more...</a>
Seperti yang ditunjukkan di atas, paginator menyediakan metode praktis yang dapat kita gunakan untuk berpindah antar halaman hasil dengan mudah.
Atau, kita bisa menggunakan permintaan AJAX untuk memuat hasil. Pastikan untuk melewati halaman saat ini + 1 di page
parameter data permintaan.