2

I use Laravel 8. I have 3 table. Course table, UserCourse, and User table. I want to get user courses. I tried it with tinker: Course::find(1)->user_courses -it works fine and give back me user_course.

UserCourse::find(1)->user_course - the problem is here, this will return me "null"

How can I get the User Courses?

Course table

    Schema::create('courses', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->timestamps();
    });

UserCourse table

    Schema::create('user_courses', function (Blueprint $table) {
        $table->id();
        $table->foreignId('user_id')->constrained()->onDelete('cascade');
        $table->foreignId('course_id')->constrained()->onDelete('cascade');
        $table->timestamps();
    });

User table

    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('email')->unique();
        $table->string('username')->unique();
        $table->string('password');
        $table->timestamp('updated_at')->nullable();
        $table->timestamp('created_at')->nullable();
    });

Course.php

class Course extends Model
{
use HasFactory;

protected $fillable = [
    'title',
];

public function user_courses()
{
    return $this->hasMany(UserCourse::class);
}
}

UserCourse.php

class UserCourse extends Model
{
use HasFactory;

protected $fillable = [];


public function user_course()
{
    return $this->belongsTo(Course::class);
}
}
xMrViktorx
  • 79
  • 2
  • 9

1 Answers1

3

Your database structure make it that the relation between course and user is a many to many relation with a pivot table in the middle.

Some correction you need to do for it to work seemingly with laravel conventions.

- The pivot table name should be course_user without a primary key

 Schema::create('course_user', function (Blueprint $table) {
        $table->foreignId('user_id')->constrained()->onDelete('cascade');
        $table->foreignId('course_id')->constrained()->onDelete('cascade');
        $table->timestamps();
    });

- Remove the UserCourse.php model since it's a pivot

- Define the relation courses in User model as follow

User.php

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

- Define the relation users in Course model as follow

Course.php

public function users()
{
    return $this->belongsToMany(User::class);
}

Now to get any user courses, just run User::find(1)->courses

Same thing to get the users that belongs to the same couses Course::find(1)->users

get courses that the user has not taken:

$userId = 1;
$courses = Course::whereDoesntHave('users', function($userQB) use($userId) {
    $userQB->where('id',$userId);
})->get();
N69S
  • 16,110
  • 3
  • 22
  • 36
  • Course::find(1)->users is works fine, but User::find(1)->courses return null – xMrViktorx Apr 26 '21 at 08:09
  • @xMrViktorx did you modify your migrations ? the structure is symetric, if one way worked, the other way should work too. – N69S Apr 26 '21 at 08:29
  • Yes, i modified. – xMrViktorx Apr 26 '21 at 08:30
  • @xMrViktorx Do you get results running this ? `Course::find(1)->users()->first()->courses` if yes, then everything works correctly, check your database entries for the results you want. – N69S Apr 26 '21 at 08:31
  • @xMrViktorx if you want some quick help, join me in the chat room https://chat.stackoverflow.com/rooms/231603/https-stackoverflow-com-questions-67262509-laravel-one-to-many-inverse-belongs – N69S Apr 26 '21 at 08:35
  • I can't talk in chat rooms, because I dont have enought reputation. But its works, fine. I don't know what the problem was but I solved it. How can I get courses that the user has not taken? – xMrViktorx Apr 26 '21 at 08:44
  • @xMrViktorx There is a pretty neat way for that, will add it in the answer – N69S Apr 26 '21 at 08:46
  • @xMrViktorx you just need 20 reputation to join the chat room, you should have enough for it. – N69S Apr 26 '21 at 08:53
  • Now I have 21 reputation, but I can't write. I tried your solution and Error: Request failed with status code 500 – xMrViktorx Apr 26 '21 at 08:57
  • @xMrViktorx my bad, it's `whereDoesntHave` not `doesntHave`. the later one doesnt accept a second parameter and is just a short form of the first one. like `Course::doesntHave('users')` will give you the courses that doesnt have any users linked to them – N69S Apr 26 '21 at 09:04