PHPackages                             turahe/laravel-likeable - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. turahe/laravel-likeable

ActiveLibrary[Database &amp; ORM](/categories/database)

turahe/laravel-likeable
=======================

Trait for Laravel Eloquent models to allow easy implementation of a 'like' or 'favorite' or 'remember' feature.

v1.2.0(7mo ago)97052MITPHPPHP ^8.3CI passing

Since Oct 27Pushed 7mo ago1 watchersCompare

[ Source](https://github.com/turahe/laravel-likeable)[ Packagist](https://packagist.org/packages/turahe/laravel-likeable)[ Docs](https://github.com/turahe/laravel-likeable)[ RSS](/packages/turahe-laravel-likeable/feed)WikiDiscussions master Synced today

READMEChangelog (2)Dependencies (8)Versions (6)Used By (0)

Introduction
------------

[](#introduction)

[![Latest Stable Version](https://camo.githubusercontent.com/03581309a67d8c8e4d0e3584d407e138a3099a0e136391799be19f8eebc536c2/68747470733a2f2f706f7365722e707567782e6f72672f7475726168652f6c61726176656c2d6c696b6561626c652f76)](//packagist.org/packages/turahe/laravel-likeable)[![Total Downloads](https://camo.githubusercontent.com/694ad2bf9024ab58d4a5e31fe5303c820fe9cfb136e1c0eba7ed84cb60dfe33e/68747470733a2f2f706f7365722e707567782e6f72672f7475726168652f6c61726176656c2d6c696b6561626c652f646f776e6c6f616473)](//packagist.org/packages/turahe/laravel-likeable)[![License](https://camo.githubusercontent.com/4aa5d7aa656da8f2fa8a4c8020f9e0294c49b60a94c7916fc8bd54c95f3d7747/68747470733a2f2f706f7365722e707567782e6f72672f7475726168652f6c61726176656c2d6c696b6561626c652f6c6963656e7365)](//packagist.org/packages/turahe/laravel-likeable)[![Tests](https://github.com/turahe/laravel-likeable/actions/workflows/tests.yml/badge.svg)](https://github.com/turahe/laravel-likeable/actions/workflows/tests.yml)[![Release](https://github.com/turahe/laravel-likeable/actions/workflows/release.yml/badge.svg)](https://github.com/turahe/laravel-likeable/actions/workflows/release.yml)[![Version Bump](https://github.com/turahe/laravel-likeable/actions/workflows/version-bump.yml/badge.svg)](https://github.com/turahe/laravel-likeable/actions/workflows/version-bump.yml)[![Code Coverage](https://camo.githubusercontent.com/c48616de132831d4187e700fc2ad33df16d5cdb282b6d719cf6e143dc05df558/68747470733a2f2f636f6465636f762e696f2f67682f7475726168652f6c61726176656c2d6c696b6561626c652f6272616e63682f6d61696e2f67726170682f62616467652e737667)](https://codecov.io/gh/turahe/laravel-likeable)[![PHP Version](https://camo.githubusercontent.com/3cd770b20545837658262654c7c1cdb3b59cd82ebca19d6408dfe66b0ff9430f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d382e332532422d626c75652e737667)](https://php.net)[![Laravel Version](https://camo.githubusercontent.com/b4e32f52a06a0d97226fbe53cf78384d0d7c1d7dd0e17965af4c8f4ce86f6833/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d313125324225323025374325323031322532422d7265642e737667)](https://laravel.com)[![Conventional Commits](https://camo.githubusercontent.com/9f7a75f0e3af8cca0597d218e8708da4791128679178573a9806a514be52d2eb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f436f6e76656e74696f6e616c253230436f6d6d6974732d312e302e302d2532334645353139363f6c6f676f3d636f6e76656e74696f6e616c636f6d6d697473266c6f676f436f6c6f723d7768697465)](https://conventionalcommits.org)[![Semantic Versioning](https://camo.githubusercontent.com/e58ab7d64121fdf6ba10eca65a5b7d0cf5fae71ed6903ecce85e0647eb1359ca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f73656d7665722d322e302e302d677265656e2e737667)](https://semver.org)[![Tests](https://camo.githubusercontent.com/0b9fe42cd91f5ea29a6994bf8b73319b417de5570df4e3346f1e13ed7e82d870/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d373925323070617373696e672d627269676874677265656e2e737667)](https://github.com/turahe/laravel-likeable/actions/workflows/tests.yml)

Laravel Likeable simplifies management of Eloquent model's likes &amp; dislikes. Make any model `likeable` &amp; `dislikeable` in a minute!

Contents
--------

[](#contents)

- [Features](#features)
- [Installation](#installation)
- [Usage](#usage)
    - [Prepare likeable model](#prepare-likeable-model)
    - [Available methods](#available-methods)
    - [Scopes](#scopes)
    - [Events](#events)
    - [Console commands](#console-commands)
- [Extending](#extending)
- [Change log](#change-log)
- [Contributing](#contributing)
- [Testing](#testing)
- [Continuous Integration](#continuous-integration)
- [Release Process](#release-process)
- [Security](#security)
- [Contributors](#contributors)
- [Alternatives](#alternatives)
- [License](#license)
- [About Turahe](#about-turahe)

Features
--------

[](#features)

- ✅ **Designed to work with Laravel Eloquent models**
- ✅ **Using contracts to keep high customization capabilities**
- ✅ **Using traits to get functionality out of the box**
- ✅ **Most part of the logic is handled by the `LikeableService`**
- ✅ **Has Artisan command `likeable:recount {model?} {type?}` to re-fetch likes counters**
- ✅ **Likeable model can have Likes and Dislikes**
- ✅ **Likes and Dislikes for one model are mutually exclusive**
- ✅ **Get Likeable models ordered by likes count**
- ✅ **Events for `like`, `unlike`, `dislike`, `undislike` methods**
- ✅ **Comprehensive test coverage (79 tests, 0 failures)**
- ✅ **Following PHP Standard Recommendations:**
    - [PSR-1 (Basic Coding Standard)](http://www.php-fig.org/psr/psr-1/)
    - [PSR-2 (Coding Style Guide)](http://www.php-fig.org/psr/psr-2/)
    - [PSR-4 (Autoloading Standard)](http://www.php-fig.org/psr/psr-4/)
- ✅ **Fully tested with PHPUnit**
- ✅ **Continuous Integration with GitHub Actions**
- ✅ **Code style checks with PHP CS Fixer**
- ✅ **Static analysis with Larastan**
- ✅ **Automated release workflows with conventional commits**
- ✅ **Semantic versioning and changelog generation**

Installation
------------

[](#installation)

First, pull in the package through Composer.

```
$ composer require turahe/laravel-likeable
```

**If you are using Laravel 5.5+ you can skip the register package part.**

#### Register package on Laravel 5.4 and lower

[](#register-package-on-laravel-54-and-lower)

Include the service provider within `app/config/app.php`.

```
'providers' => [
    Turahe\Likeable\LikeableServiceProvider::class,
],
```

#### Perform Database Migration

[](#perform-database-migration)

At last, you need to publish and run database migrations.

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

Usage
-----

[](#usage)

### Prepare likeable model

[](#prepare-likeable-model)

Use `Likeable` contract in model which will get likes behavior and implement it or just use `Likeable` trait.

```
use Turahe\Likeable\Contracts\Likeable as LikeableContract;
use Turahe\Likeable\Traits\Likeable;
use Illuminate\Database\Eloquent\Model;

class Article extends Model implements LikeableContract
{
    use Likeable;
}
```

### Available methods

[](#available-methods)

#### Likes

[](#likes)

##### Like model

[](#like-model)

```
$article->like(); // current user
$article->like($user->id);
```

##### Remove like mark from model

[](#remove-like-mark-from-model)

```
$article->unlike(); // current user
$article->unlike($user->id);
```

##### Toggle like mark of model

[](#toggle-like-mark-of-model)

```
$article->likeToggle(); // current user
$article->likeToggle($user->id);
```

##### Get model likes count

[](#get-model-likes-count)

```
$article->likesCount;
```

##### Get model likes counter

[](#get-model-likes-counter)

```
$article->likesCounter;
```

##### Get likes relation

[](#get-likes-relation)

```
$article->likes();
```

##### Get iterable `Illuminate\Database\Eloquent\Collection` of existing model likes

[](#get-iterable-illuminatedatabaseeloquentcollection-of-existing-model-likes)

```
$article->likes;
```

##### Boolean check if user liked model

[](#boolean-check-if-user-liked-model)

```
$article->liked; // current user
$article->liked(); // current user
$article->liked($user->id);
```

*Checks in eager loaded relations `likes` &amp; `likesAndDislikes` first.*

##### Get collection of users who liked model

[](#get-collection-of-users-who-liked-model)

```
$article->collectLikers();
```

##### Delete all likes for model

[](#delete-all-likes-for-model)

```
$article->removeLikes();
```

#### Dislikes

[](#dislikes)

##### Dislike model

[](#dislike-model)

```
$article->dislike(); // current user
$article->dislike($user->id);
```

##### Remove dislike mark from model

[](#remove-dislike-mark-from-model)

```
$article->undislike(); // current user
$article->undislike($user->id);
```

##### Toggle dislike mark of model

[](#toggle-dislike-mark-of-model)

```
$article->dislikeToggle(); // current user
$article->dislikeToggle($user->id);
```

##### Get model dislikes count

[](#get-model-dislikes-count)

```
$article->dislikesCount;
```

##### Get model dislikes counter

[](#get-model-dislikes-counter)

```
$article->dislikesCounter;
```

##### Get dislikes relation

[](#get-dislikes-relation)

```
$article->dislikes();
```

##### Get iterable `Illuminate\Database\Eloquent\Collection` of existing model dislikes

[](#get-iterable-illuminatedatabaseeloquentcollection-of-existing-model-dislikes)

```
$article->dislikes;
```

##### Boolean check if user disliked model

[](#boolean-check-if-user-disliked-model)

```
$article->disliked; // current user
$article->disliked(); // current user
$article->disliked($user->id);
```

*Checks in eager loaded relations `dislikes` &amp; `likesAndDislikes` first.*

##### Get collection of users who disliked model

[](#get-collection-of-users-who-disliked-model)

```
$article->collectDislikers();
```

##### Delete all dislikes for model

[](#delete-all-dislikes-for-model)

```
$article->removeDislikes();
```

#### Likes and Dislikes

[](#likes-and-dislikes)

##### Get difference between likes and dislikes

[](#get-difference-between-likes-and-dislikes)

```
$article->likesDiffDislikesCount;
```

##### Get likes and dislikes relation

[](#get-likes-and-dislikes-relation)

```
$article->likesAndDislikes();
```

##### Get iterable `Illuminate\Database\Eloquent\Collection` of existing model likes and dislikes

[](#get-iterable-illuminatedatabaseeloquentcollection-of-existing-model-likes-and-dislikes)

```
$article->likesAndDislikes;
```

### Scopes

[](#scopes)

##### Find all articles liked by user

[](#find-all-articles-liked-by-user)

```
Article::whereLikedBy($user->id)
    ->with('likesCounter') // Allow eager load (optional)
    ->get();
```

##### Find all articles disliked by user

[](#find-all-articles-disliked-by-user)

```
Article::whereDislikedBy($user->id)
    ->with('dislikesCounter') // Allow eager load (optional)
    ->get();
```

##### Fetch Likeable models by likes count

[](#fetch-likeable-models-by-likes-count)

```
$sortedArticles = Article::orderByLikesCount()->get();
$sortedArticles = Article::orderByLikesCount('asc')->get();
```

*Uses `desc` as default order direction.*

##### Fetch Likeable models by dislikes count

[](#fetch-likeable-models-by-dislikes-count)

```
$sortedArticles = Article::orderByDislikesCount()->get();
$sortedArticles = Article::orderByDislikesCount('asc')->get();
```

*Uses `desc` as default order direction.*

### Events

[](#events)

On each like added `\Turahe\Likeable\Events\ModelWasLiked` event is fired.

On each like removed `\Turahe\Likeable\Events\ModelWasUnliked` event is fired.

On each dislike added `\Turahe\Likeable\Events\ModelWasDisliked` event is fired.

On each dislike removed `\Turahe\Likeable\Events\ModelWasUndisliked` event is fired.

### Console commands

[](#console-commands)

##### Recount likes and dislikes of all model types

[](#recount-likes-and-dislikes-of-all-model-types)

```
$ php artisan likeable:recount
```

##### Recount likes and dislikes of concrete model type (using morph map alias)

[](#recount-likes-and-dislikes-of-concrete-model-type-using-morph-map-alias)

```
$ php artisan likeable:recount --model="article"
```

##### Recount likes and dislikes of concrete model type (using fully qualified class name)

[](#recount-likes-and-dislikes-of-concrete-model-type-using-fully-qualified-class-name)

```
$ php artisan likeable:recount --model="App\Models\Article"
```

##### Recount only likes of all model types

[](#recount-only-likes-of-all-model-types)

```
$ php artisan likeable:recount --type="like"
```

##### Recount only likes of concrete model type (using morph map alias)

[](#recount-only-likes-of-concrete-model-type-using-morph-map-alias)

```
$ php artisan likeable:recount --model="article" --type="like"
```

##### Recount only likes of concrete model type (using fully qualified class name)

[](#recount-only-likes-of-concrete-model-type-using-fully-qualified-class-name)

```
$ php artisan likeable:recount --model="App\Models\Article" --type="like"
```

##### Recount only dislikes of all model types

[](#recount-only-dislikes-of-all-model-types)

```
$ php artisan likeable:recount --type="dislike"
```

##### Recount only dislikes of concrete model type (using morph map alias)

[](#recount-only-dislikes-of-concrete-model-type-using-morph-map-alias)

```
$ php artisan likeable:recount --model="article" --type="dislike"
```

##### Recount only dislikes of concrete model type (using fully qualified class name)

[](#recount-only-dislikes-of-concrete-model-type-using-fully-qualified-class-name)

```
$ php artisan likeable:recount --model="App\Models\Article" --type="dislike"
```

Extending
---------

[](#extending)

You can override core classes of package with your own implementations:

- `Models\Like`
- `Models\LikeCounter`
- `Services\LikeableService`

*Note: Don't forget that all custom models must implement original models interfaces.*

To make it you should use container [binding interfaces to implementations](https://laravel.com/docs/master/container#binding-interfaces-to-implementations) in your application service providers.

##### Use model class own implementation

[](#use-model-class-own-implementation)

```
$this->app->bind(
    \Turahe\Likeable\Contracts\Like::class,
    \App\Models\CustomLike::class
);
```

##### Use service class own implementation

[](#use-service-class-own-implementation)

```
$this->app->singleton(
    \Turahe\Likeable\Contracts\LikeableService::class,
    \App\Services\CustomService::class
);
```

After that your `CustomLike` and `CustomService` classes will be instantiable with helper method `app()`.

```
$model = app(\Turahe\Likeable\Contracts\Like::class);
$service = app(\Turahe\Likeable\Contracts\LikeableService::class);
```

Change log
----------

[](#change-log)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Testing
-------

[](#testing)

This package includes comprehensive test coverage with 79 tests covering all functionality:

- **Common Use Tests** - Basic like/unlike functionality
- **Counter Tests** - Like/dislike counter management
- **Dislike Tests** - Dislike-specific functionality
- **Enum Tests** - LikeType enum functionality
- **Event Tests** - Event dispatching
- **Exception Tests** - Custom exception handling
- **Service Tests** - Service layer functionality
- **Toggle Tests** - Like/dislike toggle operations
- **Console Command Tests** - Artisan command functionality

### Running Tests

[](#running-tests)

You can run the tests with:

```
$ vendor/bin/phpunit
```

Or use the composer script:

```
$ composer test
```

### Test Coverage

[](#test-coverage)

Run tests with coverage:

```
$ composer test:coverage
```

This will generate HTML coverage reports in the `coverage-html` directory.

Continuous Integration
----------------------

[](#continuous-integration)

This package uses GitHub Actions for continuous integration. The CI pipeline includes:

### Test Matrix

[](#test-matrix)

- **PHP Versions**: 8.3, 8.4
- **Laravel Versions**: 11.x, 12.x
- **Test Coverage**: Generated for PHP 8.3+ + Laravel 11/12.x

### CI Jobs

[](#ci-jobs)

1. **Tests**: Runs the full test suite across all PHP/Laravel combinations with code coverage
2. **Static Analysis**: Code style checking with PHP CS Fixer and Larastan across all PHP/Laravel combinations
3. **Lint**: PHP syntax validation
4. **Coverage**: Detailed code coverage reporting with HTML reports

### Local Development

[](#local-development)

You can run the same checks locally:

```
# Run all checks
$ composer check

# Run specific checks
$ composer test          # Run tests
$ composer test:coverage # Run tests with coverage
$ composer lint          # Check code style
$ composer analyse       # Run static analysis
```

### Code Coverage

[](#code-coverage)

Code coverage reports are generated and uploaded to [Codecov](https://codecov.io/gh/turahe/laravel-likeable).

Release Process
---------------

[](#release-process)

This package uses automated release workflows for version management and deployment.

### Automated Release Workflows

[](#automated-release-workflows)

#### Version Bump Workflow

[](#version-bump-workflow)

- **Trigger**: Pushes to `main` branch with conventional commits
- **Actions**:
    - Runs tests, static analysis, and linting
    - Updates `CHANGELOG.md` with new entries
    - Creates release preparation PRs for new features
    - Follows [Conventional Commits](https://www.conventionalcommits.org/) format

#### Release Workflow

[](#release-workflow)

- **Trigger**: Pushing tags with `v*` pattern (e.g., `v1.2.3`)
- **Actions**:
    - Validates code quality (tests, analysis, linting)
    - Generates changelog from git history
    - Creates GitHub release with assets
    - Uploads `composer.json`, `CHANGELOG.md`, and `README.md` as release assets

### Creating a Release

[](#creating-a-release)

1. **Prepare Changes**: Ensure all changes follow conventional commit format
2. **Create Tag**: Create and push a new version tag ```
    git tag v1.2.3
    git push origin v1.2.3
    ```
3. **Automated Process**: The release workflow will automatically:
    - Run all quality checks
    - Generate release notes
    - Create GitHub release
    - Upload release assets

### Conventional Commits

[](#conventional-commits)

This project follows the [Conventional Commits](https://www.conventionalcommits.org/) specification:

- `feat:` - New features (triggers release preparation)
- `fix:` - Bug fixes
- `docs:` - Documentation changes
- `style:` - Code style changes
- `refactor:` - Code refactoring
- `perf:` - Performance improvements
- `test:` - Test additions or changes
- `build:` - Build system changes
- `ci:` - CI/CD changes
- `chore:` - Maintenance tasks

Security
--------

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

Contributors
------------

[](#contributors)

- [Nur Wachid](https://github.com/turahe) - *Initial work*

Alternatives
------------

[](#alternatives)

- [spatie/laravel-likes](https://github.com/spatie/laravel-likes) - A simple package to add likes to Eloquent models
- [rtconner/laravel-likeable](https://github.com/rtconner/laravel-likeable) - Likeable trait for Laravel Eloquent models

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE) for more information.

About Turahe
------------

[](#about-turahe)

Turahe is a software development company focused on creating high-quality Laravel packages and applications. Visit us at [turahe.id](https://turahe.id).

###  Health Score

46

—

FairBetter than 93% of packages

Maintenance62

Regular maintenance activity

Popularity24

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity72

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~577 days

Total

4

Last Release

238d ago

Major Versions

v0.0.1 → v1.0.02024-08-01

PHP version history (3 changes)v0.0.1PHP &gt;=5.6.0

v1.0.0PHP ^7.3|^8.0

v1.1.0PHP ^8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/f3513bd6100438bcb8c6b1a7e241a66e1ddaf1c11ee33883e06ef4a2784120db?d=identicon)[turahe](/maintainers/turahe)

---

Top Contributors

[![turahe](https://avatars.githubusercontent.com/u/6832622?v=4)](https://github.com/turahe "turahe (47 commits)")

---

Tags

dislikedislike-modeldislikesdislikes-countlaravellikelikes-countrecount-likessimplelaraveleloquenttraitlikerememberFollowfavoritelikeablelikablefavourite

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/turahe-laravel-likeable/health.svg)

```
[![Health](https://phpackages.com/badges/turahe-laravel-likeable/health.svg)](https://phpackages.com/packages/turahe-laravel-likeable)
```

###  Alternatives

[rtconner/laravel-likeable

Trait for Laravel Eloquent models to allow easy implementation of a 'like' or 'favorite' or 'remember' feature.

402385.8k5](/packages/rtconner-laravel-likeable)[cybercog/laravel-love

Make Laravel Eloquent models reactable with any type of emotions in a minutes!

1.2k293.6k1](/packages/cybercog-laravel-love)[qirolab/laravel-reactions

Implement reactions (like, dislike, love, emotion etc) on Laravel Eloquent models.

19662.9k](/packages/qirolab-laravel-reactions)[christiankuri/laravel-favorite

Allows Laravel Eloquent models to implement a 'favorite' or 'remember' or 'follow' feature.

226466.8k4](/packages/christiankuri-laravel-favorite)[devdojo/laravel-reactions

3529.4k](/packages/devdojo-laravel-reactions)[jamesmills/watchable

A package to allow your Models to become watchable by a User

685.4k](/packages/jamesmills-watchable)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
