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

MohcinBN's avatar

Adding new pack with courses

Hello, I'm working on a project who have one of his features adding new Packs that contains many courses, also courses can have many packs it's mean as I know the ManyToMany relationship so I should work with pivot table.

I have already courses in my Database, I want to add a new pack with courses, It didn't work. I will list below all my current working on code. Thanks in advance for help

Course Model:

public function packs()
{
    return $this->belongsToMany(Pack::class);
}

Pack Model:

public function course()
{
    return $this->hasMany(Course::class);
}

My Blade:

                <form action="{{ route('pack.store') }}" method="POST" enctype="multipart/form-data">
                    @csrf
                    @method('POST')

                    <div class="mb-4">
                        <label for="name">Name</label>
                        <input type="text" class="form-control" id="name" name="name" required="" placeholder="Name">
                    </div>
                    <div class="mb-4">
                        <label for="course_id">Select Course for this pack <span style="color: red;">*</span></label>
                        @foreach ($courses as $course)
                            <div class="form-check">
                                <input type="checkbox" name="course_id[]" value="{{ $course->id }}" id="course_id">
                                <label for="course_id">{{ $course->title }}</label>
                            </div>
                        @endforeach
                    </div>

                    <button class="btn btn-outline-success" type="submit">Create Pack</button>
                </form>

PackController:

public function store(StorePackRequest $request)
{
    $newPack = new Pack;

    $newPack->name = $request->name;

    $newPack->courses()->attach($request->course_id);

    dd($newPack);
    $newPack->save();

    return redirect()->route('pack.create')->with('status', ' The pack has been created with selected courses');
}

Pivot table migration:

    Schema::create('course_pack', function (Blueprint $table) {
        $table->id();
        $table->foreignId('course_id')->nullable()->constrained();
        $table->foreignId('pack_id')->nullable()->constrained();
        $table->timestamps();
    });
0 likes
38 replies
tykus's avatar
tykus
Best Answer
Level 104

The Pack model should also be a belongsToMany

public function courses()
{
    return $this->belongsToMany(Course::class);
}

Then save the Pack before attaching:

public function store(StorePackRequest $request)
{
    $newPack = new Pack;
    $newPack->name = $request->name;
    $newPack->save();

    $newPack->courses()->attach($request->course_id);

    return redirect()->route('pack.create')->with('status', ' The pack has been created with selected courses');
}
1 like
MohcinBN's avatar

@tykus I will try your solution and return to you, then If I want to assign user to the pack? it's also belongsToMany?

tykus's avatar

@MohcinBounouara

If I want to assign user to the pack? it's also belongsToMany?

Not necessarily; how would you describe the relationship - does a Pack belong to a User (so user_id column on the packs table)?

1 like
MohcinBN's avatar

@tykus Understood, I have another ask if you don't mind; I try to access the property title in the course that is in relation with pack in the pack_course like below:

    $packs = Pack::with('courses')->first();
    $packs->courses()->title;
    dd($packs);

I got: Undefined property: Illuminate\Database\Eloquent\Relations\BelongsToMany::$title

tykus's avatar

@MohcinBN $packs->courses() - returns a Relation Builder, not a Collection of Pack instances. Because it is a belongsToMany, the property ($packs->courses) is a Collection - so $packs->courses->title will not work either; you would need to iterate:

$packs = Pack::with('courses')->first();
foreach ($packs->courses as $course) {
    dump($course->title);
}
1 like
MohcinBN's avatar

@tykus Understood, this is work when you use first(), but when you use get() it did not work?

tykus's avatar

@MohcinBN because get returns a Collection of Pack instances; and every Pack instance has a Collection of Course instances. So, you need a nested loop:

$packs = Pack::with('courses')->get();
foreach ($packs as $pack) {
    foreach ($pack->courses as $course) {
        dump($course->title);
    }
}
MohcinBN's avatar

@tykus Thank you for your time,

My controller:

public function index()
{
    $packs = Pack::all();
    $packs_courses = Pack::with('courses')->first();
    return view('backend.packs.index', compact('packs', 'packs_courses'));
    //dd($packs);
    return "Index Packs";
}

My Blade:

        <tbody>
            <!-- Item -->
            @foreach ($packs as $pack)
                <tr>
                    <td><a href="#" class="text-primary fw-bold">{{ $pack->id }}</a> </td>
                    <td>
                        {{ $pack->name }}
                    </td>
                    <td>
                        @foreach ($packs_courses->courses as $course)
                            {{ $course->title }}
                        @endforeach
                    </td>
                    <td>
                        {{ $pack->created_at }}
                    </td>
                    <td>
                        <a href=""><button class="btn btn-pill btn-outline-gray-800" type="button">Edit</button></a>

                        <form method="POST" action="" style="float: right;">
                            @csrf
                            <input name="_method" type="hidden" value="DELETE">

                            <button type="submit" class="btn btn-danger btn-flat show-alert-before-delete-lesson btn-sm"
                                data-toggle="tooltip" title='Delete'>Delete</button>

                        </form>
                    </td>
                </tr>
                <!-- End of Item -->
            @endforeach
        </tbody>

But I did not got the courses related to the pack?

MohcinBN's avatar

@tykus Hello, here If i want to assign user to pack, this is my logic can you help?

In Pack Model:

public function packs()
{
    return $this->belongsToMany(Pack::class);
}

In user Model:

public function packs()
{
    return $this->belongsToMany(Pack::class);
}

User migration:

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->forignId('pack_id')->constrained();
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password');
        $table->rememberToken();
        $table->timestamps();
    });
}
tykus's avatar

@MohcinBN the relationships are not right. Can you describe what it should be in words A Pack ....... User(s)?

MohcinBN's avatar

@tykus I make an error when I paste the user model relationships, should be this: public function users() { return $this->belongsTo(User::class); }

tykus's avatar

@MohcinBN sure, but it is not just that... you have pack_id on the users table, so it is not belongsTo either. That is why I asked you to describe what you need the relation to be.

MohcinBN's avatar

@tykus I have pack that have many courses, that is already done as a first task, now I want o assign pack to user so this user can access this pack (Or many pack) so he/she can see and learn just courses in their pack? hope it's clear. thanks

tykus's avatar

@MohcinBN so a Pack belongs to a User and a User can have many Packs?

If that is the case, the packs table should have a user_id column, and the relationships will be

// User model
public function packs()
{
    return $this->hasMany(Pack::class);
}
// Pack model
public function user()
{
    return $this->belongsTo(User::class);
}
1 like
MohcinBN's avatar

@tykus Done, so what is the logic to assign pack to user? we need to iterate to all users in pack edit blade to check selected user?

tykus's avatar

@MohcinBN in the same Controller action as before? Where does the User come from; is it the authenticated user, or a User ID in the Request? Once you have the User instance, you can create the Pack using the relationship:

public function store(StorePackRequest $request)
{
    $user = auth()->user(); //or
//  $user = User::findOrFail($request->input('user_id'));

    $newPack = $user->packs()->create([
        'name' => $request->name,
    ]);
    $newPack->courses()->attach($request->course_id);

    return redirect()->route('pack.create')->with('status', ' The pack has been created with selected courses');
}
MohcinBN's avatar

@tykus I will iterate over all user and maybe I would go with multiple user select so the user will come from request, I did that but i got: Method Illuminate\Database\Eloquent\Collection::packs does not exist. Even if my packs function are defined on the user model as before

tykus's avatar

@MohcinBN each User has packs, but the Collection of Users does not. Show me how you're using it...

MohcinBN's avatar

