Laravel relationship between 3 models (group,member,post) - laravel

I have 3 models that are related to each other.
Group
GroupMember
GroupPost
GroupPostComment
Now, I have separeted the database tables aswell.
groups
group_members
group_posts
group_post_comments
For each group a member is a member of, I insert a new row in group_members.
The foreign key here is "group_id", wich relates to the id field in groups.
In group_posts there is a new row for every post posted. This container a group_id field aswell.
What I'm struggling with is the GroupMember model.
How can I get an collection of all the posts from this GroupMember, that the GroupMember posted in that one group its related to?
Here is my models setup.
Group model
public function category() {
return $this -> belongsTo('App\GroupCategory', 'category_id');
}
public function owner() {
return $this -> hasOne('App\GroupMember', 'group_id') -> where('owner', true);
}
public function mods() {
return $this -> hasMany('App\GroupMember', 'group_id') -> where('mod', true);
}
public function admins() {
return $this -> hasMany('App\GroupMember', 'group_id') -> where('admin', true);
}
public function members() {
return $this -> hasMany('App\GroupMember', 'group_id');
}
public function posts() {
return $this -> hasMany('App\GroupPost', 'group_id');
}
public function comments() {
return $this -> hasMany('App\GroupPostComment', 'group_id');
}
GroupMember model
public function group() {
return $this -> belongsTo('App\Group');
}
public function posts() {
return $this -> hasMany('App\GroupPost', 'group_id', 'group_id');
}
public function comments() {
return $this -> hasMany('App\GroupPostComment', 'group_id', 'group_id');
}
public function user() {
return $this -> belongsTo('App\User');
}
GroupPost model
public function user() {
return $this -> belongsTo('App\User');
}
public function comments() {
return $this -> hasMany('App\GroupPostComment', 'post_id');
}
public function group() {
return $this -> belongsTo('App\Group');
}
The problem is the GroupMember model and the posts() / comments() method.
There is an error in my relation, but I can't see what I am doing wrong.
Does anyone see what I'm doing wrong?

This case is a little bit confusing to resolve, although easy to. I guess that's why you haven't received any help yet because some people struggle to understand.
1. Clear some confusions
In your title you mentioned
Laravel relationship between 3 models (group,member,post)
Yet, there is no Member model to be seen. And I think most of your difficulties come from there. In my tryout, I will assume you have a User model and the table that goes with.
Question: Can a user be member of many groups ? If the answer is yest, then you have a many to many relationship between Group and User (members). Thus, update your Group model like this:
public function members() {
return $this->belongsToMany('App\User', 'group_members', 'group_id', 'member_id');
}
And in the User model, you define the opposite
public function groups() {
return $this->belongsToMany('App\Group', 'group_members', 'member_id', 'group_id');
}
Right, you noticed now group_members table has a composite key made of group_id and member_id respectively representing groups and users table.
2. How to get the all the posts belonging to a member in a specific group
First thing first, a GroupPost (post) belongs to two entities: a Group and User (member). In your GroupPost model you already have a relationship to User. So all good. To answer your questions, there are many possibilities.
//Direct eloquent when user id and group id are known
$posts = GroupPost::where('user_id', 1)->where('group_id', 1)->get();
//Directly from the user
$member = User::find(1);
$posts = $member->groupPosts()->where('group_id', 1)->get();
Don't forget to define groupPosts() relationship in User model
public function groupPosts() {
return $this->hasMany('App\GroupPost');
}

Related

Laravel - Eloquent How can make this relationship HasMany -> BelongToThrough

