hypefactors/laravel-follow
A Laravel package that adds follow and unfollow behavior to Eloquent models. Let users follow other users or any model, retrieve followers and following lists, check relationships, and count followers through a simple, polymorphic API.
Install the package with Composer and run its migrations:
composer require hypefactors/laravel-follow
php artisan vendor:publish # publish the package migration(s)
php artisan migrate
This creates the polymorphic follows table used to store follower/followable pairs. Check the published migration for the exact column names and indexes before building queries against it.
Next, add the package traits to the models that participate in the follow graph. The actor model gets CanFollow; models that can be followed get CanBeFollowed:
use Hypefactors\LaravelFollow\Traits\CanFollow;
class User extends Authenticatable
{
use CanFollow;
}
use Hypefactors\LaravelFollow\Traits\CanBeFollowed;
class Post extends Model
{
use CanBeFollowed;
}
The first day-to-day use case is a simple follow button: a user follows a post (or another user, topic, etc.), the app checks isFollowing(), and lists results through followings/followers:
$user->follow($post);
$user->unfollow($post);
$user->toggleFollow($post);
$user->isFollowing($post); // bool
$post->isFollowedBy($user); // bool
$user->followings; // models the user follows
$post->followers; // models following the post
Because the relation is polymorphic, any Eloquent model can follow or be followed without schema changes.
Controller endpoints for UI actions. Keep follow/unfollow tiny and idempotent. Use toggleFollow for a single-button UI and authorize first:
public function toggle(Post $post, Request $request)
{
$this->authorize('follow', $post);
$request->user()->toggleFollow($post);
return back();
}
Check state before rendering. In Blade or an API resource, expose whether the current user follows the model so the front end can render the right button state:
'is_following' => $request->user()?->isFollowing($this->resource) ?? false,
Eager-load counts instead of counting collections. For listing pages, use withCount so you do not trigger N+1 queries:
$posts = Post::withCount('followers')->paginate();
foreach ($posts as $post) {
echo $post->followers_count;
}
Build feeds from the follow graph. For a "following feed", collect the IDs of followed users/topics and query posts in a second step. Use the package's Follow model or the relationship query rather than loading full collections:
use Hypefactors\LaravelFollow\Models\Follow;
$followedUserIds = Follow::query()
->where('follower_type', $user->getMorphClass())
->where('follower_id', $user->id)
->where('followable_type', (new User)->getMorphClass())
->pluck('followable_id');
$feed = Post::whereIn('user_id', $followedUserIds)
->latest()
->paginate();
Paginate through the relationship, not the property. $post->followers loads the entire collection. For follower lists use $post->followers()->paginate() (or the equivalent relation query) so large accounts stay responsive.
Use it for more than user-follows. The same traits support following tags, teams, repositories, or any model. This is usually cleaner than adding several bespoke pivot tables.
Test the stored pivot rows. Assert against the follows table using getMorphClass() so tests keep working if you later adopt a morph map:
$user->follow($post);
$this->assertTrue($user->isFollowing($post));
$this->assertDatabaseHas('follows', [
'follower_id' => $user->id,
'follower_type' => $user->getMorphClass(),
'followable_id' => $post->id,
'followable_type' => $post->getMorphClass(),
]);
Keep notification/side effects in your own layer. The package is a persistence helper; if you need "X followed you" notifications or activity records, dispatch your own events from the controller/service after a successful follow.
Relation::enforceMorphMap(), register every followable and follower model. The follows table stores morph types, so changing a class name or aliasing later will orphan existing rows.$user->followings is polymorphic and may contain users, posts, and topics together. Filter by type before assuming a shape, or query the Follow model directly with followable_type.(follower_id, follower_type, followable_id, followable_type); if not, guard with isFollowing() inside a transaction or add the index yourself.follows rows behind. Clean up in model deleting events or a scheduled prune, and be careful with soft deletes—soft-deleted models still appear in follower counts unless you scope queries.followers_count only exists with withCount. Otherwise use $post->followers()->count(). Do not assume the attribute is always present.follow() with a model that has no primary key will fail or store bad data. Persist models first.Follow model or table name. If you need extra columns (e.g. created_at semantics, metadata), extending the model/config is usually cleaner than editing vendor migrations after the fact.How can I help you explore Laravel packages today?