skip to Main Content

I’m creating project with Laravel. I want to pull out user->name from subscription table which also has user_id column in it. I want to show the current user’s subscribers’ name from subscription table. But it shows error:

Property [subs] does not exist on this collection instance

here is my code.

This is from IndexController

public function home() {
    $data = User::all();
    return view("amvs.index", [
        'users' => $data,
    ]);
}

This is from index.blade.php

<a href="#" class="list-group-item list-group-item-action border rounded-0">Subscriptions</a>
@foreach ($users->subs as $sub)
    <span class="ms-2">{{$subs->name}}</span>
@endforeach

This is from user model

public function sub(){
    return $this->hasMany('AppModelsSubscription');
}

I didn’t write anything in Subscription model. My subscription table

Schema::create('subscriptions', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->integer('user_id');
    $table->timestamps();
});

My user table

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

I’m a beginner so enlighten me.

2

Answers


  1. First of all, In your controller you should load the subs. That will be better as it will not add extra query for loading the relations. So what you can do is following

    $data = User::with('subs')->all();
    

    you should also change the relationship as hasMany follows the following convention:

       public function subs(){
        return $this->hasMany('AppModelsSubscription');
       }
    

    As you are pulling all the users you have to first loop through the users first, then you can iterate over subs for each users like below:

    @foreach ($users as $user)
        @foreach ($user->subs as $sub)
            <span class="ms-2">{{$subs->name}}</span>
        @endforeach
    @endforeach
    
    Login or Signup to reply.
  2. The issue is that you’re trying to access a method on an Eloquent Collection which does not have any properties or methods relatated to your User or its sub relationship.

    Additionally, consider using Eager Loading when accessing relationships, it is more performant and solves the N+1 query problem.

    public function home() {
        // access the authenticated User and load their subs relationship
        $user = Auth::user()->with('subs')->first();
    
        return view("amvs.index", [
            'user' => $user
        ]);
    }
    

    Then to access the Users subs in your view:

    @foreach ($user->subs as $sub)
    {
        <span class="ms-2">{{$sub->name}}</span>
    }
    

    However, you will want to change your subscriptions migration as the user_id field needs to be the same type as the id field on your users table.

    Schema::create('subscriptions', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->foreignId('user_id');
        $table->timestamps();
    });
    

    Further questions

    don’t know why I should use foreignId?

    For relationships to work, the field type (string, integer etc.) of the primary and foreign key fieds must be the same. The default primary key in Laravel is the id field and it has as type of unsigned big integer. If you define a foreign key field in a related table and its type is anything other than unsignedBigInteger the relationship will fail.

    foreignId is simply a helper method provided by Laravel that creates a field with the correct type and the required foreign key reference. Previously you had to do that all yourself, for example:

    $table->unsignedBigInteger('user_id');
    
    $table->foreign('user_id')->references('id')->on('users');
    

    why you used first()?

    The reason for using first() is that it returns a Model rather than an Eloquent Collection. You’re only interested in one User (the authenticated User) so it is more efficient to use first() rather than get() as you don’t then need to loop or extract the first item in the collection.

    You might want to spend some free time watching the Laravel from Scratch series. It is really detailed and covers lots of common scenarios.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search