Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need help to structure Eloquent Many to Many relationship (laravel 5.1)

I am trying to build a 'facebook groups' style application, which contains groups filled with members, each member has a membership type (eg. admin, officer, user..) and each group has its group type (public, closed, secret).

so I created few tables:

users - (id, name ..)
groups - (id, name, group_type_id ..)  
group_types - (id, type)
group_members - (user_id, group_id, membership_type_id)
group_membership_types - (id, type)

I believe this is the proper approach to structure the DB (correct me if I wrong).

now I need to convert it to Eloquent models, so I created the models, but got really confused when trying to make the relationship between them, I read about 'pivot' and 'hasManyThrough' and got even more confuse.

theses are the models I created so far:

class Group extends BaseModel
{ 
    protected $table = 'groups';

    public function Members() {
        return $this->belongsToMany('App\GroupMemeber');
    }

    public function Type() {
        return $this->belongsTo('App\GroupType');
    }
}

--

class GroupType extends BaseModel
{
   protected $table = 'group_types';

   protected $guarded = ['id', 'type'];

}

--

class GroupMemebershipType extends BaseModel
{
    protected $table = 'group_membership_types';
}

--

class GroupMember extends BaseModel
{

    protected $table = 'group_members';

    public function User() {
        return $this->belongsTo('App\User');
    }

    public function Group() {
        return $this->hasMany('App\Group');
    }

    public function MembershipType() {
        return $this->belongsTo('App\GroupMemebershipType');
    }
}

am I doing it right? how would you create those models?

like image 416
Or Bachar Avatar asked Sep 14 '15 10:09

Or Bachar


People also ask

What is the use of whereHas in Laravel?

whereHas() works basically the same as has() but allows you to specify additional filters for the related model to check.

What is BelongsTo in Laravel?

BelongsTo relationship in laravel is used to create the relation between two tables. belongsTo means create the relation one to one in inverse direction or its opposite of hasOne. For example if a user has a profile and we wanted to get profile with the user details then we can use belongsTo relationship.


1 Answers

Pivot table conventions

Pivot tables are, by convention, named tablename1_tablename2 where tablename1 is alphabetically superseding tablename2. In this case, group_members should be group_user. If you change this, you don't need to define the $table variable, so you can remove those to clean up the code if you want.

Eloquent relations

The Eloquent relationships are well documented, and if you are ever unsure you can always refer to the code documentation, which is pretty straight-forward:

hasOne

Define a one-to-one relationship.

hasMany

Define a one-to-many relationship.

hasManyThrough

Define a has-many-through relationship.

belongsTo

Define an inverse one-to-one or many relationship.

belongsToMany

Define a many-to-many relationship. 

When using a pivot-table, you can add ->withPivot() and Eloquent will automagically find your conventionally named pivot table. You don't even need models for these "middle"-objects, because they (probably) won't be used in your presentation-layer.

Three-way pivot tables

Now, as for your group memberships, here is where things get a little complicated. The hasManyThrough relation is for accessing distant relations via an intermediate relation, and is not what you are looking for. Laravel does not offer any "plug-and-play" functionality for this type of relationship, and while there is a Laravel 4 library for this purpose, it is not very dynamic but only offers three-way functionality. This is fine for now, but what if you decide to expand on your pivot-table in the future? Then this would break.

Restructuring the database

I looked over the structure of your tables, and noticed that it can easily be restructured: UML Diagram

By avoiding the three-way pivot tables, your code (and table structure) is much more easily maintained and more readable. I think this applies to any pivot-table with three-way relations, and a good rule of thumb is to avoid it by using a smarter table structure.

Result

User

A user

  • belongs to many memberships
  • has many groups through memberships

Code:

class User extends Model
{
    public function memberships() {
        return $this->belongsToMany('App\Membership');
    }

    public function groups() {
        return $this->hasManyThrough('App\Group', 'App\Membership');
    }
}

Membership

A membership

  • has many users
  • belongs to a group

Code:

class Membership extends Model
{
    public function users() {
        return $this->hasMany('App\User');
    }

    public function group() {
        return $this->hasOne('App\Group');
    }
}

Group

A group

  • has many memberships
  • has many users through memberships

Code:

class Group extends Model
{
    public function memberships() {
        return $this->hasMany('App\Membership');
    }

    public function users() {
        return $this->hasManyThrough('App\User', 'App\Membership');
    }
}
like image 184
OskarD90 Avatar answered Oct 28 '22 05:10

OskarD90