├── .editorconfig ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── composer.json ├── database └── migrations │ ├── create_rate_types_table.php.stub │ ├── create_ratings_table.php.stub │ └── create_reviews_table.php.stub ├── database_structure.png ├── db.rd.xml ├── phpunit.xml ├── src ├── Contracts │ └── R8.php ├── Models │ ├── RateType.php │ ├── Rating.php │ └── Review.php ├── R8ServiceProvider.php └── Traits │ └── R8Trait.php └── tests └── TestCase.php /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_style = space 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | .idea/ 3 | composer.lock 4 | .php_cs.cache 5 | build/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [1.0.0] - 2020-05-30 11 | 12 | First Major Release 13 | 14 | ### Fixed 15 | 16 | - Bad Indentations and Formatting 17 | - Database Nullable Fields Errors for `ratings.type_id`, `ratings.review_id` and `reviews.User_id`. 18 | 19 | ## [0.1.1-beta] - 2020-05-30 20 | 21 | - Initial Beta Release. 22 | 23 | ### Added 24 | 25 | - Laravel 7 Support 26 | - Updated Database Structure 27 | - Rating Types 28 | - Documentation 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Shashwat Mishra 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # R8: Reviews, Ratings and Recommendations 2 | 3 | [![Latest Stable Version](https://poser.pugx.org/secrethash/r8/v)](//packagist.org/packages/secrethash/r8) [![Total Downloads](https://poser.pugx.org/secrethash/r8/downloads)](//packagist.org/packages/secrethash/r8) [![Dependents](https://poser.pugx.org/secrethash/r8/dependents)](//packagist.org/packages/secrethash/r8) [![Latest Unstable Version](https://poser.pugx.org/secrethash/r8/v/unstable)](//packagist.org/packages/secrethash/r8) [![License](https://poser.pugx.org/secrethash/r8/license)](./LICENSE) 4 | 5 | Laravel has always been missing a package like this, that supports dynamic rating with multiple Rating Types (ex. Like in Amazon or any e-commerce platform, Quality Rating, Customer Service Experience Ratings, etc.) with Integrated Reviews and Recommend Functionality. 6 | 7 | The main Ideology behind this package is to make it easily adaptable for everyone's use case. 8 | 9 | Reviews & Ratings system for Laravel 7. You can rate any of your models. 10 | 11 | - Custom Rating Types (ex: Product Quality, Delivery Speed, Pricing, etc.) without any limitations. 12 | - Display Overall and Average Ratings 13 | - Method Chaining 14 | - You can set whether the model being rated is recommended. 15 | 16 | # Installation 17 | 18 | First, pull in the package through Composer. 19 | 20 | ``` 21 | composer require secrethash/r8 22 | ``` 23 | 24 | **NOTE: The `dev-master` is _UNDER HEAVY DEVELOPMENT_** 25 | 26 | You will need to publish and run the migrations. 27 | 28 | ``` 29 | php artisan vendor:publish --provider="Secrethash\R8\R8ServiceProvider" --tag="migrations" 30 | ``` 31 | 32 | Run the migrations 33 | 34 | ``` 35 | php artisan migrate 36 | ``` 37 | 38 | --- 39 | 40 | ## Setup 41 | 42 | Setup the model that will be reviewed, rated & recommended. 43 | 44 | ```php 45 | with('post', $post); 86 | } 87 | 88 | ``` 89 | 90 | ### Reviews & Recommend 91 | 92 | `resources/views/post/show.blade.php` 93 | 94 | ```php 95 | @foreach($post->reviews as $review) 96 | 97 |

{{ $review->title }}

98 |

{{ $review->body }}

99 | Recommended: {{ $review->recommend }} 100 | By: {{ $review->author->name }} 101 | 102 | @endforeach 103 | ``` 104 | 105 | ### Ratings 106 | 107 | **NOTE:** A Review must be created first to Create and link One or Many ratings with it. 108 | 109 | `resources/views/post/show.blade.php` 110 | 111 | ```php 112 | @foreach($post->reviews as $review) 113 | 114 |

{{ $review->title }}

115 |

{{ $review->body }}

116 | Recommended: {{ $review->recommend }} 117 | By: {{ $review->author->name }} 118 | 119 | @foreach ($review->ratings as $rating) 120 | {{ $rating->type->name }} 121 | {{ $rating->value }} 122 | @endforeach 123 | 124 | @endforeach 125 | ``` 126 | 127 | ## Create 128 | 129 | ### Reviews 130 | 131 | `App\Http\Controllers\ReviewController.php` 132 | 133 | ```php 134 | reviews()->create([ 155 | 'title' => 'One More Bad Sample Review', 156 | 'body' => 'This is a another new sample review. This one has 4 Type Reviews.', 157 | 'recommend' => 'No', 158 | ]); 159 | 160 | // Associate Author User ID 161 | $review->author()->associate(auth()->user()->id); 162 | 163 | } 164 | } 165 | ``` 166 | 167 | ### Rating 168 | 169 | > **Assumption:** A Rating Type has already been created with `'slug' => 'customer-service'`. 170 | 171 | `App\Http\Controllers\ReviewController.php` 172 | 173 | ```php 174 | first(); 196 | 197 | // Create Review 198 | $review = $post->reviews()->create([ 199 | 'title' => 'One More Bad Sample Review', 200 | 'body' => 'This is a another new sample review. This one has 4 Type Reviews.', 201 | 'recommend' => 'Yes', // Enum: accepts 'Yes' or 'No' 202 | ]); 203 | 204 | // Associate Author User ID 205 | $review->author()->associate(auth()->user()->id); 206 | 207 | // Creating Rating 208 | $rating = $review->ratings()->create([ 209 | 'value' => 5 210 | ]); 211 | 212 | // Associate Rating Type ID 213 | $rating->type()->associate($type->id); 214 | 215 | // Saving Everything 216 | $review->save(); 217 | $rating->save(); 218 | 219 | } 220 | } 221 | ``` 222 | 223 | ## RateTypes 224 | 225 | Similarly, `Secrethash\R8\Models\RateType` can be used to create Rating Types like _Product Quality_, _Customer Service_, _Delivery_, etc. 226 | 227 | | Fillable | Description | 228 | | -------- | ------------- | 229 | | slug | Sluggish Name | 230 | | name | Full Name | 231 | 232 | ## Other Operations 233 | 234 | To keep things simple, Operations like Counting Reviews and Ratings are done through well defined relations, the Laravel Way. 235 | 236 | ### Counting 237 | 238 | #### Reviews 239 | 240 | ```php 241 | reviews->count(); 254 | 255 | $approved = $post->reviews 256 | ->where('approved', 1) 257 | ->count(); 258 | 259 | return view('post.show')->with(['post' => $post, 'reviews' => $reviews, 'approved' => $approved]); 260 | } 261 | } 262 | ``` 263 | 264 | #### Ratings 265 | 266 | Assuming the counting will be performed directly in the `blade.php` file. 267 | 268 | `resources/views/post/show.blade.php` 269 | 270 | ```php 271 | @foreach($post->reviews as $review) 272 | ... 273 | Total Ratings: {{ $review->ratings->count() }} 274 | ... 275 | @endforeach 276 | ``` 277 | 278 | ### Average 279 | 280 | #### Ratings 281 | 282 | Laravel manages collections in a smart way. And as we know that "All multi-result sets returned by Eloquent are instances of the `Illuminate\Database\Eloquent\Collection` object" [Laravel Docs][1] 283 | All you need to do is pass in the name of the table (here `value`) in the `average()` collection helper method. 284 | 285 | `resources/views/post/show.blade.php` 286 | 287 | ```php 288 | @foreach($post->reviews as $review) 289 | ... 290 | Average Ratings: {{ $review->ratings->average('value') }} 291 | ... 292 | @endforeach 293 | ``` 294 | 295 | ## Contributions 296 | 297 | Contributions are welcomed and appreciated. Feel free to create a Pull Request or an Issue. 298 | 299 | ### Database Structure 300 | 301 | As this package is still under development, the database structure might change in future. The structure ER Diagram is provided as [XML File](./db.rd.xml) and also as an Image File. 302 | ![Database Entity Relation Diagram](./database_structure.png) 303 | 304 | ## License 305 | 306 | This project is Licensed under MIT. See the [License File](./LICENSE) for more information. 307 | 308 | ### Note 309 | 310 | > This repository has been forked from [codebyray/laravel-review-rateable](https://github.com/codebyray/laravel-review-rateable.git) 311 | 312 | It was forked initially as a head-start and a lot has been changed since then. The whole concept and methodology has been changed. 313 | 314 | Please note that the original code does not matches the code from this repository as a lot has been changed. 315 | 316 | [1]: https://laravel.com/docs/7.x/eloquent-collections "Laravel Docs for Eloquent Collections" 317 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "secrethash/r8", 3 | "type": "package", 4 | "description": "Review & Rating system for Laravel", 5 | "keywords": [ 6 | "rating", 7 | "Ratable", 8 | "laravel", 9 | "Review-Rateable", 10 | "reviewable" 11 | ], 12 | "homepage": "https://github.com/secrethash/r8", 13 | "license": "MIT", 14 | "authors": [ 15 | { 16 | "name": "Shashwat Mishra", 17 | "email": "secrethash96@gmail.com" 18 | } 19 | ], 20 | "minimum-stability": "dev", 21 | "require": { 22 | "php" : "^7.2", 23 | "illuminate/auth": "^5.8|^6.0|^7.0", 24 | "illuminate/container": "^5.8|^6.0|^7.0", 25 | "illuminate/contracts": "^5.8|^6.0|^7.0", 26 | "illuminate/database": "~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0", 27 | "illuminate/support": "~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0", 28 | "nesbot/carbon": "^2.17" 29 | }, 30 | "require-dev": { 31 | "phpunit/phpunit": "^6.3|^7.0|^8.0", 32 | "orchestra/testbench": "~3.5.0|~3.6.0|^4.0" 33 | }, 34 | "autoload": { 35 | "psr-4": { 36 | "Secrethash\\R8\\": "src" 37 | } 38 | }, 39 | "autoload-dev": { 40 | "psr-4": { 41 | "Secrethash\\R8\\Test\\": "tests" 42 | } 43 | }, 44 | "extra": { 45 | "laravel": { 46 | "providers": [ 47 | "Secrethash\\R8\\R8ServiceProvider" 48 | ] 49 | } 50 | }, 51 | "scripts": { 52 | "test": "vendor/bin/phpunit", 53 | "test:windows": "vendor\\bin\\phpunit" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /database/migrations/create_rate_types_table.php.stub: -------------------------------------------------------------------------------- 1 | id(); 12 | $table->string('slug'); 13 | $table->string('name'); 14 | $table->timestamps(); 15 | }); 16 | } 17 | 18 | public function down() 19 | { 20 | Schema::dropIfExists('rate_types'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /database/migrations/create_ratings_table.php.stub: -------------------------------------------------------------------------------- 1 | id(); 12 | $table->foreignId('review_id')->nullable()->constrained(); 13 | $table->unsignedBigInteger('type_id')->nullable(); 14 | $table->float('value'); 15 | $table->timestamps(); 16 | 17 | $table->foreign('type_id')->references('id')->on('rate_types'); 18 | }); 19 | } 20 | 21 | public function down() 22 | { 23 | Schema::dropIfExists('ratings'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /database/migrations/create_reviews_table.php.stub: -------------------------------------------------------------------------------- 1 | id(); 12 | $table->string('title')->nullable(); 13 | $table->string('body')->nullable(); 14 | $table->enum('recommend', ['Yes', 'No'])->nullable(); 15 | $table->boolean('approved')->default(0); 16 | $table->foreignId('user_id')->nullable()->constrained(); 17 | $table->morphs('reviewable'); 18 | $table->timestamps(); 19 | }); 20 | } 21 | 22 | public function down() 23 | { 24 | Schema::dropIfExists('reviews'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /database_structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secrethash/r8/234479341c70a79e8d78422512c8fa3d539a37bd/database_structure.png -------------------------------------------------------------------------------- /db.rd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | INTEGER 48 | NULL 49 | 50 | VARCHAR 51 | NULL 52 | 53 | MEDIUMTEXT 54 | NULL 55 | 56 | ENUM 57 | NULL 58 | 59 | INT 60 | NULL 61 | 62 | INTEGER 63 | NULL 64 | 65 | 66 | INTEGER 67 | NULL 68 | 69 | VARCHAR 70 | NULL 71 | 72 | id 73 | 74 |
75 | 76 | 77 | INTEGER 78 | NULL 79 | 80 | INTEGER 81 | NULL 82 | 83 | 84 | INTEGER 85 | NULL 86 | 87 | 88 | DECIMAL 89 | NULL 90 | 91 | id 92 | 93 |
94 | 95 | 96 | INTEGER 97 | NULL 98 | 99 | VARCHAR 100 | NULL 101 | 102 | VARCHAR 103 | NULL 104 | 105 | id 106 | 107 |
108 | 109 | 110 | INTEGER 111 | NULL 112 | 113 | VARCHAR 114 | NULL 115 | 116 | INTEGER 117 | NULL 118 | 119 | INTEGER 120 | NULL 121 | 122 | INTEGER 123 | NULL 124 | 125 | INTEGER 126 | NULL 127 | 128 | id 129 | 130 |
131 |
132 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | 18 | 19 | 20 | ./src/ 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Contracts/R8.php: -------------------------------------------------------------------------------- 1 | hasMany(Rating::class, 'rating_rate_type')->withPivot('value'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Models/Rating.php: -------------------------------------------------------------------------------- 1 | belongsTo(Review::class); 27 | } 28 | 29 | /** 30 | * Rate Types Relationship 31 | * 32 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 33 | */ 34 | 35 | public function type() 36 | { 37 | return $this->belongsTo(RateType::class); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Models/Review.php: -------------------------------------------------------------------------------- 1 | morphTo(); 27 | } 28 | 29 | /** 30 | * Ratings Relationship 31 | * 32 | * @return \Illuminate\Database\Eloquent\Relations\HasMany 33 | */ 34 | public function ratings() 35 | { 36 | return $this->hasMany(Rating::class); 37 | } 38 | 39 | /** 40 | * @return \Illuminate\Database\Eloquent\Relations\MorphTo 41 | */ 42 | public function author() 43 | { 44 | return $this->belongsTo(User::class, 'user_id'); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/R8ServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 18 | __DIR__ . '/../database/migrations/create_reviews_table.php.stub' => $this->app->databasePath() . "/migrations/{$this->timestamp(10)}_create_reviews_table.php", 19 | __DIR__ . '/../database/migrations/create_rate_types_table.php.stub' => $this->app->databasePath() . "/migrations/{$this->timestamp(20)}_create_rate_types_table.php", 20 | __DIR__ . '/../database/migrations/create_ratings_table.php.stub' => $this->app->databasePath() . "/migrations/{$this->timestamp(30)}_create_ratings_table.php", 21 | ], 'migrations'); 22 | } 23 | 24 | /** 25 | * Register any application services. 26 | * 27 | * @return void 28 | */ 29 | public function register() 30 | { 31 | } 32 | 33 | /** 34 | * Create Timestamps 35 | * 36 | * @return Carbon\Carbon 37 | */ 38 | protected function timestamp($seconds) 39 | { 40 | $timestamp = Carbon::now()->addSeconds($seconds) 41 | ->format('Y_m_d_His'); 42 | return $timestamp; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Traits/R8Trait.php: -------------------------------------------------------------------------------- 1 | morphMany(Review::class, 'reviewable'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | set('database.default', 'testing'); 40 | $app['config']->set('database.connections.testing', [ 41 | 'driver' => 'sqlite', 42 | 'database' => ':memory:', 43 | 'prefix' => '', 44 | ]); 45 | } 46 | } --------------------------------------------------------------------------------