eloquent-works/fellowship

Fellowship provides elegant friendship and social connection tools for Laravel applications, including friend requests, blocks, mutual friends, and relationship management.

Maintainers

Package info

github.com/EloquentWorks/Fellowship

pkg:composer/eloquent-works/fellowship

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.0 2026-07-26 09:11 UTC

This package is not auto-updated.

Last update: 2026-07-27 07:16:21 UTC


README

Tests Latest Release License

A complete fellowship and social-connection package for Laravel applications.

Laravel Fellowship adds fellowship requests, accepted connections, blocking, mutual fellowships, request expiration, resend cooldowns, lifecycle events, optional web routes, and maintenance commands to your Eloquent models.

$user->sendFellowshipRequestTo($otherUser);

$otherUser->acceptFellowshipRequestFrom($user);

$user->isFellowshipWith($otherUser);

✨ Highlights

  • Send, accept, deny, cancel, and expire fellowship requests
  • Create and remove accepted fellowships
  • Block and unblock users
  • Prevent requests between blocked users
  • Retrieve incoming and outgoing requests
  • Retrieve accepted and blocked users
  • Find and count mutual fellowships
  • Configure request expiration and resend cooldowns
  • Dispatch lifecycle events for application integrations
  • Register optional web routes with Route::fellowship()
  • Customize package models, tables, routes, and controllers
  • Expire stale pending requests with an Artisan command

📋 Requirements

Laravel PHP Orchestra Testbench
12.x 8.2+ 10.x
13.x 8.3+ 11.x

📦 Installation

Install Fellowship through Composer:

composer require eloquent-works/fellowship

Publish the configuration and migrations:

php artisan fellowship:install

Publish the optional route snippet during installation:

php artisan fellowship:install --routes

Run the migrations:

php artisan migrate

🧩 Add the Trait

Add HasFellowships to every Eloquent model that can participate in a fellowship:

<?php

namespace App\Models;

use EloquentWorks\Fellowship\Traits\HasFellowships;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasFellowships;
}

📨 Fellowship Requests

Send a request:

$request = $user->sendFellowshipRequestTo($otherUser);

Accept or deny an incoming request:

$otherUser->acceptFellowshipRequestFrom($user);

$otherUser->denyFellowshipRequestFrom($user);

Cancel an outgoing request:

$user->cancelFellowshipRequestTo($otherUser);

Check whether a request can be sent:

$user->canSendFellowshipRequestTo($otherUser);

🤝 Accepted Fellowships

Check whether two models share an accepted fellowship:

$user->isFellowshipWith($otherUser);

Retrieve accepted fellowships:

$friends = $user->friends();

$count = $user->fellowshipsCount();

Remove an accepted fellowship:

$user->removeFellowship($otherUser);

removeFellowshipWith() remains available as a compatibility alias.

👥 Mutual Fellowships

Retrieve mutual connections:

$mutual = $user->mutualFellowshipsWith($otherUser);

Count mutual connections:

$count = $user->mutualFellowshipsCountWith($otherUser);

Singular compatibility helpers are also available:

$user->mutualFellowshipWith($otherUser);
$user->mutualFellowshipCountWith($otherUser);

🚫 Blocking

Block or unblock another user:

$user->blockUser($otherUser);

$user->unblockUser($otherUser);

Inspect blocking state:

$user->hasBlocked($otherUser);
$user->isBlockedBy($otherUser);

Retrieve blocked users:

$user->blockedUsers();
$user->blockedByUsers();

Blocking removes an existing request or accepted fellowship between the two models and prevents new requests until the blocker unblocks the other user.

🔎 Relationships and Status

Retrieve the stored relationship model:

$fellowship = $user->fellowshipWith($otherUser);

Retrieve its status:

$status = $user->fellowshipStatusWith($otherUser);

The status is one of the package status values, such as pending, accepted, denied, canceled, expired, or blocked; otherwise, it is null.

Request collections:

$user->incomingFellowshipRequests();
$user->outgoingFellowshipRequests();

Relationship queries:

$user->sentFellowships();
$user->receivedFellowships();
$user->acceptedSentFellowships();
$user->acceptedReceivedFellowships();
$user->pendingSentFellowships();
$user->pendingReceivedFellowships();

🛣️ Web Routes

Fellowship does not load web routes automatically. Register them where you want them in routes/web.php:

<?php

use Illuminate\Support\Facades\Route;

Route::fellowship();

Customize the route group:

Route::fellowship([
    'prefix' => 'connections',
    'name' => 'connections.',
    'middleware' => ['web', 'auth', 'verified'],
]);

The macro registers routes for sending, accepting, denying, canceling, and removing fellowships, along with blocking and unblocking users.

⚙️ Configuration

Publish the configuration file:

php artisan vendor:publish --tag=fellowship-config

Important defaults:

return [
    'models' => [
        'fellowship' => EloquentWorks\Fellowship\Models\Fellowship::class,
        'user' => null,
    ],

    'tables' => [
        'users' => 'users',
        'fellowships' => 'fellowships',
    ],

    'routes' => [
        'prefix' => 'fellowship',
        'middleware' => ['web', 'auth'],
        'name' => 'fellowship.',
    ],

    'expires_after_days' => 30,
    'request_cooldown_days' => 7,
    'dispatch_events' => true,
];

Set expires_after_days to null when pending requests should never expire. Set request_cooldown_days to null or 0 to disable resend cooldowns.

📣 Events

Fellowship can dispatch the following lifecycle events:

  • FellowshipRequestSent
  • FellowshipRequestAccepted
  • FellowshipRequestDenied
  • FellowshipRequestCanceled
  • FellowshipRequestExpired
  • FellowshipRemoved
  • UserBlocked
  • UserUnblocked

Use these events for notifications, activity feeds, auditing, achievements, analytics, and other application-specific side effects.

Disable all package events through configuration:

'dispatch_events' => false,

⏳ Expiration and Scheduling

Expire stale pending requests manually:

php artisan fellowships:expire

Process records with a custom chunk size:

php artisan fellowships:expire --chunk=500

Schedule automatic expiration in your application:

use Illuminate\Support\Facades\Schedule;

Schedule::command('fellowships:expire')->daily();

📚 Documentation

✅ Quality Checks

Run the complete quality suite:

composer quality

Or run each check separately:

composer format:test
composer analyse
composer test

Format the package source:

composer format

🔒 Security

Please report security vulnerabilities privately according to SECURITY.md. Do not disclose unresolved vulnerabilities through public GitHub issues.

🤝 Contributing

See CONTRIBUTING.md and CODE_OF_CONDUCT.md.

🙏 Credits

Built by Eloquent Works.

📄 License

Laravel Fellowship is open-source software licensed under the MIT License.