Saneesh's avatar

Follower-following relation

Hi All, I'm following Adam Wathan's 'Test Driven Laravel' to learn TDD. As part of it I want to implement a follower-following relationship and https://stackoverflow.com/questions/44913409/laravel-follower-following-relationships/44913501

App/User.php

class User extends Authenticatable
{
    // users that are followed by this user  [user->]
    public function following() {
      return $this->belongsToMany(User::class, 'followers', 'follower_id', 'following_id');        
    }

    // users that follow this user      [->user]
    public function followers() {
      return $this->belongsToMany(User::class, 'followers', 'following_id', 'follower_id');        
    }
}

Users Schema

Schema::create('users', function (Blueprint $table) {
            $table->bigIncrements('id');
            
            $table->string('username');            
            $table->string('password');
            $table->rememberToken();
            
            $table->timestamps();
        });

Followers schema

Schema::create('followers', function (Blueprint $table) {
            $table->bigIncrements('id');

            $table->integer('follower_id')->unsigned();
            $table->integer('following_id')->unsigned();

            $table->timestamps();
        });

FollowOtherUsersTest.php

$userSan = factory(User::class)->create();
$this->actingAs($userSan)
          ->json('POST', 'following', ['username' => 'johndoe']);

FollowingController@store

// Get the username through request and find that user.
$userJohn = User::where('username', request('username'))->firstOrFail();

// Attach the user to the logged in user
Auth::user()->following()->attach($userJohn);

// Get the following user
$myFollowers = Auth::user()->followers()->get();  
dd($myFollowers); // Expected to return $userJohn

The queries generated is as follows:

[2020-01-08 09:48:21] local.INFO: insert into "users" ("username", "password", "remember_token", "updated_at", "created_at") values (?, ?, ?, ?, ?) ["collins.bertha","yIXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi","SXcZIUHjqj","2020-01-08 09:48:21","2020-01-08 09:48:21"] 
[2020-01-08 09:48:21] local.INFO: insert into "users" ("username", "password", "remember_token", "updated_at", "created_at") values (?, ?, ?, ?, ?) ["johndoe","yIXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi","NcbXaRBhoz","2020-01-08 09:48:21","2020-01-08 09:48:21"] 
[2020-01-08 09:48:21] local.INFO: select * from "users" where "username" = ? limit 1 ["johndoe"] 
[2020-01-08 09:48:21] local.INFO: insert into "followers" ("follower_id", "following_id") values (?, ?) [1,2] 
[2020-01-08 09:48:21] local.INFO: select "users".*, "followers"."following_id" as "pivot_following_id", "followers"."follower_id" as "pivot_follower_id" from "users" inner join "followers" on "users"."id" = "followers"."follower_id" where "followers"."following_id" = ? [1] 

Database used to create these tables is Sqlite. When I print the $myFollowers it is empty. What is wrong in this code?

Regards, Saneesh.

0 likes
5 replies
Sti3bas's avatar

@saneesh you're attaching the user to followings, but dumping followers.

Auth::user()->following()->attach($userJohn); should be $userJohn->following()->attach(Auth::user());

ammarax's avatar

i suppose you have to refresh your $user istance from DB

Try this in FollowingController@store

// Get the username through request and find that user.
$userJohn = User::where('username', request('username'))->firstOrFail();

$user = Auth::user();
// Attach the user to the logged in user
$user->following()->attach($userJohn);

// Get the following user
$myFollowers = Auth::user()->followers()->get();  
//refresh the entity
$user->fresh();

dd($myFollowers);
Saneesh's avatar

Still the same result.

if you check the query

SELECT 
   "users".*, "followers"."following_id" as "pivot_following_id", 
   "followers"."follower_id" as "pivot_follower_id" 
FROM "users" inner join "followers" 
    on "users"."id" = "followers"."follower_id" 
WHERE "followers"."following_id" = ? [1]

Auth users id is 1. Why the where "followers"."following_id" = ? [1]?? I think this query part is failing

Saneesh's avatar

Hello @sti3bas,

// Add the current user(auth user) attach/follow $userJohn
$userJohn->following()->attach(Auth::user());        

// Get the followers of $userJohn
$userJohnFollowers = $userJohn->followers()->get(); 
dd($userJohnFollowers);  // Empty

What I want is,

$sanFollowing = Auth::user()->following()->get(); has to return $userJohn $userJohn->followers()->get() has to return auth user

How can I achieve this?

Saneesh's avatar

Thank you guys, here is the output I was expecting!

  $userFan = factory(User::class)->create(); 
  $userJohn = User::where('username', request('username'))->firstOrFail();
  $userJohn->followers()->attach(Auth::user());        
  $userJohn->followers()->attach($userFan);        


  $userJohnFollowers = $userJohn->followers()->get(); 

  \Log::info('User John followers...');
  foreach($userJohnFollowers as $userJohnFollower) {
      \Log::info(1, $userJohnFollower->toArray());
  } 

  $sanFollowings = Auth::user()->following()->get();  

  \Log::info('Auth followings...');
  foreach($sanFollowings as $sanFollowing) {
      \Log::info(1, $sanFollowing->toArray());
  }

Now the result coming as expected:

[2020-01-08 18:04:45] local.INFO: User John followers...  
[2020-01-08 18:04:45] local.INFO: 1 {"id":1,"username":"vito61","created_at":"2020-01-08 18:04:44","updated_at":"2020-01-08 18:04:44","pivot":{"following_id":"2","follower_id":"1"}} 
[2020-01-08 18:04:45] local.INFO: 1 {"id":3,"username":"runolfsdottir.emilia","created_at":"2020-01-08 18:04:45","updated_at":"2020-01-08 18:04:45","pivot":{"following_id":"2","follower_id":"3"}} 
[2020-01-08 18:04:45] local.INFO: Auth followings...  
[2020-01-08 18:04:45] local.INFO: 1 {"id":2,"username":"johndoe","created_at":"2020-01-08 18:04:44","updated_at":"2020-01-08 18:04:44","pivot":{"follower_id":"1","following_id":"2"}} 

Issues I was faced:

  1. Wrong understanding!
  2. Wrongly interpreted the output

Please or to participate in this conversation.