@tykus So I will go with assign one user to many packs,

    //$user = auth()->user(); //or
    $user = User::findOrFail($request->user_id);

    $newPack = $user->packs()->create([
        'name' => $request->name,
    ]);
    $newPack->courses()->attach($request->course_id);

    return redirect()->route('pack.create')->with('status', ' The pack has been created with selected courses'); 
tykus's avatar

And, $request->user_id is an integer or an array of integers???

MohcinBN's avatar

@tykus I want it to be an array, because I want to select more that user to assign to the pack.

tykus's avatar

@MohcinBN okay 🤦‍♂️.... in that case it must be a belongsToMany - I misunderstood what you meant by we need to iterate to all users in pack edit blade to check selected user? - The previous implementation with pack_id on the users table confused matters!

You need a pack_user pivot table with user_id and pack_id foreign keys. Then, attaching is similar to the existing courses relationship:

// User model
public function packs()
{
    return $this->belongsToMany(Pack::class);
}
// Pack model
public function users()
{
    return $this->belongsToMany(User::class);
}
public function store(StorePackRequest $request)
{
    $pack = Pack::create([
        'name' => $request->name,
    ]);
    $pack->users()->attach($request->user_id);
    $pack->courses()->attach($request->course_id);

    return redirect()->route('pack.create')->with('status', ' The pack has been created with selected courses');
}
1 like
MohcinBN's avatar

@tykus AlAll is fine, thank you, that what I'm tried to explain in the beginning but i did not explain it clearly, thank you.. I'm now will work the edit part and I will be finishing with the back-end MVP, So I will start with front, every user will wee the packs assigned so will see the courses assigned..

MohcinBN's avatar

@tykus Hello. I'm stuck in a point, I'll be thankful if you help, So I'm now able to loop through packs related to the identified user, I want when click to course name to go to the course details, after show lessons under this course when click on every lesson see his details.

In my course Model: public function lessons() { return $this->hasMany(Lesson::class); }

In my lesson model: public function course() { return $this->belongsTo(Course::class); }

Frontend Controller / Pack controller:

public function index()
{
    //$userPacks = Auth::user()->packs()->get();
    $userPacksWithCourses = Auth::user()->packs()->with('courses')->get();
    //dd($userPacksWithCourses);
    return view('frontend.pack.index', compact('userPacksWithCourses'));
}

index that list the packs releated to auth user:

        @foreach ($userPacksWithCourses as $userPacksWithCourse)
            <h1 class="avenir-black title-thefirst">{{ $userPacksWithCourse->name }}</h1>
       @foreach ($userPacksWithCourse->courses as $course)
                        <h3 class="avenir-black title-paragraph">{{ $course->title }}
		@endforeach
		@endforeach   
tykus's avatar

@MohcinBN you need a link

foreach ($userPacksWithCourses as $userPacksWithCourse)
    <h1 class="avenir-black title-thefirst">{{ $userPacksWithCourse->name }}</h1>
    @foreach ($userPacksWithCourse->courses as $course)
        <a href="{{ route('courses.show', $course) }}" class="avenir-black title-paragraph">
            {{ $course->title }}</a>
    @endforeach
@endforeach   

Obviously, you will need the appropriate routes to show the Course Details, Lesson Details etc, e.g.

Route::get('courses/{course}', [CourseController::class, 'show'])->name('courses.show');
Route::get('lessons/{lesson}', [LessonController::class, 'show'])->name('lessons.show');
// CourseController
public function show(Course $course)
{
    // authorization??
    abort_unless($course->user->is(auth()->user()), 403);
    // load the lessons
    $course->load('lessons');
    return view('courses.show', compact($course));
}
//resources/views/courses/show.blade.php
<h1>{{ $course->title }}</h1>
<p>{{ $course->description }}
<ul>
@foreach ($course->lessons as $lesson)
    <li><a href="{{ route('lessons.show', $lesson)">{{ $lesson->title }}</a></li>
@endforeach
</ul>
MohcinBN's avatar

@tykus Nice,, your explanation help me a lot to improve my code, to show the details of the lesson related to course, I should create a show function on the Lesson Controller?

MohcinBN's avatar

@tykus I had a partial to show lessons related to the course, but when go to lessons details. The lesson details view gives "Undefined variable: course" even if I leaded the lesson with course ol LessonController

    @foreach ($course->lessons as $lesson)
        <li style="list-style: none;">
            <a class="popinmedium nav-link active" href="{{ route('lessons.show', $lesson) }}"><span
                    class="round-number-course">
                </span>{{ $lesson->title }}</a>
        </li>
    @endforeach

LessonController: public function show(Lesson $lesson) { $lesson->load('course'); //dd($lesson); return view('frontend.lessons.show', compact('lesson')); }

tykus's avatar

@MohcinBN $lesson->load('course'); results in a course property on the Lesson instance:

$lesson->course

not a $course variable

MohcinBN's avatar

@tykus That's what i'm tried to test but got "Trying to get property 'title' of non-objec"

            @foreach ($lesson->course as $lesson)
                <li style="list-style: none;">
                    <a class="popinmedium nav-link active" href="{{ route('lessons.show', $lesson) }}"><span
                            class="round-number-course">
                        </span>{{ $lesson->title }}</a>
                </li>
            @endforeach
tykus's avatar

@MohcinBN why are you iterating over $lesson->course? It should be one Course.

If you have a Collection of Lesson instances, then:

@foreach ($lessons as $lesson)
   <li style="list-style: none;">
       <a class="popinmedium nav-link active" href="{{ route('lessons.show', $lesson) }}">
            <span class="round-number-course"></span>{{ $lesson->course->title ?? '' }}
        </a>
    </li>
@endforeach
MohcinBN's avatar

@tykus I think I didn't explain it well,, When I enter course I list in the sidebar the lessons sub this course like that:

    @foreach ($course->lessons as $lesson)
        <li style="list-style: none;">
            <a class="popinmedium nav-link active" href="{{ route('lessons.show', $lesson) }}"><span
                    class="round-number-course">
                </span>{{ $lesson->title }}</a>
        </li>
    @endforeach 

But when I enter to the single lesson I want to keep this lessons on the side, that my issue.

tykus's avatar

@MohcinBN in that case;

Pass a course variable to the view:

public function show(Lesson $lesson) 
{ 
    $course = $lesson->course;
    return view('frontend.lessons.show', compact('lesson', 'course'));
}
1 like
MohcinBN's avatar

@tykus Thannk you, I learnt a lot about Laravel relationship with your answers, God bless you!

MohcinBN's avatar

Hello, @tykus

I wanna finish to adding quiz functionalities for this project?, can you suggest the speedy way? and if there are a packages to done the work quickly? please!

tykus's avatar
public function index()
{
    $packs = Pack::with('courses')->get();
    return view('backend.packs.index', compact('packs'));
}
tbody>
            <!-- Item -->
            @foreach ($packs as $pack)
                <tr>
                    <td><a href="#" class="text-primary fw-bold">{{ $pack->id }}</a> </td>
                    <td>
                        {{ $pack->name }}
                    </td>
                    <td>
                        @foreach ($pack->courses as $course)
                            {{ $course->title }}
                        @endforeach
                    </td>
                    <td>
                        {{ $pack->created_at }}
                    </td>
                    <td>
                        <a href=""><button class="btn btn-pill btn-outline-gray-800" type="button">Edit</button></a>

                        <form method="POST" action="" style="float: right;">
                            @csrf
                            <input name="_method" type="hidden" value="DELETE">

                            <button type="submit" class="btn btn-danger btn-flat show-alert-before-delete-lesson btn-sm"
                                data-toggle="tooltip" title='Delete'>Delete</button>

                        </form>
                    </td>
                </tr>
                <!-- End of Item -->
            @endforeach
        </tbody>

Please or to participate in this conversation.