Trước tiên, chúng ta hãy xem cách thực hiện việc này với trình tạo truy vấn cơ bản. Sau đó, chúng ta sẽ thảo luận về cách thực hiện truy vấn này với các mô hình 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()
hàm tính toán khoảng cách mà chúng ta có thể sắp xếp kết quả theo. paginate()
của Laravel thực hiện phân trang tự động cho chúng tôi bằng cách sử dụng trang page
tham số được chuyển qua URL yêu cầu. Đọc tài liệu phân trang
để biết thêm thông tin. Với hàm trên, chúng ta có thể tìm nạp một tập hợp kết quả được phân trang như sau:
$point = new Point($latitude, $longitude);
$sortedDishes = paginateDishesFromPoint($point, 15);
... ở đâu Point
là Grimzy\LaravelMysqlSpatial\Types\Point
lớp từ gói
chúng tôi đang sử dụng và 15
là số lượng kết quả trên mỗi trang.
Bây giờ, chúng ta hãy thử làm điều này với các mô hình Eloquent. Chúng tôi sẽ sử dụng phạm vi truy vấn cục bộ để đóng gói logic cần thiết để tạo phần truy vấn thực hiện thứ tự:
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');
}
}
Việc triển khai này sử dụng siêu dữ liệu trên các mô hình để thêm bảng và tên trường vào truy vấn, vì vậy chúng tôi không cần cập nhật phương pháp này nếu chúng thay đổi. Bây giờ chúng ta có thể tìm nạp tập hợp đã sắp xếp bằng cách sử dụng mô hình:
$point = new Point($latitude, $longitude);
$sortedDishes = Dish::orderByDistanceFrom($point)->paginate($pageSize);
$sortedDishes
là một phiên bản của LengthAwarePaginator
của Laravel bao bọc một Collection
của các mô hình. Nếu chúng tôi chuyển kết quả cho một dạng xem, đây là cách hiển thị chúng trong mẫu Blade:
<ul>
@foreach($sortedDishes as $dish)
<li>{{ $dish->name }} is {{ $dish->distance }} meters away.</li>
@endforeach
</ul>
<a href="{{ $sortedDishes->nextPageUrl() }}">Load more...</a>
Như được hiển thị ở trên, trình phân trang cung cấp các phương pháp tiện lợi mà chúng tôi có thể sử dụng để dễ dàng di chuyển giữa các kết quả được phân trang.
Ngoài ra, chúng ta có thể sử dụng các yêu cầu AJAX để tải kết quả. Chỉ cần đảm bảo vượt qua trang hiện tại + 1 trong trang page
tham số của dữ liệu yêu cầu.