I got problems with the hasManyThrough function in Laravel.
My goal is to get a feed where the posts show up by users that the logged in user follows. I try to achieve this by:
In User.php, get the ID of the logged in user
Match the user's id with the columns called user_id in Follow.php
Get the target_id from the rows in Follow.php
Get the posts where user_id matches the target_ids from Follow.php
I retrieve the data correctly by who the user follows. However, the user_id that gets returned in the data is the logged in user and not the author of the post. Why?
User.php
public function feed() {
return $this->hasManyThrough(
'App\Post',
'App\Follow',
'user_id',
'user_id',
'id',
'target_id'
)
->with('user')
->orderBy('id', 'DESC');
}
Post.php
public function user() {
return $this->belongsTo('App\User');
}
Called from controller via
$posts = Auth::user()->feed;
Your code creates this query: select `posts`.*, `follows`.`user_id`...
As you can see, posts.user_id gets overwritten by follows.user_id (follows.user_id is necessary for eager loading).
I see two possible solutions for your problem:
Rename follows.user_id.
Use two separate relationships: User → HasMany → Follow → HasMany → Post
Related
I have a website build in Laravel.
I have two tables - Groups and Group members.
For each group_member, the row in the table has id, group_id and user_id.
The groups have a name and a description.
When a user joins a group, a row is created in the group_member table.
But I now need to get the groups that a user is part of.
So if I have user_id = 5, I need to get all the rows in group_member where user_id = 5, and then get the corresponding group, so I can query the groups.
I need to do something like $groups = Groups::whereGroup_member ...
But I cant query the model like that, because in Groups there is no where it specificies who the members are, it is just the group details - the members are specificed in group_member table.
How do I get the groups, which a member is part of using the laravel query standards?
In your User.php Model
public function group_member(){
return $this->hasMany(GroupMember::class,'user_id','id;);
}
In your GroupMember.php Model
public function group(){
return $this->belongsTo(Group::class,'group_id','id');
}
Your query will be
$users = User::with('group_member.group')->find($user_id);
You should use Many-to-Many relation:
class Group
...
public function members() {
return $this->belongsToMany(User::class); // Users (members) that belongs to Group
}
class User
...
public function groups() {
return $this->belongsToMany(Group::class, 'group_member', 'user_id', 'group_id'); // Groups that User belongs to
}
And at controller, when You have user id:
$groups = User::where('id', $user_id)->groups;
More about this written at official docs: https://laravel.com/docs/5.4/eloquent-relationships#many-to-many
Can normally figure these relationships out but stumped on this one.
I have a basic blog platform that allows user to sign up and post blog posts.
Users can also follow other users.
I am trying to make a view where I can see all of the blog posts by the authors that I follow
I have the normal users table, and then a blog posts table which contains the user_id of the creator.
For followers, I then have a pivot table called followers which has user_id and follower_id.
This is my basic line to get all posts:
$posts = Post::orderBy('created_at', 'DESC')->get();
How can I change that so it only shows the posts where there post user_id is a field that matches in the followers table?
Thanks.
You may try something like this:
App\User Model:
public function favoriteAuthors()
{
return $this->belongsToMany(
User::class, // as Author
'followers', // pivot table
'follower_id', // as follower_id
'user_id', // as author_id
);
}
public function posts()
{
return $this
->hasMany(Post::class, 'user_id', 'id')
->orderBy('created_at', 'DESC');
}
Then load all posts of your favorite authors:
$posts = User::with('favoriteAuthors.posts')->find(auth()->user()->id);
Also you can use something like this:
if($me = auth()->user()) {
$me->load(['favoriteAuthors.posts']);
}
Now the $me will contain users that you follw and each users will contain their posts.
I am trying to create a youtube style subscription model for my application. I've had small amounts of success so far, that being that you can follow other users and it stores who is following who in the database. However I am having trouble retrieving the list of people the current user is following.
The database:
users table (id, first_name, last_name, email, password, token, timestamps)
subscriptions Table (id, user_id, subscriber_id, timestamps)
user model:
public function subscriptions()
{
return $this->belongsToMany('App\User', 'subscriptions', 'user_id',
'subscriber_id')->withTimestamps();
}
public function subscribers()
{
return $this->belongsToMany('App\User', 'subscriptions', 'subscriber_id',
'user_id')->withTimestamps();
}
I am using this code to retrieve all of the current users subscriptions (aka who they are following)
$subscriber = Auth::user()->id;
$user = User::find($subscriber);
$userids = $user->subscriptions->lists('user_id');
return $userids;
Now, this code is currently returning a null value. On further investigation this makes sense as the query that is being run is incorrect
SQL Query:
select `user_id` from `users` inner join `subscriptions` on `users`.`id` = `subscriptions`.`subscriber_id` where `subscriptions`.`user_id` = 14
My current set up is trying to look for the wrong thing.
If user 1 follows users 2, 3 and 4 then my code should return 2, 3 and 4.
Can somebody please help correct my relationship set up or the code that I am running? It should be looking for the user_id in the subscriptions table based on the current users subscriber_ID.
Laravel 5.3 Eloquent Relationships
If you check the code at the end of the Many-to-Many relationships part, you will see this line of code.
return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');
Here, we have the 'role_user' as the pivot (relationship) table, 'user_id' which is the foreign key in relationship table and primary key in user model, and 'role_id' is foreign key in relationship table and primary key in roles model.
So when you try to do this:
public function subscriptions()
{
return $this->belongsToMany('App\User', 'subscriptions', 'user_id',
'subscriber_id')->withTimestamps();
}
You are actually taking 'subscriber_id' as a foreign key in your relationship table and primary key for a subscriber. Since the function is trying to get the subscriptions, reaching to the subscriber id's won't do the work. This is why when you changed them they worked.
The result should look like this:
public function subscribers()
{
return $this->belongsToMany('App\User', 'subscriptions', 'user_id',
'subscriber_id')->withTimestamps();
}
public function subscriptions()
{
return $this->belongsToMany('App\User', 'subscriptions', 'subscriber_id',
'user_id')->withTimestamps();
}
So out of pure chance, I swapped the subscribers() and subscriptions() relationships about and it's now returning the correct data.. I don't understand why but it is definitely returning the ID's that I was expecting.
I'll keep the question open for now in case anyone with a clear solution answers.
The Issue
I want to get all users who are not managers of a company.
The Relationships
I have a User model, that can have one CompanyGroup. The CompanyGroup can have many Managers. Managers can manage different types of entity, not just CompanyGroups, so this is a polymorphic relationship (however, not directly relevant to my question).
User Model
public function group()
{
return $this->belongsTo('App\CompanyGroup', 'company_group_id');
}
Company Group
public function managers()
{
// This is polymorphic, as a manager can manage different types of entity.
return $this->morphMany('App\Manager', 'managable');
}
Manager
public function user()
{
return $this->belongsTo('App\User', 'user_uuid', 'uuid');
}
What i've tried:
// Get all users, with a relationship of 'group', and the group's 'managers'
$users = $this->user->whereHas('group.managers', function($query)use($group)
{
// Exclude any users where the user's UUID is present in the managers table
$query->where('exp_members.uuid', '!=', 'managers.user_uuid');
})->get();
What this produced
Nothing! It didn't list any users at all. The managers table is currently empty, so it should return all users that have the $group->id assigned to them. If i enter a random record in the managers table, it returns all of the users that have the group id assigned to them, but it doesn't filter out those who are managers.
I was trying to get the attendance of each user in a course where the users and the courses have many to many relationship and the attendance table is based on the relationship.
But i couldn't call $user->pivot->attendance(); directly i had to call for the pivot object it self so i can call a function to it as you can see in the answer
The Following is a sample of my Database scheme
I need to run
$users=$course->users;
foreach($users as $user)
{
$user->pivot->attendance(); //error in this line
}
this line gives and error
Call to undefined method
Illuminate\Database\Query\Builder::attendance()
users
id
name
etc
courses
id
name
startDate
endDate
course_user
id
course_id
user_id
payment
regDate
status
userattendance
id
course_user_id
time
inOrOut
And here is the CourseUserPivot Class
class CourseUserPivot extends Eloquent {
protected $table ="course_user";
public function course()
{
return $this->belongsTo('Course');
}
public function user()
{
return $this->belongsTo('User');
}
public function attendance()
{
return $this->hasMany('Userattendance','course_user_id');
}
}
P.S: $user->pivot->payment works and displays the attribute but i cant call methods
You can't use $user->pivot->attendance(); as this calls attendance on the user object not on the pivot object
You will have to fetch the pivot object then call the function like so
CourseUserPivot::find($user->pivot->id)->attendance();
make user that where you used withPivot() function you include the id in the array
like in
class Course{
...
...
public function users()
{
return $this->belongsToMany('Candidate')
->withPivot('id',
'summary',
'status',
'payment'
);
}
}
I was trying to accomplish the same thing, and I was having trouble getting it to work like I wanted until I included the 'id' column of my custom pivot model in the withPivot() method.
For some context, my database structure is:
User table
id
Items Table
id
Sets table (defines a set and the items that can be in an instance of it)
id
Set_User table (Custom Pivot Model, instances of a set created by a user)
id, set_id, user_id
Items_SetUser table (items that belong to a set instance that belong to a user)
item_id, setuser_id
I do this in the controller to get all the sets that user has made an instance of, with custom pivot table data:
$user_sets = \Auth::user()->sets()->withPivot('id', 'name')->get();
And then in blade I can access the items associated with each set instance like this:
$set->pivot->set_items()->count()
Without including 'id' in the call to withPivot(), the above is not possible. Note that set_items() is a method on the custom pivot model that defines a relationship with the items table.