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 Likeable Laravel Package

turahe/laravel-likeable

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require turahe/laravel-likeable
    

    Ensure your Laravel version is 11+ or 12+ and PHP is 8.3+.

  2. Use the Trait Apply the Likeable trait to your Eloquent model:

    use Turahe\Likeable\Likeable;
    
    class Post extends Model
    {
        use Likeable;
    }
    

    This auto-generates:

    • likes() relationship (many-to-many with users table).
    • like(), unlike(), toggleLike() methods.
    • isLikedBy() helper.
  3. First Use Case

    // Toggle a user's like on a Post
    $post = Post::find(1);
    $post->toggleLike(auth()->id());
    
    // Check if a user liked the Post
    if ($post->isLikedBy(auth()->id())) {
        echo "Liked!";
    }
    
  4. Migrations Run the included migration (published via LikeableServiceProvider):

    php artisan vendor:publish --provider="Turahe\Likeable\LikeableServiceProvider" --tag="migrations"
    php artisan migrate
    

Implementation Patterns

Core Workflows

  1. Basic Like Actions

    // Like/unlike via user ID
    $post->like($userId);      // Add like
    $post->unlike($userId);    // Remove like
    $post->toggleLike($userId); // Toggle state
    
    // Like/unlike via authenticated user (if using Laravel auth)
    $post->like(auth()->id());
    
  2. Querying Liked Models

    // Get all liked Posts for a user
    $likedPosts = auth()->user()->likedPosts;
    
    // Get Posts liked by a specific user
    $user = User::find(1);
    $user->likedPosts; // Collection of liked Posts
    
  3. Counting Likes

    $post->likesCount; // Returns integer count of likes
    
  4. Customizing the Like Table Override the default likeable table name in your model:

    class Post extends Model
    {
        use Likeable;
    
        protected $likeableTable = 'post_likes';
    }
    

Advanced Patterns

  1. Customizing the Relationship Extend the default likes() relationship:

    public function likes()
    {
        return $this->belongsToMany(User::class, 'custom_like_table')
                    ->withTimestamps()
                    ->as('likes');
    }
    
  2. Adding Metadata to Likes Extend the pivot table to store additional data (e.g., created_at):

    // Migration for custom pivot table
    Schema::create('post_likes', function (Blueprint $table) {
        $table->id();
        $table->foreignId('post_id')->constrained()->cascadeOnDelete();
        $table->foreignId('user_id')->constrained()->cascadeOnDelete();
        $table->timestamps();
    });
    
    // Update the relationship in your model
    public function likes()
    {
        return $this->belongsToMany(User::class, 'post_likes')
                    ->withTimestamps();
    }
    
  3. Batch Liking/Unliking

    // Like multiple posts at once
    $postIds = [1, 2, 3];
    $userId = auth()->id();
    foreach ($postIds as $id) {
        Post::find($id)->toggleLike($userId);
    }
    
    // Or use a query builder approach
    Post::whereIn('id', $postIds)->each->toggleLike($userId);
    
  4. Event Listeners Listen for like/unlike events (e.g., to trigger notifications):

    // In EventServiceProvider
    protected $listen = [
        'Turahe\Likeable\Events\LikeAdded' => [
            'App\Listeners\SendLikeNotification',
        ],
        'Turahe\Likeable\Events\LikeRemoved' => [
            'App\Listeners\SendUnlikeNotification',
        ],
    ];
    
  5. API Responses Serialize like data in API responses:

    return PostResource::make($post)->additional([
        'is_liked' => $post->isLikedBy(auth()->id()),
        'likes_count' => $post->likesCount,
    ]);
    

Gotchas and Tips

Pitfalls

  1. Migration Conflicts

    • If you manually create a likeable table, the package’s migration will fail. Solution: Publish the migration first (vendor:publish --tag="migrations") and let the package handle it.
  2. User ID Mismatch

    • The package assumes user_id in the pivot table. If your users table uses a different column (e.g., uuid), override the relationship:
      public function likes()
      {
          return $this->belongsToMany(User::class, 'likeable')
                      ->using(Likeable::class)
                      ->withPivot('user_uuid'); // Custom pivot column
      }
      
  3. Caching Issues

    • likesCount and isLikedBy() may return stale data if cached. Solution: Clear the cache after bulk operations:
      Cache::forget("post:{$post->id}:likes_count");
      
  4. Mass Assignment Risks

    • The pivot table is vulnerable to mass assignment if not guarded. Solution: Add $guarded = ['user_id'] to your model or use $fillable.
  5. Soft Deletes

    • If your users table uses soft deletes, ensure the relationship respects it:
      public function likes()
      {
          return $this
              ->belongsToMany(User::class, 'likeable')
              ->withTimestamps()
              ->withPivot('created_at')
              ->whereNull('users.deleted_at');
      }
      

Debugging Tips

  1. Check Pivot Table Verify the pivot table structure:

    php artisan schema:dump
    

    Or inspect directly:

    \DB::select("PRAGMA table_info(likeable)");
    
  2. Log Like Events Temporarily log like actions to debug:

    event(new \Turahe\Likeable\Events\LikeAdded($this, $userId));
    // Add to EventServiceProvider
    
  3. Test Relationships Validate the relationship in Tinker:

    php artisan tinker
    >> $post = App\Models\Post::find(1);
    >> $post->likes
    

Extension Points

  1. Custom Like Logic Override the toggleLike() method for custom behavior:

    public function toggleLike($userId)
    {
        if ($this->isLikedBy($userId)) {
            $this->unlike($userId);
            event(new LikeRemoved($this, $userId));
        } else {
            $this->like($userId);
            event(new LikeAdded($this, $userId));
        }
        // Custom logic (e.g., increment a counter)
    }
    
  2. Add Like Conditions Restrict likes to specific users (e.g., only admins):

    public function like($userId)
    {
        $user = User::find($userId);
        if (!$user->isAdmin()) {
            throw new \Exception("Only admins can like this.");
        }
        $this->likes()->attach($userId);
    }
    
  3. Custom Pivot Data Store additional data (e.g., like_reason):

    $post->likes()->attach($userId, ['reason' => 'Great content!']);
    
  4. Rate Limiting Prevent spam likes with middleware:

    // app/Http/Middleware/PreventLikeSpam.php
    public function handle($request, Closure $next)
    {
        $user = auth()->user();
        $likes = $user->likes()->where('created_at', '>', now()->subMinutes(5))->count();
        if ($likes > 10) {
            abort(429, 'Too many likes!');
        }
        return $next($request);
    }
    
  5. Testing Use the Likeable trait in tests:

    public function test_like_toggle()
    {
        $post = new Post();
        $post->toggleLike(1);
        $this->assertTrue($post->isLikedBy(1));
        $post->toggleLike(1);
        $this->assertFalse($post->isLikedBy(1));
    }
    
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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui