This is the valid “has-many-through” relationship.

“has-many-through” relationship

Probably not this.

Complicated relationship

A country has many states and a state has many cities. A country doesn’t have direct relationship with the city.

In your case, a user has many following users and a user has many tweets. A tweet’s immediate parent is the user, not the following user.

As you can see from the error message, Laravel couldn’t generate the valid query.

select `tweets`.*, `followers`.`user_id` from `tweets` inner join `followers` on `followers`.`id` = `tweets`.`user_id` where `followers`.`user_id` is null)

This is the expected query.

SELECT `tweets`.*

FROM followers

INNER JOIN tweets ON `followers`.`user_id` = `tweets`.`user_id`

WHERE `followers`.`follower_user_id` = ‘1’

ORDER BY `tweets`.`created_at` DESC;

Expected query output

Alright, how does the eager loading achieve it? It is using two queries instead of one. Check out the documentation.

select `users`.*, `followers`.`follower_user_id` as `pivot_follower_user_id`, `followers`.`user_id` as `pivot_user_id`, `followers`.`created_at` as `pivot_created_at`, `followers`.`updated_at` as `pivot_updated_at` from `users` inner join `followers` on `users`.`id` = `followers`.`user_id` where `followers`.`follower_user_id` = ? select * from `tweets` where `tweets`.`user_id` in (?) order by `created_at` desc

Eager loading is making more sense than “has-many-through” relationship here.

Next step is improving the performance.

The timeline is worked, but your job hasn’t done here. What if you have more than a thousand users in your following list? Your homepage probably very slow.

So, your next step is improving the performance.

Improve the Performance

Your Home page is slowing down as you follow more users.

What pops up in your mind? MySQL? Probably the database is the first thing you blame.

It is not the MySQL’s fault. MySQL is capable of returning thousands row of data in milliseconds. Then, what?

Your greatest enemy here is your user’s browser. The browser takes ten to twenty seconds to render the Home page. Before the rendering done, your user already leaves and tell his friends that your website is slow.

In the old time, the Internet Explorer cannot even open the homepage.

To improve the performance, you implement infinite scrolling feature. The content will be fetched in a chunk, ten tweets per time. When you are scrolling down, the new contents will load via AJAX.

Additionally, I recommend you to use Single Action Controller which is specifically designed for a single action.

Single Action Controller

Single action controller does one thing only.

For example, AddPostController inserts a new post, EditPostController updates a post, and ShowPostController returns a post. AddPostController doesn’t update post.

You can learn more in detail from Michael Dyrynda. This is his post, Single action controllers in Laravel.

//Terminal php artisan make:controller ShowTimeline

Controller created successfully.

// app/Http/Controllers/ShowTimeline.php use Auth;

... class ShowTimeline

{

public function __invoke()

{

$user = Auth::user(); return response()->json($user->timeline());

}

}

Add a new route.

// routes/web.php Route::group(['middleware' => 'auth'], function () {

Route::get('/timeline', 'ShowTimeline');

...

});

Hit the browser address bar with http://laratweet.app/timeline. You will see this.