I am trying to render all ads from users. Users have latitude and longitude saved in his table, so what I am trying to do is a filter of places that will paint the ads/posts of those users in that area of search (I am using google maps api), but I am receiving constantly this message and I am not able to render the page with Vue.
lluminate\Database\Eloquent\Builder::eagerLoadRelation(): Argument #3 ($constraints) must be of type Closure, array given,
I have Ads and users. A user contains latitude and longitude of a place, this is my model (I have made it shorter):
class User extends Authenticatable {
protected $fillable = [ 'name', 'email', 'email_verified_at', 'password', 'address', 'lat', 'lng' 'published_ad_id' ];
public function ads(){
return $this->hasMany("App\Models\Ad", "published_ad_id");
}
}
And here is my Ads model:
class Ad extends Model
{
use HasFactory;
protected $table = 'ads';
protected $primaryKey = 'id';
protected $fillable = ['user_id','title', 'description', 'image', 'music_genre'];
// protected $guarded = ['created_at', 'updated_at', 'availabilities_id'];
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function availability()
{
return $this->hasOne(Availability::class , 'availabilities_id');
}
}
This would be my controller:
class AnuncioController extends Controller
{
public function index(Request $request)
{
// $anuncios = Ad::query();
$userLocationLat = $request->input('lat');
$userLocationLng = $request->input('lng');
$distance = $request->input('distance');
$nearestUsers = [];
foreach (User::all() as $users){
$distanceBetweenLocations = $this->getDistance($users->lat, $users->lng, $userLocationLat, $userLocationLng);
if ($distanceBetweenLocations <= $distance ){
$nearestUsers[] = $users;
}
// elseif ($userLocationLat == null){
// $nearestUsers[] = $users;
// }
}
$anuncios = Ad::with(['user'=>$nearestUsers])->latest()->paginate(5)->withQueryString();
return Inertia::render('Anuncio/Index', compact('anuncios')
);
}
private function getDistance($point1_lat, $point1_long, $point2_lat, $point2_long, $unit = 'km', $decimals = 2) {
// Calculate the distance in degrees
$degrees = rad2deg(acos((sin(deg2rad($point1_lat))*sin(deg2rad($point2_lat))) (cos(deg2rad($point1_lat))*cos(deg2rad($point2_lat))*cos(deg2rad($point1_long-$point2_long)))));
// Convert the distance in degrees to the chosen unit (kilometres, miles or nautical miles)
switch($unit) {
case 'km':
$distance = $degrees * 111.13384; // 1 degree = 111.13384 km, based on the average diameter of the Earth (12,735 km)
break;
case 'mi':
$distance = $degrees * 69.05482; // 1 degree = 69.05482 miles, based on the average diameter of the Earth (7,913.1 miles)
break;
case 'nmi':
$distance = $degrees * 59.97662; // 1 degree = 59.97662 nautic miles, based on the average diameter of the Earth (6,876.3 nautical miles)
}
return round($distance, $decimals);
}
}
As you can see I am trying to pass users array so I can use it in the part of front but is not working.
In the front I have this vue.js:
<template>
<AppLayout>
<h1>HOLA</h1>
<div v-for="anuncio in anuncios" :key="anuncio.id" >
<div >
<div >{{ anuncio.title }}</div>
<p >
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatibus quia, nulla! Maiores et perferendis eaque, exercitationem praesentium nihil.
</p>
<p>
{{anuncio.description}}
</p>
<p>
{{ anuncio.user.name}}
</p>
</div>
<div >
<span >#photography</span>
<span >#travel</span>
<span >#winter</span>
</div>
</div>
</AppLayout>
</template>
<script>
import AppLayout from "../../Layouts/AppLayout";
export default {
name: "index",
// props: ['restaurants'],
props: {
anuncios: Object
},
components: {AppLayout}
}
</script>
<style scoped>
</style>
I think that the problem is in the controller and how I am passing the data to Ads, but I can't find where I'm doing it wrong or how to get that array.
CodePudding user response:
You should use closure as value and filter inside.
$anuncios = Ad
::with([
'user' => function ($query) use ($nearestUsers) {
$query->whereIn('id', $nearestUsers)
}
])
->latest()
->paginate(5)
->withQueryString();
CodePudding user response:
Try, collecting all user ids to $nearestUsers
array and filter ads from using that array.
Like this,
foreach (User::all() as $users){
$distanceBetweenLocations = $this->getDistance($users->lat, $users->lng, $userLocationLat, $userLocationLng);
if ($distanceBetweenLocations <= $distance ){
$nearestUsers[] = $users->id;
}
}
$anuncios = Ad::with(['user'])->whereIn('user_id', $nearestUsers)->latest()->paginate(5)->withQueryString();