Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

cbcw's avatar
Level 2

Collection in a collection using pivot - trying to get view

This is my UsersController.php file ...

class UsersController extends Controller
{
    public function index()
    {
        $users = User::All();

        foreach ($users as $user) {
            // ... irrelevent code here ...
            

		// find the kid that matches the current user in the loop
            $kids = Kid::find($user->kid); 

            echo $kids;
 	    };		

        };

        return view('users', ['users' => $users, 'kids' => $kids]);
    }

}

and users.blade.php ...

<td>
	@foreach ($kids as $kid)
		{{ $kid->kid_first_name }}
	@endforeach
</td>

The kid is showing the first name of the last kid in the list for every entry. Why? What is the best way to iterate through a collection within a collection - I already have a pivot table and I can see the data using dd. I can even force an object of data into the right place on the view, but I can not pull any single piece of data for the view... Any help would be tremendously appreciated! Thanks!

0 likes
52 replies
automica's avatar

@cbcw whats your relationship between User and Kid?

is the User a parent and they hasMany Kid?

in User model:

public function kids() {
	return $this->hasMany(Kid::class);
}

With this relationship defined, you should be able to chain your kids from your User so:

$users = User::all();

then your blade will look like:

@foreach($users as $user)
	@foreach($user->kids() as $kid)
		{{ $kid->first_name; }} {{ $kid->last_name; }
	@endforeach;
@endforeach;

BTW the issue with your current code, is at // HERE - At this point, $user is the last user in your $users array.

    foreach ($users as $user) {
            // ... irrelevent code here ...
            };

		// HERE

		// find the kid that matches the current user in the loop
            $kids = Kid::find($user->kid); 
1 like
a4ashraf's avatar

@cbcw

try this in your controller


	public function index()
    	{
        	$users = User::with('kids')->get();

        	return view('users', compact('users'));

    	}

and in blade file

@foreach ($users as $user)
		{{ $user->kids->kid_first_name }}
		{{ $user->kids->kid_last_name }}
		{{ $user->kids->kid_name }}
	@endforeach
cbcw's avatar
Level 2

Thank you for your reply... The relationship between the User/Kid is belongsToMany, both ways.

Whenever I try to use:

@foreach($user->kids as $kid)

I get "Invalid argument supplied for foreach()"

Sorry, the code example is not great, I will fix it. The $kids assignment is within the foreach(users ...) loop.

automica's avatar

@cbcw if its belongsToMany, then you still should be able to get this in your blade.

Loop through all users. Then inside loop through all kids for that user.

@foreach($users as $user)
	@foreach($user->kids() as $kid)
		{{ $kid->first_name; }} {{ $kid->last_name; }
	@endforeach;
@endforeach;

can you show your User model?

cbcw's avatar
Level 2

@a4ashraf Thank you for your reply. My thought is this will not get me the intended results as I need all users listed regardless of them having kids or not.

automica's avatar

@cbcw in that case, you just need to put a condition around your inner loop:

@foreach($users as $user)

{{ $user->first_name }} {{ $user->last_name }}

	@forelse($user->kids() as $kid)
		{{ $kid->first_name; }} {{ $kid->last_name; }
	
	@empty
		// no kids
	@endforelse;
@endforeach;
cbcw's avatar
Level 2

@automica That is my thought as well, but I am still getting the error (Invalid argument supplied for foreach()) at this line...

@foreach($user->kids as $kid)
automica's avatar

can you post your migrations? you mention user.kid which seems usual for this kind of relationship.

your join table should be called

kid_user

// with fields
kid_id,user_id
cbcw's avatar
Level 2

@automica That is exactly what I have.

class CreateKidUserTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('kid_user', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('kid_id');
            $table->unsignedBigInteger('user_id');
            $table->timestamps();

            $table->unique(['kid_id', 'user_id']);

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

        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('kid_user');
    }
}
automica's avatar

in that case, I think as @a4ashraf said, we're missing a pair of brackets.

if you change

@foreach($user->kids as $kid)

to

@foreach($user->kids() as $kid)

does that work?

cbcw's avatar
Level 2

@automica @a4ashraf That last error was my fault... the new error is this: "Call to undefined method App\Models\User::kids() "

User.php:

public function kid()
    {
        return $this->belongsToMany(Kid::class);

    }
automica's avatar

@cbcw

public function kids() // needs to be plural
    {
        return $this->belongsToMany(Kid::class);

    }
cbcw's avatar
Level 2

@automica Now I have a new error... "Trying to get property 'kid_first_name' of non-object"

<td>
@foreach($user->kids() as $kid)
{{ $kid->kid_first_name }}
@endforeach
</td>
automica's avatar

you just need to use the field name you've defined on that model (eg first_name, last_name):

{{ $kid->first_name }} {{ $kid->last_name }
cbcw's avatar
Level 2

@automica The field names are actually:

"kid_first_name" and "kid_last_name"

automica's avatar

lets debug:

drop this in your foreach. it may be there is no kid for that user.

@forelse($user->kids() as $kid)
<?php dump($kid); ?>
@empty
	// no kids
@endforelse;
cbcw's avatar
Level 2

@automica

That dump returns "false" for each of the users, but some of them do have kids.

cbcw's avatar
Level 2

@automica

public function kids()
    {
        return $this->belongsToMany(Kid::class);

    }
a4ashraf's avatar

@cbcw

  • for instance: your kids' table has no match records with user use this
           return $this->belongsToMany(Kid::class)->withDefault([
    	'kid_first_name' => null,
    	'kid_last_name' => null,
    	....
    	...
    ]);
    ``
    
  • for instance your pivot table have no match data
  • for instance your fillable not define
  • for instance your model not in App

try to figure out above

cbcw's avatar
Level 2

@a4ashraf Thanks, but now I have a new error... "Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsToMany::withDefault() "

a4ashraf's avatar

@cbcw

how are you defining and which version of laravel you are using

https://laravel.com/docs/8.x/eloquent-relationships#default-models

To populate the default model with attributes, you may pass an array or Closure to the withDefault method:

/**
 * Get the author of the post.
 */
public function user()
{
    return $this->belongsTo('App\Models\User')->withDefault([
        'name' => 'Guest Author',
    ]);
}

/**
 * Get the author of the post.
 */
public function user()
{
    return $this->belongsTo('App\Models\User')->withDefault(function ($user, $post) {
        $user->name = 'Guest Author';
    });
}

cbcw's avatar
Level 2

@a4ashraf

public function kids()
    {
        return $this->belongsToMany(Kid::class)->withDefault([
            'id' => null,
            'kid_first_name' => null,
            'kid_last_name' => null,
            'kid_unit_id' => null,
            'created_at' => null,
            'updated_at' => null,
            'is_deleted' => null
        ]);

    }

Laravel 8.x

a4ashraf's avatar

@cbcw

first Share your complete model and controller file

and try this

public function kids()
    {
        return $this->belongsToMany(Kid::class)->withDefault([
            'id' => null,
            'kid_first_name' => null,
            'kid_last_name' => null,
            'kid_unit_id' => null,
        ]);

    }
automica's avatar

@cbcw can you also show your migration for kids table.

Does that table have an id column on it?

cbcw's avatar
Level 2

@a4ashraf @automica Model: (with suggested edits)

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Jetstream\HasProfilePhoto;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens;
    use HasFactory;
    use HasProfilePhoto;
    use Notifiable;
    use TwoFactorAuthenticatable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
        'two_factor_recovery_codes',
        'two_factor_secret',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */

    /* protected $appends = [
        'profile_photo_url',
    ]; */

    public function orgs()
    {
        return $this->belongsTo(Org::class);

    }

    public function kids()
    {
        return $this->belongsToMany(Kid::class)->withDefault([
            'id' => null,
            'kid_first_name' => null,
            'kid_last_name' => null,
            'kid_unit_id' => null,
        ]);

    }

}

UsersController.php

<?php

namespace App\Http\Controllers;

use App\Models\User;
use App\Models\Kid;
use Illuminate\Http\Request;

class UsersController extends Controller
{
    public function index()
    {
        $users = User::All();

        foreach ($users as $user) {
            if($user->title_show == 0){
                $user->title = '';
            };


            $kids = Kid::find($user->kids);

            echo $kids;

        };

        return view('users', ['users' => $users, 'kids' => $kids]);
    }

}

and ... create_kids_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateKidsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('kids', function (Blueprint $table) {
            $table->id();

            $table->string('kid_first_name');
            $table->string('kid_last_name');
            $table->string('kid_unit_id');

            $table->timestamps();

            $table->boolean('is_deleted')->default(0);

        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('kids');
    }
}
automica's avatar

@cbcw whilst you are at it, index method should be reduced to:

 public function index()
    {
        $users = User::All();

        return view('users', ['users' => $users]);
    }

in your kid model, make sure you don't have anything in your $protected array as if you do, then these fields won't render.

Next

Please or to participate in this conversation.