Installation:
composer require rennokki/befriended
Publish the migration:
php artisan vendor:publish --provider="RenokiCo\Befriended\BefriendedServiceProvider" --tag="migrations"
Run migrations:
php artisan migrate
Model Setup:
Use the RenokiCo\Befriended\Traits\Befriended trait in your Eloquent model (e.g., User):
use RenokiCo\Befriended\Traits\Befriended;
class User extends Model
{
use Befriended;
}
First Use Case: Follow a user:
$user1 = User::find(1);
$user2 = User::find(2);
$user1->follow($user2); // Returns true if successful
database/migrations/ for the befriended table structure.RenokiCo\Befriended\Traits\Befriended for available methods.following(), blocked(), and notBlocked() for querying.Following/Unfollowing:
$user->follow($targetUser); // Follow
$user->unfollow($targetUser); // Unfollow
$user->isFollowing($targetUser); // Check
Blocking/Unblocking:
$user->block($targetUser); // Block
$user->unblock($targetUser); // Unblock
$user->isBlockedBy($targetUser); // Check
Content Filtering:
Use scopes to filter models (e.g., Post) based on followers/blockers:
$user->following()->posts(); // Posts from followed users
$user->notBlocked()->posts(); // Posts from non-blocked users
Custom Models:
Extend the Befriended trait to other models (e.g., Team, Organization) for hierarchical relationships.
API Endpoints: Create routes for social actions:
Route::post('/users/{user}/follow', [UserController::class, 'follow']);
Controller logic:
public function follow(User $user, User $targetUser)
{
$user->follow($targetUser);
return response()->json(['success' => true]);
}
Notifications: Trigger events on follow/block actions:
$user->follow($targetUser)->then(function ($followed) {
Notification::send($followed, new UserFollowed($user));
});
Caching:
Cache frequent queries (e.g., isFollowing) to reduce database load:
$user->isFollowing($targetUser); // Cache with Laravel's cache helper
Circular Follows: Avoid infinite loops when checking mutual follows. Use:
$user->isFollowing($targetUser) && $targetUser->isFollowing($user);
Soft Deletes:
If using SoftDeletes, ensure the befriended table handles soft-deleted models correctly. Override the trait if needed.
Mass Assignment:
The befriended table uses a pivot structure. Guard against mass assignment risks:
protected $guarded = ['follower_id', 'followed_id'];
Performance:
Scopes like following() can be slow on large datasets. Optimize with:
$user->following()->with(['posts' => function ($query) {
$query->limit(10);
}])->get();
Migration Issues: If migrations fail, check for duplicate table names or missing foreign keys. Reset migrations if needed:
php artisan migrate:fresh
Trait Conflicts:
If methods conflict (e.g., follow), rename or alias the trait methods:
use RenokiCo\Befriended\Traits\Befriended as BefriendedTrait;
class User extends Model {
use BefriendedTrait {
follow as private followTrait;
}
public function follow(User $user) {
return $this->followTrait($user);
}
}
Logging: Enable query logging to debug scope performance:
DB::enableQueryLog();
$user->following()->get();
dd(DB::getQueryLog());
Custom Logic:
Override trait methods (e.g., follow) to add validation or logic:
public function follow(User $user)
{
if ($this->isBlockedBy($user)) {
throw new \Exception("Cannot follow a blocked user.");
}
return parent::follow($user);
}
Events:
Publish and listen to events (e.g., Following, Blocking) for custom workflows:
// In EventServiceProvider
protected $listen = [
'RenokiCo\Befriended\Events\Following' => [
'App\Listeners\LogFollowAction',
],
];
API Resources:
Extend Befriended data in API responses:
public function toArray($request)
{
return [
'id' => $this->id,
'is_following' => auth()->user()->isFollowing($this),
'is_blocked' => auth()->user()->isBlockedBy($this),
];
}
Testing: Use factories to seed test data:
$user1 = User::factory()->create();
$user2 = User::factory()->create();
$user1->follow($user2);
$this->assertTrue($user1->isFollowing($user2));
How can I help you explore Laravel packages today?