├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── database └── migrations │ ├── add_type_column_to_ratings_table.php.stub │ └── create_ratings_table.php.stub ├── media └── like-dislike.png └── src ├── LaravelRating.php ├── LaravelRatingFacade.php ├── LaravelRatingServiceProvider.php ├── Models └── Rating.php └── Traits ├── Like ├── CanLike.php └── Likeable.php ├── Rate ├── CanRate.php └── Rateable.php └── Vote ├── CanVote.php └── Votable.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-rating` will be documented in this file. 4 | 5 | ## 1.0.0 - 202X-XX-XX 6 | 7 | - initial release 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) nagy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |         3 | 4 |         5 | 6 | 7 |

8 | 9 | # New Maintainer 10 | This package now maintined by [Ahmed Nagi](https://twitter.com/nagiworks) 11 | 12 | # Laravel-Ratings 13 | Laravel package that allows you to **rate, like & dislike or vote up & down** your models with a simple and clear way.
14 | *If you see this packge can help, Don't skimp on me with a star :)* 15 | 16 | * [Install](https://github.com/mohamednagy/Laravel-rating#install) 17 | * [Rating](https://github.com/mohamednagy/Laravel-rating#rating) 18 | * [Like & Dislike](https://github.com/mohamednagy/Laravel-rating#like--dislike) 19 | * [Voting](https://github.com/mohamednagy/Laravel-rating#voting) 20 | 21 | 22 | ## Rating 23 | include `CanRate` trait into your user model to apply rating functions 24 | ```php 25 | use Nagy\LaravelRating\Traits\Rate\CanRate; 26 | 27 | class User extends Model 28 | { 29 | use CanRate; 30 | ``` 31 | include `Rateable` trait to your model that will be rateable 32 | ```php 33 | use Nagy\LaravelRating\Traits\Rate\Rateable; 34 | 35 | class Post extends Model 36 | { 37 | use Rateable; 38 | ``` 39 | 40 | now you can rate your models as the following: 41 | ```php 42 | $user->rate($postModel, 5); 43 | ``` 44 | also you can unrate your models as the following: 45 | ```php 46 | $user->unrate($postModel); 47 | 48 | // alternatively 49 | $user->rate($postModel, -1); 50 | // or 51 | $user->rate($postModel, false); 52 | // or 53 | $user->rate($postModel, null); 54 | ``` 55 | 56 | get the average ratings of a model 57 | ```php 58 | $post->ratingsAvg(); 59 | ``` 60 | get the total count of ratings of a model 61 | ```php 62 | $post->ratingsCount(); 63 | ``` 64 | 65 | get the rated models by a user 66 | ```php 67 | $user->rated(); // returns a collection of rated models 68 | ``` 69 | 70 | ## Voting 71 | include `CanVote` trait into your user model to apply rating functionalties 72 | ```php 73 | use Nagy\LaravelRating\Traits\Vote\CanVote; 74 | 75 | class User extends Model 76 | { 77 | use CanVote; 78 | ``` 79 | include `Votable` trait to your model that will be votable 80 | ```php 81 | use Nagy\LaravelRating\Traits\Vote\Votable; 82 | 83 | class Post extends Model 84 | { 85 | use Votable; 86 | ``` 87 | now you can vote your model as the following: 88 | ```php 89 | // up vote or +1 your model 90 | $user->upVote($postModel); 91 | 92 | // down vote or -1 your model 93 | $user->downVote($postModel); 94 | ``` 95 | get total votes count 96 | ```php 97 | $postModel->votesCount(); 98 | ``` 99 | get total up votes count 100 | ```php 101 | $postModel->upVotesCount(); 102 | ``` 103 | get total down votes count 104 | ```php 105 | $postModel->downVotesCount(); 106 | ``` 107 | 108 | get the up voted models by a user 109 | ```php 110 | $user->upVoted(); // returns a collection of up voted models 111 | ``` 112 | 113 | get the down voted models by a user 114 | ```php 115 | $user->downVoted(); // returns a collection of down voted models 116 | ``` 117 | 118 | get the total voted models by a user 119 | ```php 120 | $user->voted(); // returns a collection of total voted models; 121 | ``` 122 | 123 | ## Like & Dislike 124 | include `CanLike` trait into your user model to apply like and dislike functionalties 125 | ```php 126 | use Nagy\LaravelRating\Traits\Like\CanLike; 127 | 128 | class User extends Model 129 | { 130 | use CanLike; 131 | ``` 132 | include `Likeable` trait to your model that will be likeable 133 | ```php 134 | use Nagy\LaravelRating\Traits\Like\Likeable; 135 | 136 | class Post extends Model 137 | { 138 | use Likeable; 139 | ``` 140 | now you can like your model as the following: 141 | ```php 142 | // like 143 | $user->like($postModel); 144 | 145 | // dislike 146 | $user->dislike($postModel); 147 | ``` 148 | get total likes count 149 | ```php 150 | $postModel->likesCount(); 151 | ``` 152 | get total dislikes count 153 | ```php 154 | $postModel->dislikesCount(); 155 | ``` 156 | get total likes and dislikes count 157 | ```php 158 | $postModel->likesDislikesCount(); 159 | ``` 160 | get the liked models by a user 161 | ```php 162 | $user->liked(); // return a collection of liked models; 163 | ``` 164 | get the disliked models by a user 165 | ```php 166 | $user->disliked(); // return a collection of disliked models; 167 | ``` 168 | get the total liked and disliked models by a user 169 | ```php 170 | $user->likedDisliked(); // return a collection of liked and disliked models; 171 | ``` 172 | 173 | # Install 174 | 175 | for laravel 8.* , 7.* , 6.* 176 | 177 | ```bash 178 | composer require nagy/laravel-rating 179 | ``` 180 | 181 | for laravel 5.* 182 | 183 | ```bash 184 | composer require nagy/laravel-rating:^1.2 185 | ``` 186 | 187 | in your config/app.php 188 | 189 | ```php 190 | 'providers' => [ 191 | ... 192 | Nagy\LaravelRating\LaravelRatingServiceProvider::class 193 | ], 194 | 195 | 'aliases' => [ 196 | ... 197 | "LaravelRating" => \Nagy\LaravelRating\LaravelRatingFacade::class, 198 | ] 199 | ``` 200 | 201 | > You don't need this step in laravel5.5 `package:discover` will do the job :) 202 | 203 | publish the migrations 204 | 205 | ```bash 206 | php artisan vendor:publish --tag=laravelRatings 207 | ``` 208 | 209 | run the migrations 210 | 211 | ```bash 212 | php artisan migrate 213 | ``` 214 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nagy/laravel-rating", 3 | "description": "manage rating column for elqouent models", 4 | "keywords": [ 5 | "nagy", 6 | "laravel-rating" 7 | ], 8 | "homepage": "https://github.com/nagy/laravel-rating", 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Ahmed Nagi", 13 | "email": "info@ahmednagi.com", 14 | "role": "Developer" 15 | }, 16 | { 17 | "name": "Mohamed Nagy", 18 | "email": "mohamed.n.haleem@gmail.com", 19 | "role": "Developer" 20 | } 21 | ], 22 | "require": { 23 | "php": "^8.0|^7.3", 24 | "illuminate/contracts": "^8.0|^7.0|^6.0" 25 | }, 26 | "require-dev": { 27 | "orchestra/testbench": "^6.0|^5.0|^4.0", 28 | "phpunit/phpunit": "^9.3|^8.0", 29 | "vimeo/psalm": "^4.4" 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "Nagy\\LaravelRating\\": "src", 34 | "Nagy\\LaravelRating\\Database\\Factories\\": "database/factories" 35 | } 36 | }, 37 | "autoload-dev": { 38 | "psr-4": { 39 | "Nagy\\LaravelRating\\Tests\\": "tests" 40 | } 41 | }, 42 | "scripts": { 43 | "psalm": "vendor/bin/psalm", 44 | "test": "vendor/bin/phpunit --colors=always", 45 | "test-coverage": "vendor/bin/phpunit --coverage-html coverage" 46 | }, 47 | "config": { 48 | "sort-packages": true 49 | }, 50 | "extra": { 51 | "laravel": { 52 | "providers": [ 53 | "Nagy\\LaravelRating\\LaravelRatingServiceProvider" 54 | ], 55 | "aliases": { 56 | "LaravelRatingFacade": "Nagy\\LaravelRating\\LaravelRatingFacade" 57 | } 58 | } 59 | }, 60 | "minimum-stability": "dev", 61 | "prefer-stable": true 62 | } 63 | -------------------------------------------------------------------------------- /database/migrations/add_type_column_to_ratings_table.php.stub: -------------------------------------------------------------------------------- 1 | string('type')->nullable(); 13 | }); 14 | } 15 | 16 | public function down() 17 | { 18 | Schema::dropColumns('ratings', ['type']); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /database/migrations/create_ratings_table.php.stub: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 13 | 14 | $table->morphs('model'); 15 | $table->morphs('rateable'); 16 | $table->decimal('value', 2, 1); 17 | 18 | $table->timestamps(); 19 | }); 20 | } 21 | 22 | public function down() 23 | { 24 | Schema::dropIfExists('ratings'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /media/like-dislike.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohamednagy/Laravel-rating/febd673ab87709c56231bce038f000597e8a4993/media/like-dislike.png -------------------------------------------------------------------------------- /src/LaravelRating.php: -------------------------------------------------------------------------------- 1 | isRated($user, $rateable, $type)) { 16 | return $user->{$this->resolveTypeRelation($type)}() 17 | ->where('rateable_id', $rateable->id) 18 | ->where('type', $type) 19 | ->where('rateable_type', $this->getRateableByClass($rateable)) 20 | ->update(['value' => $value]); 21 | } 22 | 23 | return $user->{$this->resolveTypeRelation($type)}()->create([ 24 | 'rateable_id' => $rateable->id, 25 | 'rateable_type' => $this->getRateableByClass($rateable), 26 | 'value' => $value, 27 | 'type' => $type, 28 | ]); 29 | } 30 | 31 | public function unRate($user, $rateable, $type) 32 | { 33 | if ($this->isRated($user, $rateable, $type)) { 34 | return $user->{$this->resolveTypeRelation($type)}() 35 | ->where('rateable_id', $rateable->id) 36 | ->where('type', $type) 37 | ->where('rateable_type', $this->getRateableByClass($rateable)) 38 | ->delete(); 39 | } 40 | 41 | return false; 42 | } 43 | 44 | public function isRated($user, $rateable, $type) 45 | { 46 | $rating = $user->{$this->resolveTypeRelation($type)}() 47 | ->where('rateable_id', $rateable->id) 48 | ->where('rateable_type', $this->getRateableByClass($rateable)) 49 | ->where('type', $type) 50 | ->first(); 51 | 52 | return $rating != null; 53 | } 54 | 55 | public function getRatingValue($user, $rateable, $type) 56 | { 57 | $rating = $user->{$this->resolveTypeRelation($type)}() 58 | ->where('rateable_id', $rateable->id) 59 | ->where('rateable_type', $this->getRateableByClass($rateable)) 60 | ->where('type', $type) 61 | ->first(); 62 | 63 | return $rating != null ? $rating->value : null; 64 | } 65 | 66 | private function resolveTypeRelation($type) 67 | { 68 | $lookup = [ 69 | static::TYPE_LIKE => 'likes', 70 | static::TYPE_RATE => 'ratings', 71 | static::TYPE_VOTE => 'votes', 72 | ]; 73 | 74 | return $lookup[$type]; 75 | } 76 | 77 | public function resolveRatedItems($items) 78 | { 79 | $collection = collect(); 80 | 81 | foreach ($items as $item) { 82 | $rateableClass = $this->getRateableByKey($item->rateable_type); 83 | $collection->push((new $rateableClass)->find($item->rateable_id)); 84 | } 85 | 86 | return $collection; 87 | } 88 | 89 | private function getRateableByClass($rateable) 90 | { 91 | $rateable = get_class($rateable); 92 | if (in_array($rateable, Relation::$morphMap)) { 93 | $rateable = array_search($rateable, Relation::$morphMap); 94 | } 95 | 96 | return $rateable; 97 | } 98 | 99 | private function getRateableByKey($rateable) 100 | { 101 | if (array_key_exists($rateable, Relation::$morphMap)) { 102 | $rateable = Relation::$morphMap[$rateable]; 103 | } 104 | 105 | return $rateable; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/LaravelRatingFacade.php: -------------------------------------------------------------------------------- 1 | publishes([ 17 | __DIR__.'/../database/migrations/create_ratings_table.php.stub' => app()->basePath().'/database/migrations/'.date('Y_m_d_His', time() + 1).'_create_ratings_table.php', 18 | 19 | __DIR__.'/../database/migrations/add_type_column_to_ratings_table.php.stub' => app()->basePath().'/database/migrations/'.date('Y_m_d_His', time() + 2).'_add_type_column_to_ratings_table.php', 20 | ], 'laravelRatings'); 21 | } 22 | 23 | /** 24 | * 25 | * @return void 26 | */ 27 | public function register() 28 | { 29 | $this->app->bind('laravelRating', function () { 30 | return new LaravelRating(); 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Models/Rating.php: -------------------------------------------------------------------------------- 1 | morphTo(); 16 | } 17 | 18 | public function rateable() 19 | { 20 | return $this->morphTo(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Traits/Like/CanLike.php: -------------------------------------------------------------------------------- 1 | morphMany(Rating::class, 'model')->where('type', LaravelRating::TYPE_LIKE); 14 | } 15 | 16 | public function like($model) 17 | { 18 | return LaravelRatingFacade::rate($this, $model, 1, LaravelRating::TYPE_LIKE); 19 | } 20 | 21 | public function dislike($model) 22 | { 23 | return LaravelRatingFacade::rate($this, $model, 0, LaravelRating::TYPE_LIKE); 24 | } 25 | 26 | public function isLiked($model) 27 | { 28 | return LaravelRatingFacade::isRated($this, $model, LaravelRating::TYPE_LIKE); 29 | } 30 | 31 | public function liked() 32 | { 33 | $liked = $this->likes()->where('value', 1)->get(); 34 | 35 | return LaravelRatingFacade::resolveRatedItems($liked); 36 | } 37 | 38 | public function disliked() 39 | { 40 | $disliked = $this->likes()->where('value', 0)->get(); 41 | 42 | return LaravelRatingFacade::resolveRatedItems($disliked); 43 | } 44 | 45 | public function likedDisliked() 46 | { 47 | return LaravelRatingFacade::resolveRatedItems($this->likes); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Traits/Like/Likeable.php: -------------------------------------------------------------------------------- 1 | morphMany(Rating::class, 'rateable'); 12 | } 13 | 14 | public function likesDislikesCount() 15 | { 16 | return $this->likes()->count(); 17 | } 18 | 19 | public function likesCount() 20 | { 21 | return $this->likes()->where('value', 1)->count(); 22 | } 23 | 24 | public function dislikesCount() 25 | { 26 | return $this->likes()->where('value', 0)->count(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Traits/Rate/CanRate.php: -------------------------------------------------------------------------------- 1 | morphMany(Rating::class, 'model')->where('type', LaravelRating::TYPE_RATE); 14 | } 15 | 16 | public function rate($model, $value) 17 | { 18 | if ($value === null || $value === false || $value === -1) { 19 | return $this->unRate($model); 20 | } 21 | 22 | return LaravelRatingFacade::rate($this, $model, $value, LaravelRating::TYPE_RATE); 23 | } 24 | 25 | public function unRate($model) 26 | { 27 | return LaravelRatingFacade::unRate($this, $model, LaravelRating::TYPE_RATE); 28 | } 29 | 30 | public function getRatingValue($model) 31 | { 32 | return LaravelRatingFacade::getRatingValue($this, $model, LaravelRating::TYPE_RATE); 33 | } 34 | 35 | public function isRated($model) 36 | { 37 | return LaravelRatingFacade::isRated($this, $model, LaravelRating::TYPE_RATE); 38 | } 39 | 40 | public function rated() 41 | { 42 | return LaravelRatingFacade::resolveRatedItems($this->ratings); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Traits/Rate/Rateable.php: -------------------------------------------------------------------------------- 1 | morphMany(Rating::class, 'rateable'); 12 | } 13 | 14 | public function ratingsAvg() 15 | { 16 | return $this->ratings()->avg('value'); 17 | } 18 | 19 | public function ratingsCount() 20 | { 21 | return $this->ratings()->count(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Traits/Vote/CanVote.php: -------------------------------------------------------------------------------- 1 | morphMany(Rating::class, 'model')->where('type', LaravelRating::TYPE_VOTE); 14 | } 15 | 16 | public function upVote($model) 17 | { 18 | return LaravelRatingFacade::rate($this, $model, 1, LaravelRating::TYPE_VOTE); 19 | } 20 | 21 | public function downVote($model) 22 | { 23 | return LaravelRatingFacade::rate($this, $model, 0, LaravelRating::TYPE_VOTE); 24 | } 25 | 26 | public function isVoted($model) 27 | { 28 | return LaravelRatingFacade::isRated($this, $model, LaravelRating::TYPE_VOTE); 29 | } 30 | 31 | public function getVotingValue($model) 32 | { 33 | return LaravelRatingFacade::getRatingValue($this, $model, LaravelRating::TYPE_VOTE); 34 | } 35 | 36 | public function upVoted() 37 | { 38 | $upVoted = $this->votes()->where('value', 1)->get(); 39 | 40 | return LaravelRatingFacade::resolveRatedItems($upVoted); 41 | } 42 | 43 | public function downVoted() 44 | { 45 | $downVoted = $this->votes()->where('value', 0)->get(); 46 | 47 | return LaravelRatingFacade::resolveRatedItems($downVoted); 48 | } 49 | 50 | public function voted() 51 | { 52 | return LaravelRatingFacade::resolveRatedItems($this->votes); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Traits/Vote/Votable.php: -------------------------------------------------------------------------------- 1 | morphMany(Rating::class, 'rateable'); 12 | } 13 | 14 | public function totalVotesCount() 15 | { 16 | return $this->votes()->count(); 17 | } 18 | 19 | public function upVotesCount() 20 | { 21 | return $this->votes()->where('value', 1)->count(); 22 | } 23 | 24 | public function downVotesCount() 25 | { 26 | return $this->votes()->where('value', 0)->count(); 27 | } 28 | 29 | public function votesDiff() 30 | { 31 | return $this->upVotesCount() - $this->downVotesCount(); 32 | } 33 | } 34 | --------------------------------------------------------------------------------