Home > Software design >  Argument #3 ($constraints) must be of type Closure, array given
Argument #3 ($constraints) must be of type Closure, array given

Time:05-08

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();
  • Related