Create friendship system for social site in Laravel.

Last Updated on February 4, 2019 by Amarjit Singh

Almost every social networking site has some sort of friendship system as that of Facebook. Where a user can send a friend request to other, accept or reject requests sent by other users, block other users. Now let’s start implementing these requirements step by step.

Created New Project:

Create a fresh Laravel project using this composer create project command.

composer create-project --prefer-dist laravel/laravel friendships

This will take some time to complete. Therefore sit back and let the composer download all the files. When the installation gets completed, run this command to enable login, registration and forgot password features in your project.

php artisan make:auth

Now we are ready to start creating a friendship system. First, we will create database tables required.

Creating Database tables required

We will create a table with name ‘friendships’. This table will be used to store friendship status between two users.

Create a migration with this schema.

//============== migration to create friendships table ======================
  Schema::create(‘friendships’, function(Blueprint $table){
      $table->increments(‘id’);
      $table->integer(‘first_user’)->index();
      $table->integer(‘second_user’)->index();
      $table->integer(‘acted_user’)->index();
      $table->enum(‘status’, [‘pending’, ‘confirmed’, ‘blocked’]);
      $table->timestamps();
  });

After defining above migration create friendships table with this command.

php artisan migrate

Now create an ORM Model for friendships table with this command.

php artisan make:model Friendship

Now we will have to implement a relation in User Model to fetch all of the friends. Since Eloquent doesn’t provide a relation that can fetch child records matching either of two columns. That is, the relations based on two columns are not provided by Eloquent. Therefore we will create two relations one will fetch friends based on first_user field and other will fetch friends based on the second_user field. Finally, we will merge friends fetched by these two relations to get all friends. Therefore in your User model paste the following code.

//======================== functions to get friends attribute =========================

	// friendship that this user started
	protected function friendsOfThisUser()
	{
		return $this->belongsToMany(User::class, ‘friendships’, ‘first_user’, ‘second_user’)
		->withPivot(‘status’)
		->wherePivot(‘status’, ‘confirmed’);
	}

	// friendship that this user was asked for
	protected function thisUserFriendOf()
	{
		return $this->belongsToMany(User::class, ‘friendships’, ‘second_user’, ‘first_user’)
		->withPivot(‘status’)
		->wherePivot(‘status’, ‘confirmed’);
	}

	// accessor allowing you call $user->friends
	public function getFriendsAttribute()
	{
		if ( ! array_key_exists(‘friends’, $this->relations)) $this->loadFriends();
		return $this->getRelation(‘friends’);
	}

	protected function loadFriends()
	{
		if ( ! array_key_exists(‘friends’, $this->relations))
		{
		$friends = $this->mergeFriends();
		$this->setRelation(‘friends’, $friends);
	}
	}

	protected function mergeFriends()
	{
		if($temp = $this->friendsOfThisUser)
		return $temp->merge($this->thisUserFriendOf);
		else
		return $this->thisUserFriendOf;
	}
//======================== end functions to get friends attribute =========================

In the above code, the function friendsOfThisUser() will fetch the friends that are invited by your friend request and the function thisUserFriendOf will fetch the friends that sent you the friend request.

Now in order to access all friends by simply calling $user->friends. we have implemented getFriendsAttribute() function. This function simply checks if there exists is any friends key in relations array. If it finds that then it returns a collection of friends by simply calling $this->getRelation('friends'). But if it doesn’t exist then it first calls loadFriends() function which sets the friends relation and then it calls $this->getRelation('friends') and returns a collection of friends.

The loadFriends() funtion further calls mergeFriends() function which merges the collection returned by the relation friendsOfThisUser, with the collection returned by relation thisUserFriendOf.

In this way, we are able to get a collection of all friends of a user by simply calling $user_model->friends

In a similar manner, we can use above technique to get blocked_friends by using following code.