How can I come up with this kind of relationship?
User:
- id
- name
- username
Post
- id
- user_id
- comment_id
Coment
- id
- other_id
Other
- id
- name
- descripton
So the relationship would be:
User - belongsToMany -> Post - belongsTo -> Comment - belongsTo -> Other
At this relationship the user have many post but the comment_id relation is belongs to.
I cant use hasManyThrough because the relationship is different.
Is there a way to make this work?
it should be hasMany -> BelongsToThrough
I could use hasMany then on each item will call the BelongsTo, but the relationship I had is too deep.
It needs a relationship that can use hasMany then belongsToThrough such relationship
UPDATE
There is a belongsToMany instead of hasMany but still not sure if I could work on this
Got an alternative solution
class User {
public function user_post_comments () {
return $this->belongsToMany(Post::class);
}
public function getCommentsAttribute() {
return $this->user_post_comments->map(function ($value, $key) {
$obj = $value->comment;
$obj->pivot=(object) [
// Extra variable for the nested
];
return $obj;
});
}
}
class Post {
public function comment () {
return $this->belongsTo(Comment::class);
}
}
$this->user->comments will return the post comment instead of posts
https://laravel.com/docs/8.x/eloquent-relationships#has-many-through
You can get comments from users like this
class User extends Model
{
/**
* Get all of the Comments for the Post.
*/
public function comments()
{
return $this->hasManyThrough(Comment::class, Post::class);
}
/**
* Get all of the Post.
*/
public function posts()
{
return $this->hasMany(Post::class);
}
}
Get Other's comment like this
class Comment extends Model
{
public function others()
{
return $this->belongsTo(Other::class);
}
}
and get final data like this
$data = User::with(['comments.others'])->get();
Got something that will work if to add other information in the pivot.
use Illuminate\Database\Eloquent\Relations\Pivot;
class ModelPivot extends Pivot
{
public $appends = ['extra_detail'];
public function getExtraDetailAttribute() {
return App\Detail::find($this->attributes['detail_id'];
}
}

How to get users from a group, with a union between two relationships in laravel?

I want to recieve all users from a group.
The problem is in this group their are student users (with a pivot table) and normal users.
So i have to merge them together, but i still want to maintain all possibilities from eloquent.
I came to this:
dd($this->belongsToMany(User::class)->union($this->hasManyThrough(User::class,Student::class,'class_id','id','id','user_id'))->get());
But as result i get:
My database relationships
Users
- id
Group
- id
Students
- id
- user_id (fk to users)
- class_id (fk to groups)
User_Group
- user_id (fk to users)
- group_id (fk to groups)
User-model:
public function students()
{
return $this->hasMany(Student::class);
}
public function groups()
{
return $this->belongsToMany(Group::class);
}
Student-model
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function class()
{
return $this->belongsTo(Group::class, 'class_id');
}
Group-model
public function students()
{
return $this->hasMany(Student::class, 'class_id');
}
public function users()
{
return $this->belongsToMany(User::class);
}
public function members()
{
//this causes the problem!!
return $this->belongsToMany(User::class)->union($this->hasManyThrough(User::class,Student::class,'class_id','id','id','user_id'));
}
in User model relationship
public function group(){
return $this->belongsToMany(Group::class);
}
in Group model relationship
public function user(){
return $this->belongsToMany(User::class, 'user_group');
}
in Students model relationship
public function user(){
return $this->belongsToMany(User::class, 'user_id', 'id');
}
public function group(){
return $this->belongsToMany(Group::class, 'class_id', 'id');
}
you can call now
$users = User::whereHas('groups',function ($query){
$query->where('group_id',1);
})->get();
Sometimes you have two relations from one model to another, due pivot tables. In my example you could go from users to groups with the relation user_groups and the relation students. To get all users that belong to a certain group i need to call both relations. To solve this issue, i made use of Abdulmajeed's example to solve it. You can see the code below. Thanks for helping me out.
public function members()
{
return User::whereHas('groups', function($q)
{
$q->where('id',$this->id);
})->orWhereHas('students', function($q)
{
$q->where('class_id',$this->id);
});
}

Laravel One to Many relation with 2 primary keys

I've 2 tables
Users table
id
name
...
Chats table
id
from_id // fk - id on users, the user sent the message
to_id // fk - id on users, intended user
message_body
Now, I'm trying to set up One to Many relation where user has many chat messages but a chat message has two user. from and to user
How can I define this relationship?. I have to user eager loading.
I tried to use Compoships but it didn't work.
My code
User Model
public function chats() {
return $this->hasMany(Chat::class, ['from_id', 'to_id'], 'id');
}
Chat Model
public function user() {
return $this->belongsTo(User::class, ['from_id', 'to_id'], 'id');
}
public function chats() {
return $this->hasMany(Chat::class, 'from_id', 'id') + $this->hasMany(Chat::class,'to_id','id');
}
public function userFrom() {
return $this->belongsTo(User::class, 'from_id', 'id');
}
public function userTo() {
return $this->belongsTo(User::class, 'to_id', 'id');
}
Why don't you do something like that?
On your User model, set up two relationships like this:
public function chatsFrom() {
return $this->hasMany('App\Chat', 'from_id');
}
public function chatsTo() {
return $this->hasMany('App\Chat', 'to_id');
}
Then, on your Chat model, also set up two relationships, one to from and another to to, both referencing a User model. Like this:
public function fromUser() {
return $this->belongsTo('App\User', 'from_id');
}
public function toUser() {
return $this->belongsTo('App\User', 'to_id');
}
This way, you can access the relationships using something like this:
$user->chatsFrom();
$user->chatsTo();
$chat->fromUser();
$chat->toUser();

Laravel relations pivot table name trouble

in my app I have 2 conversations types: normal private conversations between users and conversations for people which are interested of user product.
In my User model I declared relations like:
public function conversations()
{
return $this->belongsToMany('App\Conversation', 'conversation_user');
}
public function conversationsProduct()
{
return $this->belongsToMany('App\ConversationProduct', 'conversation_product_user', 'user_id', 'product_id');
}
Where 'conversation_user' and 'conversation_product_user' are pivot tables between 'users'-'conversations' and 'users'-'conversations_product' tables.
My conversation_user pivot table has conversation_id and user_id table properties, but conversation_product_user pivot table has additional property product_id.
In my Conversation Model I have:
public function users()
{
return $this->belongsToMany('App\User');
}
public function messages()
{
return $this->hasMany('App\Message');
}
In ConversationProduct Model I wrote:
protected $table = 'conversations_product';
public function users()
{
return $this->belongsToMany('App\User', 'conversation_product_user');
}
public function messages()
{
return $this->hasMany('App\MessageProduct');
}
In my ConversationProductController I have method to find user conversations:
public function showUserConversationsProduct(Request $request){
$user_id = $request->user_id;
//var_dump($user_id);
$userData = User::where('id', $user_id)->with('conversationsProduct')->first();
}
And there is my problem: In controller ->with('conversationsProduct') don't take relation for conversation_product_user, but for conversation_user pivot table. I can't handle it why its happen if I add second parameter as 'conversation_product_user' in my relation:
public function conversationsProduct()
{
return $this->belongsToMany('App\ConversationProduct', 'conversation_product_user', 'user_id', 'product_id');
}
I need protected $table = 'conversations_product'; to point my ConversationsProductController#store where to save conversation, but I think that can be problem with recognise proper relation.
I really appreciate any help. I attach photo of my db relations.

Updated: Why relationship works when user is Admin, but won`t when Regular user?

I have 3 models: User, Role and Currency. I am confused about relationship between them.
Then User is Admin this works:
Auth::user()->currency->symbol)
When regular User I get error:
Trying to get property of non-object
if dd(Auth::user()) it show user, but cant access to relationship with model Currency. Why it is so?
User model relationship:
public function currency()
{
return $this->belongsTo(Currency::class, 'currency_id');
}
Currency model relationship:
public function created_by()
{
return $this->belongsTo(User::class, 'created_by_id');
}
If you need extra information, let me know.
User model
public function currency()
{
return $this->belongsTo(Currency::class);
}
Currency model
public function users()
{
return $this->hasMany(User::class, 'created_by_id');
}
Going with an assumption that your User model has an attribute currency_id
$this->belongsTo(TABLE, FORIEGN KEY, TABLE KEY);
refer this
User model
public function currency()
{
return $this->belongsTo(Currency::class, 'currency_id', 'id');
}
Currency model
public function users()
{
return $this->hasMany(User::class, 'created_by_id', 'id');
}

Resources