Reputation: 177
I'm using Laravel to create a basic site with the following function: A user can follow certain topics. I have a 'users' table, a 'topics' table, and as a pivot table, I have a 'following' table.
users
----
user_id (primary)
user_first_name
etc..
following
---------
follow_id
user_id (foreign)
topic_id (foreign)
topics
------
topic_id (primary)
topic_name
etc...
I'm trying to create a page that displays all of the topics, but for the topics that the current user is following, I need to show an overlay on the box.
I have a User Model with the following function:
public function follows() {
return $this->belongsToMany('Topic', 'following', 'user_id', 'user_id');
}
However, I'm not too sure where to go from here (or whether this is right!)
Would be hugely grateful for any help.
Upvotes: 1
Views: 4211
Reputation: 698
Almost there, the follows()
relationship needs to be like this:
public function follows() {
return $this->belongsToMany('Topic', 'following', 'user_id', 'topic_id');
}
Then you should be able to grab the topics associated to the current user by doing this:
$topicsUserIsFollowing = Auth::user()->follows;
To start following a topic, you can do this (assuming you have the topic's ID):
Auth::user()->follows()->attach($topic_id);
Edit If you want to see if a topic is followed by someone, then in your Topic model put a function like this:
public function isFollowedBy($user)
{
return $user->follows->contains($this->topic_id);
}
So then you can do something like this:
$currentUser = Auth::user();
$topics = Topics::all();
foreach($topics as $topic) {
echo $topic->topic_name;
if( $topic->isFollowedBy($currentUser) ){
echo ' - [Already following this topic]';
} else {
echo ' - [Follow this topic]';
}
}
You'd want to put the loop in your view, this is just for illustration
Upvotes: 1
Reputation: 81187
1 In your setup you use non-default primary keys (topic_id
/ user_id
/ follow_id
instead of id
) so be sure to set:
protected $primaryKey = 'topic_id';
on each of your models accordingly.
2 I would suggest renaming the relation - follows
is ambiguous, unless you have literally 3 models there.
3 Your relation for your current setup, like already suggested by @ChainList:
public function follows()
{
return $this->belongsToMany('Topic', 'following', 'user_id', 'topic_id');
}
4 In order to check if a user already follows given topic, do this:
// I Assume logged in user
$user = Auth::user();
$topics = Topic::all();
// somewhere in your view
@foreach ($topics as $topic)
{{ $topic->name }}
@if ($user->follows->contains($topic->id))
Already following this topic
@else
Follow this topic (put a link here or whatever)
@endif
@endforeach
With this you run just a single query for user's topics, when you call $user->follows
for the first time.
My suggestion would be:
// leave id as primary key, it will make your life easier
// rename relation to
public function topics()
{
// rename table name to something meaningful
return $this->belongsToMany('Topic', 'topic_user'); // laravel convention
// or if you like topics_followers
}
Upvotes: 1
Reputation: 766
You sustain the following function in User Model
public function follows() {
return $this->belongsToMany('Topic', 'following');
}
and use below statement to retrieve the all topics of any user
$topics = User::find(1)->follows;
Where 1 is the user id for particular user.
Upvotes: 2
Reputation: 1208
First of all, you made a mistake on your follows method. You have the same variable name on local and foreign id 'user_id'.
Then, Did you already add a topic to an user ? If yes, it would be great if you do the same as in your User model on the Topic model
public function followedBy()
{
return $this->belongsToMany('User', 'following', 'topic_id', 'user_'id');
}
From here, you can add a following topic to users by doing
$user->following()->attach($topic_id);
Or
$user->following()->attach([$first_topic, $second, $third, ...]);
You can use the sync method too, but that will delete all previous relationship between user and the topics which are not in the array.
To retrieve all information you can simply do the following:
foreach ($user->following as $topic) {};
/!\ Do not add parentheses to following otherwise you will get a QueryBuilder instead of a collection of the topics. /!\
If you want to add more filters (for example only active topics)
foreach ($user->following()->active()->get() as $topic) {}
Notice that here I added the parentheses which are necessaries because I do not directly want the topics but a QueryBuilder to filter the results. Call the ->get() method when you are done filtering.
(This suppose you have a method called scopeActive() in your model) See Laravel scope to do so : http://laravel.com/docs/eloquent#query-scopes
You can do the opposite on the topic side by doing :
foreach ($topic->followedBy as $user) {}
PS: sorry for my English, If you misunderstood something. Not my native language.
Upvotes: 4