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 claps to any Eloquent model. Laravel Love provides a flexible, enterprise-ready system for GitHub/Facebook-style reactions with migrations and upgrade guidance, letting users express feelings about your content in minutes.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

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

    use Cog\Laravel\Love\Traits\Reactable;
    
    class Post extends Model
    {
        use Reactable;
    }
    
  3. Make a model reacterable (e.g., User):

    use Cog\Laravel\Love\Traits\Reacterable;
    
    class User extends Model
    {
        use Reacterable;
    }
    
  4. First reaction (e.g., a "like"):

    $user = User::first();
    $post = Post::first();
    
    $user->reactTo($post, 'like'); // Default reaction type
    

Key First Use Case

Display reaction counts on a post:

$post = Post::withReactionCounts()->find(1);
echo $post->reaction_counts['like']; // Outputs: 42

Implementation Patterns

Core Workflows

  1. Reaction System Setup

    • Use php artisan love:setup-reactable and php artisan love:setup-reacterable to generate migrations for existing models.
    • Customize reaction types via config/love.php:
      'reaction_types' => [
          'like' => ['mass' => 1, 'weight' => 1],
          'dislike' => ['mass' => -1, 'weight' => 1],
          'love' => ['mass' => 2, 'weight' => 2],
      ],
      
  2. Weighted Reactions

    • Assign custom rates to reactions:
      $user->reactTo($post, 'like', 5.0); // Rate between Reaction::RATE_MIN (1) and Reaction::RATE_MAX (10)
      
    • Retrieve weighted totals:
      $post->reaction_totals['like']; // Returns weighted sum (e.g., 5.0 * 42)
      
  3. Querying Reactions

    • Filter reactable models by reactions:
      Post::whereReactedToBy(User::first(), 'like')->get();
      Post::whereNotReactedToBy(User::first())->get();
      
    • Join reaction counts in queries:
      Post::joinReactionCounterOfType('like')->get();
      
  4. Aggregation & Caching

    • Rebuild aggregates via queue (recommended for large datasets):
      php artisan love:recount --queue-connection=redis
      
    • Access cached aggregates:
      $post->reaction_counts; // ['like' => 42, 'dislike' => 5]
      $post->reaction_totals; // ['like' => 210.0, 'dislike' => -25.0]
      
  5. Custom Reaction Types

    • Dynamically add types at runtime:
      $reactionType = \Cog\Laravel\Love\ReactionType::create('clap', ['mass' => 1, 'weight' => 1]);
      $user->reactTo($post, $reactionType);
      

Integration Tips

  • API Endpoints: Use Reacter::hasReactedTo() to check reactions in auth middleware:
    if (auth()->user()->hasReactedTo($post, 'like')) {
        return response()->json(['already_liked' => true]);
    }
    
  • Frontend: Fetch reaction data via:
    Post::with(['reaction_counts', 'reaction_totals'])->get();
    
  • Admin Panels: Use php artisan love:recount to manually update aggregates after bulk operations.

Gotchas and Tips

Pitfalls

  1. Rate Validation

    • Reactions with rates outside Reaction::RATE_MIN (1) and Reaction::RATE_MAX (10) throw RateOutOfRange or RateInvalid. Validate client-side to avoid API errors.
  2. Queue Dependencies

    • Aggregates (reaction_counts, reaction_totals) are updated asynchronously. Avoid relying on them immediately after reactions (e.g., in real-time APIs). Use Reaction::count() for live counts:
      $post->reactions()->where('type', 'like')->count();
      
  3. Migration Conflicts

    • If manually adding love_reactant_id or love_reacter_id columns, ensure they match the config (love.tables.reactants, love.tables.reacters). Use --not-nullable in setup commands for required fields.
  4. Observer Overrides

    • The package removes default ReactionObserver in v10+. If extending, register custom observers in LoveEventServiceProvider:
      public function boot()
      {
          $this->registerReactantListeners();
          $this->registerReacterListeners();
      }
      
  5. Caching Quirks

    • Aggregates are cached per-reactant. Clear cache after bulk updates:
      php artisan cache:clear
      
    • For large datasets, use --queue-connection with love:recount to avoid timeouts.

Debugging

  • Reaction Not Showing? Check if the reacter_id (user) and reactant_id (post) are correctly linked. Run:

    php artisan tinker
    >> \Cog\Laravel\Love\Reaction::where('reacter_id', 1)->where('reactant_id', 1)->get();
    
  • Aggregates Out of Sync? Force recount:

    php artisan love:recount --force
    
  • Performance Issues? Disable aggregate caching in config/love.php:

    'cache_aggregates' => false,
    

Extension Points

  1. Custom Reaction Models Override the default Reaction model by binding your class in LoveServiceProvider:

    $this->app->bind(\Cog\Contracts\Love\Reaction::class, CustomReaction::class);
    
  2. Event Listeners Extend reaction logic by listening to events:

    \Cog\Laravel\Love\Events\ReactionCreated::class => [
        \App\Listeners\LogReaction::class,
    ],
    
  3. Dynamic Reaction Types Fetch all types dynamically:

    $types = \Cog\Laravel\Love\ReactionType::all();
    
  4. Multi-Tenant Support Scope reactions by tenant in Reacterable/Reactable traits by overriding:

    protected static function getReacterTable()
    {
        return 'tenants_' . tenant()->id . '.users';
    }
    

Pro Tips

  • Bulk Reactions: Use Reacter::reactToMany() for batch operations:
    $user->reactToMany($posts, 'like');
    
  • Rate-Based Features: Combine reaction_totals with reaction_counts to calculate averages:
    $post->average_rating = $post->reaction_totals['like'] / $post->reaction_counts['like'];
    
  • Soft Deletes: Ensure your Reacter/Reactant models use SoftDeletes if reactions should persist after deletion. Override getQualifiedReacterKeyName()/getQualifiedReactantKeyName() to handle soft-deleted keys.
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport