I would like to build 'likes' functionality in my app where one user (user1) can like another user (user2), and then if user2 likes back user1 they would match. What is the best way to implement that kind of logic? My current idea is something like this.
users_table
public function up()
{
Schema::create('users', function(Blueprint $table)
{
$table->increments('id');
$table->string('email');
$table->string('first_name');
$table->string('last_name');
$table->string('password', 60);
$table->rememberToken()->nullable();
$table->timestamps();
});
}
likes_users_table
public function up()
{
Schema::create('likes_users', function(Blueprint $table)
{
$table->integer('liked_user_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('liked_user_id')->references('id')->on('users');
$table->primary(array('user_id', 'liked_user_id'));
});
}
User.php
public function likes()
{
return $this->belongsToMany('User', 'likes_users', 'user_id', 'liked_user_id');
}
UserController.php
public function getIndex()
{
$not_friends = User::where('id', '!=', Auth::user()->id);
if (Auth::user()->likes->count()) {
$not_friends->whereNotIn('id', Auth::user()->likes->modelKeys());
}
$not_friends = $not_friends->get();
return View::make('dashboard.index')->with('not_friends', $not_friends);
}
public function add(User $user)
{
$user->likes()->attach($user->id);
}
public function store($id)
{
$user = User::find($id);
Auth::user()->add($user);
return Redirect::back();
}
This is a quick solution. There could be a more efficient way to accomplish this. Suggestions welcome.
My idea is to set a is_mutual
flag for user likes. If the users like each other the is_mutual
flag will be set.
Let's start with the migration.
Create user_likes
table.
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('user_likes', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id')->comment('user who liked this');
$table->unsignedBigInteger('liked_user_id')->comment('user whom this liked');
$table->boolean('is_mutual')->default(false)->comment('is users like each other');
$table->timestamps();
$table->softDeletes();
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('liked_user_id')->references('id')->on('users');
});
}
Then, I have updated my User
model to add the following relations
public function likedUsers()
{
return $this->belongsToMany('App\User', 'user_likes', 'user_id', 'liked_user_id');
}
public function mutualFriends()
{
return $this->belongsToMany('App\User', 'user_likes', 'user_id', 'liked_user_id')
->where('is_mutual',1);
}
Now Let's create a controller to handle the User Likes logic.
public function storeUserLikes(Request $request)
{
$user = Auth::user(); // Take the currently authenticated user
// Ofcourse, you should validate the $request
$likedUser = $request->likedUser;
// Let's findout if the other user already likes the current user
$isLikedAlready = UserLike::where([
'user_id' => $likedUser,
'liked_user_id' => $user->id,
])
->first();
// Store the user like record in the db
UserLike::create([
'user_id' => $user->id,
'liked_user_id' => $likedUser,
'is_mutual' => $isLikedAlready ? true : false
]);
// If the other user already likes the current user,
// they are a mutual connection.
// Update the row accordingly
if ($isLikedAlready) {
$isLikedAlready->is_mutual = true;
$isLikedAlready->save();
}
// Done! Now show a proper response to the User.
// I am leaving it to you :-)
}
Now, let's add the routes
Auth::routes();
Route::group(['prefix' => 'user', 'middleware' => 'auth'], function ($router) {
$router->get('/like-user/{likedUser}', ['uses' => 'UserLikesController@storeUserLikes']);
});
Now, add some users to your database (for testing). Refer Laravel database seeding and factory for more details.
How it works
The logged-in user can go to DOMAIN/user/like-user/x
to like a user. Where x is the id of the User to be liked.
Note: I have added a get route for ease. You can use POST/GET methods of your choice.
Now, Let's find a list of mutual friends from the DB
Add a function to the UserLikes
controller.
/**
* This function will return a JSON Response with mutually liked users
* for the current logged in user.
**/
public function listLikedUsers()
{
$user = Auth::user();
return response()->json([
'status' => true,
'data' => $user->mutualFriends()->get()
]);
}
Now add a route for getting the mutually liked users. Just below the current route add the following GET
route $router->get('/likes', ['uses' => 'UserLikesController@listLikedUsers']);