//====================== functions to get blocked_friends attribute ============================

	// friendship that this user started but now blocked
	protected function friendsOfThisUserBlocked()
	{
		return $this->belongsToMany(User::class, ‘friendships’, ‘first_user’, ‘second_user’)
					->withPivot(‘status’, ‘acted_user’)
					->wherePivot(‘status’, ‘blocked’)
					->wherePivot(‘acted_user’, ‘first_user’);
	}

	// friendship that this user was asked for but now blocked
	protected function thisUserFriendOfBlocked()
	{
		return $this->belongsToMany(User::class, ‘friendships’, ‘second_user’, ‘first_user’)
					->withPivot(‘status’, ‘acted_user’)
					->wherePivot(‘status’, ‘blocked’)
					->wherePivot(‘acted_user’, ‘second_user’);
	}

	// accessor allowing you call $user->blocked_friends
	public function getBlockedFriendsAttribute()
	{
		if ( ! array_key_exists(‘blocked_friends’, $this->relations)) $this->loadBlockedFriends();
			return $this->getRelation(‘blocked_friends’);
	}

	protected function loadBlockedFriends()
	{
		if ( ! array_key_exists(‘blocked_friends’, $this->relations))
		{
			$friends = $this->mergeBlockedFriends();
			$this->setRelation(‘blocked_friends’, $friends);
		}
	}

	protected function mergeBlockedFriends()
	{
		if($temp = $this->friendsOfThisUserBlocked)
			return $temp->merge($this->thisUserFriendOfBlocked);
		else
			return $this->thisUserFriendOfBlocked;
	}
// ======================================= end functions to get block_friends attribute =========

Now to get all friend requests sent to you we can use following Eloquent relation.

public function friend_requests()
{
	return $this->hasMany(Friendship::class, ‘second_user’)
	->where(‘status’, ‘pending’);
}

Using the Friendship System

Sending friend request: To send a friend request we will create an object of Friendship Model and set the value of the first_user field to the id of the user who is sending the friend request and value of second_user will be the id of the user to whom the friend request is being sent. Also, set the value of the acted_user to the id of the user who is sending the friend request. Finally set the value of the status field to ‘pending’.

Accepting a friend request: To accept a friend request simply change the acted_user field value to the id of the user who is accepting the request and also change the status field to ‘confirmed’.

Rejecting a friend request: To reject the friend request simply delete the friend request.

Blocking a user: While blocking a user there will be two cases.

  • the user is already a friend of you: In this case, simply change the value of acted_user field to the id of the user who is blocking the other and also change the value of the status field to ‘blocked’.
  • the user is not a friend of you: In this case, we will follow the steps to send a friend request with an exception that the value of the status field will be set to ‘blocked’.

11 comments on “Create friendship system for social site in Laravel.

  1. Carlos Moran

    Thank you, is the simplest code i see about friendship, i am trying to implemen in my app, i will use to get friendship via API, but i need a little more info about the implementation, do you have some project finished or some videos?

    Reply
    1. Amarjit Singh Post author

      Glad to know that you found it helpful. Yes, I have a project, in fact, this code is from that project. But I don’t have any video tutorial related to this code. All the knowledge to implement the friendship system is gathered from Stack Overflow. If you can more precisely elaborate your problem then I will help you find a perfect solution.

      Reply
  2. Amarjit Singh Post author

    In your controller method that is going to handle the request to block a user you will simply do all the steps of sending a friend request with an exception that the value of status field will be “blocked” instead of “pending”.

    Reply
  3. Amarjit Singh Post author

    Every time when we access the “friends” property from the user model the Laravel executes an SQL query. So we added the check `(!array_key_exists(‘friends’, $this->relations)) ` because we don’t want to execute the query more than one time in same request-response cycle. This will help to reduce the request time.

    Reply
  4. Roman

    How to display a list of all users and show at what stage a friend request for an authorized user, in order to display a button on the frontend, for example, “Add as friend”, “Accept application”, “Remove from friends”, “Block”? And is this done through a resource?

    Reply
    1. Amarjit Singh Post author

      Well in Laravel you can get all the users using User::all()
      and to show the friendship status you can do something as follows:

      // In User Model add this

      public function getFriendship(User $user) {
      return Friendship::where(function($q) use($user){
      $q->where(function($q) use($user) {
      $q->where('first_user', $user->id)
      $q->where('second_user', $this->id);
      })->orWhere(function($q) use($user) {
      $q->where('first_user', $this->id)
      $q->where('second_user', $user->id);
      });
      })->first();
      }

      // Then in your blade do this
      @php
      $friendship = $user->getFriendship(auth()->user());
      @endphp
      @switch($friendship->status)
      @case('pending')
      @if ($frienship->acted_user == $user->id)
      <button> Accept friend request</button>
      @else
      <span> Friend request sent</span>
      @endif
      @endcase

      @case('confirmed')
      <button>Un-friend</button>
      <button>Block</button>
      @endcase

      @case('blocked')
      @if ($frienship->acted_user == $user->id)
      <span> This user has blocked you</span>
      @else
      <button> Un-block</button>
      @endif
      @endcase
      @endswitch

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *