Installation:
composer require hootlex/laravel-friendships
Publish the migration:
php artisan vendor:publish --provider="Hootlex\Friendships\FriendshipsServiceProvider" --tag="migrations"
Run the migration:
php artisan migrate
Use the Trait:
Add Hootlex\Friendships\Traits\Friendable to your Eloquent model (e.g., User):
use Hootlex\Friendships\Traits\Friendable;
class User extends Model
{
use Friendable;
}
First Use Case:
Send a friendship request from user1 to user2:
$user1 = User::find(1);
$user2 = User::find(2);
$user1->sendFriendRequest($user2);
Sending/Managing Requests:
// Send a request
$user->sendFriendRequest($friend);
// Accept/deny
$user->acceptFriendRequest($requester);
$user->denyFriendRequest($requester);
// Check status
$status = $user->getFriendshipStatus($friend); // 'pending', 'accepted', 'blocked', etc.
Blocking Users:
$user->block($friend); // Blocks the friend
$user->unblock($friend); // Unblocks the friend
Grouping Friends:
// Create a group
$group = $user->createFriendGroup('Colleagues');
// Add friends to a group
$group->addFriends([$friend1, $friend2]);
// Retrieve friends in a group
$colleagues = $group->friends;
Querying Friends:
// Get all friends (accepted requests)
$friends = $user->friends;
// Get pending requests (received)
$pendingRequests = $user->pendingFriendRequests;
// Get sent requests
$sentRequests = $user->sentFriendRequests;
Customizing Models:
Extend the Friendable trait to add custom logic:
use Hootlex\Friendships\Traits\Friendable as BaseFriendable;
class User extends Model
{
use BaseFriendable;
public function sendFriendRequest($friend)
{
// Custom logic before sending
$result = parent::sendFriendRequest($friend);
// Custom logic after sending
return $result;
}
}
Notifications: Integrate with Laravel Notifications to alert users of new requests:
// In your User model or a service
$user->sendFriendRequest($friend)->then(function ($request) use ($friend) {
$friend->notify(new FriendRequestReceived($request));
});
API Endpoints: Example routes for a RESTful API:
Route::post('/users/{user}/friends/{friend}/request', [UserController::class, 'sendFriendRequest']);
Route::post('/users/{user}/friends/{friend}/accept', [UserController::class, 'acceptFriendRequest']);
Route::post('/users/{user}/friends/{friend}/block', [UserController::class, 'blockFriend']);
Testing: Use factories to seed test data:
$user1 = User::factory()->create();
$user2 = User::factory()->create();
$user1->sendFriendRequest($user2);
$this->assertEquals('pending', $user2->getFriendshipStatus($user1));
Migration Conflicts:
friendships table, drop it before publishing the migration to avoid conflicts.friendships table has the correct columns (user_id, friend_id, status, etc.).Circular Dependencies:
$user->sendFriendRequest($user)), as it may cause infinite loops or errors in some implementations.Status Logic:
null for no relationship, 'pending' for requests, 'accepted' for friends, and 'blocked' for blocked users. Double-check statuses when debugging:
$status = $user->getFriendshipStatus($friend);
dd($status); // Debug the status
Performance:
$user->load('friends', 'pendingFriendRequests');
Soft Deletes:
SoftDeletes, ensure the friendships table also has deleted_at and handle soft-deleted users in friendship logic.Query Logs: Enable Laravel’s query logging to inspect SQL:
DB::enableQueryLog();
$user->friends; // Trigger query
dd(DB::getQueryLog());
Friendship Status:
If getFriendshipStatus() returns unexpected results, verify the underlying friendships table data:
$friendship = DB::table('friendships')
->where('user_id', $user->id)
->where('friend_id', $friend->id)
->first();
dd($friendship);
Event Listeners:
Override or listen to friendship events (e.g., FriendRequestSent, FriendshipAccepted) to debug workflows:
// In EventServiceProvider
protected $listen = [
'Hootlex\Friendships\Events\FriendRequestSent' => [
'App\Listeners\LogFriendRequest',
],
];
Custom Statuses:
Extend the status field in the friendships table or override the getFriendshipStatus() method to add custom states (e.g., 'pending_verification').
Validation: Add validation before sending requests (e.g., prevent duplicates):
public function sendFriendRequest($friend)
{
if ($this->getFriendshipStatus($friend) !== null) {
throw new \Exception('Friendship already exists.');
}
return parent::sendFriendRequest($friend);
}
Group Customization:
Extend the FriendGroup model to add metadata (e.g., created_at, description):
class FriendGroup extends Model
{
protected $fillable = ['user_id', 'name', 'description'];
}
API Resources: Create custom API resources for friendships to control serialization:
class FriendResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'friendship_status' => $this->whenLoaded('friendshipStatus'),
];
}
}
Table Names:
The package defaults to friendships, but you can override it in the config:
'table' => 'custom_friendships',
Publish the config first:
php artisan vendor:publish --provider="Hootlex\Friendships\FriendshipsServiceProvider" --tag="config"
Model Binding:
Ensure your routes use the correct model binding (e.g., User::class instead of App\Models\User). The package relies on Eloquent’s polymorphic relationships.
Polymorphic Relationships:
If using polymorphic friendships (e.g., User and Team models), ensure the friendships table has friendable_type and friendable_id columns. The package supports this out of the box.
How can I help you explore Laravel packages today?