Reputation: 381
I'm trying the following: I have a model, called Pub, that has the following fields: "id","name","address","longitude","latitude","schedule","photo", etc.
As I need to know the distance between Pub and User, so I've created a function that calculates the distance in Pub Model using longitude and latitude:
public function pubDistance()
{
$userLat = '';
$userLong = '';
$pubLat = $this->latitude;
$pubLong = $this->longitude;
if(!($userLat && $userLong))
{
$userLat = 40.4169473;
$userLong = -3.7035285;
}
$earthRadius = 6371;
$latFrom = deg2rad($userLat);
$lonFrom = deg2rad($userLong);
$latTo = deg2rad($pubLat);
$lonTo = deg2rad($pubLong);
$latDelta = $latTo - $latFrom;
$lonDelta = $lonTo - $lonFrom;
$a = pow(cos($latTo) * sin($lonDelta), 2) +
pow(cos($latFrom) * sin($latTo) - sin($latFrom) * cos($latTo) * cos($lonDelta), 2);
$b = sin($latFrom) * sin($latTo) + cos($latFrom) * cos($latTo) * cos($lonDelta);
$angle = atan2(sqrt($a), $b);
$distance = round($angle * $earthRadius, 2);
return $distance;
}
And I use this function here (inside Pub model too):
public function getPubDistanceToUserAttribute()
{
return $this->pubDistance();
}
Then the problem I have is how to add the field to Pub model and use to order my pubs by distance.
The first thing I could do it appending:
protected $appends = ['pub_distance_to_user'];
But I'm having problems in my controller to order by that new field:
public function getPubs()
{
$pubs = Pub::all();
return $pubs;
}
This is what I have:
{
"id": 1,
"name": "Dr. Nikko Braun",
"address": "453 Wyman Crossroad\nSouth Eliashaven, NY 75636",
"longitude": "118.9395890",
"latitude": "-62.3235600",
"schedule": "1986-11-13 10:15:48",
"photo":
"email": "[email protected]",
"phone": "1-841-349-8925 x684",
"pub_distance_to_user": 15556.09
}
How I could use accesors and mutators here, or something like this in this case?...
Thanks a lot!!
Upvotes: 1
Views: 78
Reputation:
Define this in your getPubs function, since $pubs
is a collection we can use the sortBy/sortByDesc method to sort the collection by ascending or descending. In this case we want ascending to have the lowest digit first.
Source: Laravel Documentation / sortBy
Second Source: Similar to this SO answer
public function getPubs()
{
$pubs = Pub::all();
$sorted = $pubs->sortBy('pub_distance_to_user');
return $sorted;
}
Upvotes: 0
Reputation: 40653
I don't think you can do this on the query, but it should be easy to do it on the collection:
$pubs = Pub::all()->sortBy(function ($pub) {
return $pub->pubDistance();
});
Upvotes: 0
Reputation: 1642
Ok so you can add a field in the function getPubs()
by using the foreach loop,
Try this,
public function getPubs()
{
$pubs = Pub::all();
foreach($pubs as $pub){
$pub->pub_distance_to_user = Pub::pubDistance();
}
return $pubs->sortBy('pub_distance_to_user');
}
EDIT:
I think you can define your function to calcluate distance with arguments, like this way
public function pubDistance($pubLat,$pubLong)
{
$userLat = '';
$userLong = '';
if(!($userLat && $userLong))
{
$userLat = 40.4169473;
$userLong = -3.7035285;
}
$earthRadius = 6371;
$latFrom = deg2rad($userLat);
$lonFrom = deg2rad($userLong);
$latTo = deg2rad($pubLat);
$lonTo = deg2rad($pubLong);
$latDelta = $latTo - $latFrom;
$lonDelta = $lonTo - $lonFrom;
$a = pow(cos($latTo) * sin($lonDelta), 2) +
pow(cos($latFrom) * sin($latTo) - sin($latFrom) * cos($latTo) * cos($lonDelta), 2);
$b = sin($latFrom) * sin($latTo) + cos($latFrom) * cos($latTo) * cos($lonDelta);
$angle = atan2(sqrt($a), $b);
$distance = round($angle * $earthRadius, 2);
return $distance;
}
And then you have to call function by Pub::pubDistance($pub->latitude,$pub->longitude);
public function getPubs()
{
$pubs = Pub::all();
foreach($pubs as $pub){
$pub->pub_distance_to_user = Pub::pubDistance($pub->latitude,$pub->longitude);
}
return $pubs->sortBy('pub_distance_to_user');
}
Upvotes: 1
Reputation: 21681
You should try this:
Please add below code with your table field in your model:
/**
* Attributes that should be mass-assignable.
*
* @var array
*/
protected $fillable = ['yorr_field1','yorr_field1','yorr_field3'];
Upvotes: 0