Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Love Laravel Package

cybercog/laravel-love

Add reactions, likes, votes, and other “feelings” to any Eloquent model with Laravel Love. Flexible, enterprise-ready system inspired by GitHub/Facebook/Slack reactions. Includes migrations and APIs to make models reactable in minutes.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require cybercog/laravel-love
    php artisan migrate
    
  2. Make a model reactable (e.g., Post):

    php artisan love:setup-reactable Post
    

    This generates a migration adding love_reactant_id to your model.

  3. Make users reactable (e.g., User):

    php artisan love:setup-reacterable User
    

    This generates a migration adding love_reacter_id to the love_reactions table.

  4. Use in code:

    // User reacts to a Post
    $user->reactTo($post, 'like');
    
    // Check if user reacted
    $user->hasReactedTo($post, 'like');
    
    // Get reaction count
    $post->reactionCount('like');
    

First Use Case: Basic Reactions

// In a controller or service
$post = Post::find(1);
$user = auth()->user();

// Add a reaction
$user->reactTo($post, 'like');

// Check reaction status
if ($user->hasReactedTo($post, 'like')) {
    // User has liked
}

// Get total likes
$likeCount = $post->reactionCount('like');

Implementation Patterns

Core Workflows

1. Model Setup

  • Reactable Models (e.g., Post, Comment):
    use Cog\Laravel\Love\Traits\Reactable;
    
    class Post extends Model
    {
        use Reactable;
    }
    
  • Reacter Models (e.g., User, Guest):
    use Cog\Laravel\Love\Traits\Reacter;
    
    class User extends Authenticatable
    {
        use Reacter;
    }
    

2. Reaction Types

Define custom reaction types in config/love.php:

'reaction_types' => [
    'like' => [
        'name' => 'Like',
        'icon' => '❤️',
        'weight' => 1,
    ],
    'dislike' => [
        'name' => 'Dislike',
        'icon' => '👎',
        'weight' => -1,
    ],
    'laugh' => [
        'name' => 'Laugh',
        'icon' => '😂',
        'weight' => 0.5,
    ],
],

3. Weighted Reactions

// React with a custom rate (e.g., for sentiment analysis)
$user->reactTo($post, 'like', 0.8); // 80% "like"

// Check reaction rate
$rate = $user->getReactionRate($post, 'like');

4. Querying Reactions

// Get posts reacted by user
$posts = Post::whereReactedToBy($user)->get();

// Get posts with reactions between dates
$posts = Post::whereReactedToBetween(
    now()->subDays(7),
    now()
)->get();

// Get reactions for a post
$reactions = $post->reactions()->get();

5. Aggregates (Counters)

// Get total reactions for a post
$total = $post->reactionTotal();

// Get weighted sum (e.g., for sentiment)
$weightedSum = $post->reactionWeightedSum();

// Get reaction counts by type
$counts = $post->reactionCounts();

6. Bulk Operations

// Recount all aggregates (e.g., after data import)
php artisan love:recount

// Recount for a specific model
php artisan love:recount --model=Post

Integration Tips

API Endpoints

// Example: Add reaction via API
Route::post('/posts/{post}/react', function (Post $post, Request $request) {
    $user = auth()->user();
    $type = $request->input('type');
    $rate = $request->input('rate', null);

    $user->reactTo($post, $type, $rate);

    return response()->json(['success' => true]);
});

Frontend Integration

// Example: Toggle reaction
async function toggleReaction(postId, type) {
    const response = await fetch(`/posts/${postId}/react`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
        },
        body: JSON.stringify({ type }),
    });

    const data = await response.json();
    if (data.success) {
        updateReactionUI(postId, type);
    }
}

Custom Reaction Logic

// Extend Reacter trait for custom logic
class User extends Authenticatable
{
    use Reacter;

    public function reactTo($reactant, $type, $rate = null)
    {
        // Custom logic before reacting
        if ($this->isBanned()) {
            throw new \Exception("Banned users cannot react.");
        }

        return parent::reactTo($reactant, $type, $rate);
    }
}

Observers and Events

// Listen for reaction events
ReactionCreated::listen(function ($reaction) {
    // Send notification
    Notification::send($reaction->reactant, new ReactionNotification($reaction));
});

Gotchas and Tips

Pitfalls

  1. Foreign Key Constraints:

    • If you manually delete records from love_reactions, ensure foreign keys are handled:
      DB::statement('SET FOREIGN_KEY_CHECKS=0;');
      // Delete records
      DB::statement('SET FOREIGN_KEY_CHECKS=1;');
      
    • Use php artisan love:recount after bulk deletions to update aggregates.
  2. Rate Validation:

    • Reactions with rates outside RATE_MIN (default: -10) and RATE_MAX (default: 10) will throw RateOutOfRange or RateInvalid.
    • Configure in config/love.php:
      'rate' => [
          'min' => -5,
          'max' => 5,
      ],
      
  3. Queue Jobs:

    • Aggregate recounting runs asynchronously. If you need synchronous behavior, disable queues or use:
      $this->app->bind(\Cog\Laravel\Love\Reactant\Jobs\IncrementReactionAggregatesJob::class, function ($app) {
          return new class extends \Cog\Laravel\Love\Reactant\Jobs\IncrementReactionAggregatesJob {
              public function handle() {
                  parent::handle();
              }
          };
      });
      
  4. Model Caching:

    • Avoid caching reactable/reacter models aggressively, as reactions may change dynamically. Use:
      $post->fresh(); // Refresh model from DB
      
  5. Laravel Version Mismatches:

    • The package supports Laravel 9–13. Ensure your composer.json matches the package’s requirements. For example:
      "require": {
          "laravel/framework": "^10.0",
          "cybercog/laravel-love": "^10.0"
      }
      

Debugging

  1. Reaction Not Saving:

    • Check if the love_reacter_id column exists in the love_reactions table.
    • Verify the Reacter trait is used on the user model.
  2. Aggregate Counters Stale:

    • Run php artisan love:recount or manually trigger the job:
      \Cog\Laravel\Love\Reactant\Jobs\RebuildReactionAggregatesJob::dispatch();
      
  3. Query Performance:

    • Use whereReactedToBy and whereReactedToBetween scopes sparingly on large datasets. Add indexes:
      Schema::table('love_reactions', function (Blueprint $table) {
          $table->index(['love_reactant_id', 'love_reacter_id']);
          $table->index(['love_reacter_id', 'created_at']);
      });
      
  4. Custom Reaction Types Not Working:

    • Ensure the type is defined in config/love.php under reaction_types.
    • Check for typos in the type string (case-sensitive).

Tips

  1. Custom Reaction Types Dynamically:

    // Add reaction types at runtime
    $reactionTypes = config('love.reaction_types');
    $reactionTypes['custom'] = [
        'name' => 'Custom',
        'icon' => '🎨',
        'weight' => 0,
    ];
    config(['love.reaction_types' => $reactionTypes]);
    
  2. Bulk Reaction Assignment:

    // Assign reactions to multiple users at once
    $users = User::all();
    $post = Post::find(1);
    
    foreach ($users
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony