[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nindent_size = 4\nindent_style = space\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.md]\ntrim_trailing_whitespace = false\n\n[*.{yml,yaml}]\nindent_size = 2\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Path-based git attributes\n# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html\n\n# Ignore all test and documentation with \"export-ignore\".\n/.github            export-ignore\n/.gitattributes     export-ignore\n/.gitignore         export-ignore\n/phpunit.xml.dist   export-ignore\n/tests              export-ignore\n/.editorconfig      export-ignore\n/.php_cs.dist       export-ignore\n/psalm.xml          export-ignore\n/psalm.xml.dist     export-ignore\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contributing\n\nContributions are **welcome** and will be fully **credited**.\n\nPlease read and understand the contribution guide before creating an issue or pull request.\n\n## Etiquette\n\nThis project is open source, and as such, the maintainers give their free time to build and maintain the source code\nheld within. They make the code freely available in the hope that it will be of use to other developers. It would be\nextremely unfair for them to suffer abuse or anger for their hard work.\n\nPlease be considerate towards maintainers when raising issues or presenting pull requests. Let's show the\nworld that developers are civilized and selfless people.\n\nIt's the duty of the maintainer to ensure that all submissions to the project are of sufficient\nquality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used.\n\n## Viability\n\nWhen requesting or submitting new features, first consider whether it might be useful to others. Open\nsource projects are used by many developers, who may have entirely different needs to your own. Think about\nwhether or not your feature is likely to be used by other users of the project.\n\n## Procedure\n\nBefore filing an issue:\n\n- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident.\n- Check to make sure your feature suggestion isn't already present within the project.\n- Check the pull requests tab to ensure that the bug doesn't have a fix in progress.\n- Check the pull requests tab to ensure that the feature isn't already in progress.\n\nBefore submitting a pull request:\n\n- Check the codebase to ensure that your feature doesn't already exist.\n- Check the pull requests to ensure that another person hasn't already submitted the feature or fix.\n\n## Requirements\n\nIf the project maintainer has any additional requirements, you will find them listed here.\n\n- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer).\n\n- **Add tests!** - Your patch won't be accepted if it doesn't have tests.\n\n- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.\n\n- **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option.\n\n- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.\n\n- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting.\n\n**Happy coding**!\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: nagy\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Report a bug\n    url: https://github.com/mohamednagy/laravel-rating/issues/new\n    about: Report a reproducable bug\n"
  },
  {
    "path": ".github/SECURITY.md",
    "content": "# Security Policy\n\nIf you discover any security related issues, please email mohamed.n.haleem@gmail.com instead of using the issue tracker.\n"
  },
  {
    "path": ".github/workflows/php-cs-fixer.yml",
    "content": "name: Check & fix styling\n\non: [push]\n\njobs:\n  php-cs-fixer:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v2\n        with:\n          ref: ${{ github.head_ref }}\n\n      - name: Run PHP CS Fixer\n        uses: docker://oskarstark/php-cs-fixer-ga\n        with:\n          args: --config=.php_cs.dist --allow-risky=yes\n\n      - name: Commit changes\n        uses: stefanzweifel/git-auto-commit-action@v4\n        with:\n          commit_message: Fix styling\n"
  },
  {
    "path": ".github/workflows/psalm.yml",
    "content": "name: Psalm\n\non:\n  push:\n    paths:\n      - '**.php'\n      - 'psalm.xml.dist'\n\njobs:\n  psalm:\n    name: psalm\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: '7.4'\n          extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick\n          coverage: none\n\n      - name: Cache composer dependencies\n        uses: actions/cache@v2\n        with:\n          path: vendor\n          key: composer-${{ hashFiles('composer.lock') }}\n\n      - name: Run composer install\n        run: composer install -n --prefer-dist\n\n      - name: Run psalm\n        run: ./vendor/bin/psalm --output-format=github\n"
  },
  {
    "path": ".github/workflows/run-tests.yml",
    "content": "name: run-tests\n\non: [push, pull_request]\n\njobs:\n  test:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: true\n      matrix:\n        os: [ubuntu-latest, windows-latest]\n        php: [8.0, 7.4, 7.3]\n        laravel: [\"^8.0\", \"^7.0\", \"^6.0\"]\n        stability: [prefer-stable]\n        include:\n          - laravel: ^8.0\n            os: ubuntu-latest\n            testbench: ^6.0\n\n          - laravel: ^7.0\n            os: ubuntu-latest\n            testbench: ^5.0\n\n          - laravel: ^6.0\n            os: ubuntu-latest\n            testbench: ^4.0\n\n    name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v2\n\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: ${{ matrix.php }}\n          extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo\n          coverage: none\n\n      - name: Setup problem matchers\n        run: |\n          echo \"::add-matcher::${{ runner.tool_cache }}/php.json\"\n          echo \"::add-matcher::${{ runner.tool_cache }}/phpunit.json\"\n\n      - name: Install dependencies\n        run: |\n          composer require \"laravel/framework:${{ matrix.laravel }}\" \"orchestra/testbench:${{ matrix.testbench }}\" --no-interaction --no-update\n          composer update --${{ matrix.stability }} --prefer-dist --no-interaction\n\n      - name: Execute tests\n        run: vendor/bin/phpunit\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea\n.php_cs\n.php_cs.cache\n.phpunit.result.cache\nbuild\ncomposer.lock\ncoverage\ndocs\nphpunit.xml\npsalm.xml\nvendor\n"
  },
  {
    "path": ".php_cs.dist",
    "content": "<?php\n\n$finder = Symfony\\Component\\Finder\\Finder::create()\n    ->notPath('bootstrap/*')\n    ->notPath('storage/*')\n    ->notPath('resources/view/mail/*')\n    ->in([\n        __DIR__ . '/src',\n        __DIR__ . '/tests',\n    ])\n    ->name('*.php')\n    ->notName('*.blade.php')\n    ->ignoreDotFiles(true)\n    ->ignoreVCS(true);\n\nreturn PhpCsFixer\\Config::create()\n    ->setRules([\n        '@PSR2' => true,\n        'array_syntax' => ['syntax' => 'short'],\n        'ordered_imports' => ['sortAlgorithm' => 'alpha'],\n        'no_unused_imports' => true,\n        'not_operator_with_successor_space' => true,\n        'trailing_comma_in_multiline_array' => true,\n        'phpdoc_scalar' => true,\n        'unary_operator_spaces' => true,\n        'binary_operator_spaces' => true,\n        'blank_line_before_statement' => [\n            'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'],\n        ],\n        'phpdoc_single_line_var_spacing' => true,\n        'phpdoc_var_without_name' => true,\n        'class_attributes_separation' => [\n            'elements' => [\n                'method',\n            ],\n        ],\n        'method_argument_space' => [\n            'on_multiline' => 'ensure_fully_multiline',\n            'keep_multiple_spaces_after_comma' => true,\n        ],\n        'single_trait_insert_per_statement' => true,\n    ])\n    ->setFinder($finder);\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to `laravel-rating` will be documented in this file.\n\n## 1.0.0 - 202X-XX-XX\n\n- initial release\n"
  },
  {
    "path": "LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) nagy <mohamed.n.haleem@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n    <img src=\"https://image.ibb.co/eGKPgw/if_019_Star_2792947.png\" width=32> &nbsp; &nbsp; &nbsp; &nbsp;\n    <img src=\"./media/like-dislike.png\" width=60>\n    &nbsp; &nbsp; &nbsp; &nbsp;\n    <img src=\"https://image.ibb.co/hgco8b/if_chevron_up_173180.png\" width=32>\n    <img src=\"https://image.ibb.co/bANzEG/if_chevron_down_173177.png\" width=32>\n</p>\n\n# New Maintainer\nThis package now maintined by [Ahmed Nagi](https://twitter.com/nagiworks)\n\n# Laravel-Ratings\nLaravel package that allows you to **rate,  like & dislike or vote up & down** your models with a simple and clear way. <br>\n*If you see this packge can help, Don't skimp on me with a star :)*\n\n* [Install](https://github.com/mohamednagy/Laravel-rating#install)\n* <img src=\"https://image.ibb.co/eGKPgw/if_019_Star_2792947.png\" width=20> [Rating](https://github.com/mohamednagy/Laravel-rating#rating)\n* <img src=\"./media/like-dislike.png\" width=25> [Like & Dislike](https://github.com/mohamednagy/Laravel-rating#like--dislike)\n* <img src=\"https://image.ibb.co/hgco8b/if_chevron_up_173180.png\" width=20> [Voting](https://github.com/mohamednagy/Laravel-rating#voting)\n\n\n## Rating\ninclude `CanRate` trait into your user model to apply rating functions\n```php\nuse Nagy\\LaravelRating\\Traits\\Rate\\CanRate;\n\nclass User extends Model\n{\n    use CanRate;\n```\ninclude `Rateable` trait to your model that will be rateable\n```php\nuse Nagy\\LaravelRating\\Traits\\Rate\\Rateable;\n\nclass Post extends Model\n{\n    use Rateable;\n```\n\nnow you can rate your models as the following:\n```php\n$user->rate($postModel, 5);\n```\nalso you can unrate your models as the following:\n```php\n$user->unrate($postModel);\n\n// alternatively\n$user->rate($postModel, -1);\n// or\n$user->rate($postModel, false);\n// or\n$user->rate($postModel, null);\n```\n\nget the average ratings of a model\n```php\n$post->ratingsAvg();\n```\nget the total count of ratings of a model\n```php\n$post->ratingsCount();\n```\n\nget the rated models by a user\n```php\n$user->rated(); // returns a collection of rated models\n```\n\n## Voting\ninclude `CanVote` trait into your user model to apply rating functionalties\n```php\nuse Nagy\\LaravelRating\\Traits\\Vote\\CanVote;\n\nclass User extends Model\n{\n    use CanVote;\n```\ninclude `Votable` trait to your model that will be votable\n```php\nuse Nagy\\LaravelRating\\Traits\\Vote\\Votable;\n\nclass Post extends Model\n{\n    use Votable;\n```\nnow you can vote your model as the following:\n```php\n// up vote or +1  your model\n$user->upVote($postModel);\n\n// down vote or -1 your model\n$user->downVote($postModel);\n```\nget total votes count\n```php\n$postModel->votesCount();\n```\nget total up votes count\n```php\n$postModel->upVotesCount();\n```\nget total down votes count\n```php\n$postModel->downVotesCount();\n```\n\nget the up voted models by a user\n```php\n$user->upVoted(); // returns a collection of up voted models\n```\n\nget the down voted models by a user\n```php\n$user->downVoted(); // returns a collection of down voted models\n```\n\nget the total voted models by a user\n```php\n$user->voted(); // returns a collection of total voted models;\n```\n\n## Like & Dislike\ninclude `CanLike` trait into your user model to apply like and dislike functionalties\n```php\nuse Nagy\\LaravelRating\\Traits\\Like\\CanLike;\n\nclass User extends Model\n{\n    use CanLike;\n```\ninclude `Likeable` trait to your model that will be likeable\n```php\nuse Nagy\\LaravelRating\\Traits\\Like\\Likeable;\n\nclass Post extends Model\n{\n    use Likeable;\n```\nnow you can like your model as the following:\n```php\n// like\n$user->like($postModel);\n\n// dislike\n$user->dislike($postModel);\n```\nget total likes count\n```php\n$postModel->likesCount();\n```\nget total dislikes count\n```php\n$postModel->dislikesCount();\n```\nget total likes and dislikes count\n```php\n$postModel->likesDislikesCount();\n```\nget the liked models by a user\n```php\n$user->liked(); // return a collection of liked models;\n```\nget the disliked models by a user\n```php\n$user->disliked(); // return a collection of disliked models;\n```\nget the total liked and disliked models by a user\n```php\n$user->likedDisliked(); // return a collection of liked and disliked models;\n```\n\n# Install\n\nfor laravel 8.* , 7.* , 6.*\n\n```bash\ncomposer require nagy/laravel-rating\n```\n\nfor laravel 5.*\n\n```bash\ncomposer require nagy/laravel-rating:^1.2\n```\n\nin your config/app.php\n\n```php\n    'providers' => [\n        ...\n        Nagy\\LaravelRating\\LaravelRatingServiceProvider::class\n    ],\n\n    'aliases' => [\n        ...\n        \"LaravelRating\" => \\Nagy\\LaravelRating\\LaravelRatingFacade::class,\n    ]\n```\n\n> You don't need this step in laravel5.5 `package:discover`  will do the job :)\n\npublish the migrations\n\n```bash\nphp artisan vendor:publish --tag=laravelRatings\n```\n\nrun the migrations\n\n```bash\nphp artisan migrate\n```\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"nagy/laravel-rating\",\n    \"description\": \"manage rating column for elqouent models\",\n    \"keywords\": [\n        \"nagy\",\n        \"laravel-rating\"\n    ],\n    \"homepage\": \"https://github.com/nagy/laravel-rating\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Ahmed Nagi\",\n            \"email\": \"info@ahmednagi.com\",\n            \"role\": \"Developer\"\n        },\n        {\n            \"name\": \"Mohamed Nagy\",\n            \"email\": \"mohamed.n.haleem@gmail.com\",\n            \"role\": \"Developer\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^8.0|^7.3\",\n        \"illuminate/contracts\": \"^8.0|^7.0|^6.0\"\n    },\n    \"require-dev\": {\n        \"orchestra/testbench\": \"^6.0|^5.0|^4.0\",\n        \"phpunit/phpunit\": \"^9.3|^8.0\",\n        \"vimeo/psalm\": \"^4.4\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Nagy\\\\LaravelRating\\\\\": \"src\",\n            \"Nagy\\\\LaravelRating\\\\Database\\\\Factories\\\\\": \"database/factories\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Nagy\\\\LaravelRating\\\\Tests\\\\\": \"tests\"\n        }\n    },\n    \"scripts\": {\n        \"psalm\": \"vendor/bin/psalm\",\n        \"test\": \"vendor/bin/phpunit --colors=always\",\n        \"test-coverage\": \"vendor/bin/phpunit --coverage-html coverage\"\n    },\n    \"config\": {\n        \"sort-packages\": true\n    },\n    \"extra\": {\n        \"laravel\": {\n            \"providers\": [\n                \"Nagy\\\\LaravelRating\\\\LaravelRatingServiceProvider\"\n            ],\n            \"aliases\": {\n                \"LaravelRatingFacade\": \"Nagy\\\\LaravelRating\\\\LaravelRatingFacade\"\n            }\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true\n}\n"
  },
  {
    "path": "database/migrations/add_type_column_to_ratings_table.php.stub",
    "content": "<?php\n\nuse Illuminate\\Support\\Facades\\Schema;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Database\\Migrations\\Migration;\n\nclass AddTypeColumnToRatingsTable extends Migration\n{\n    public function up()\n    {\n        Schema::table('ratings', function (Blueprint $table) {\n            $table->string('type')->nullable();\n        });\n    }\n\n    public function down()\n    {\n        Schema::dropColumns('ratings', ['type']);\n    }\n}\n"
  },
  {
    "path": "database/migrations/create_ratings_table.php.stub",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass CreateRatingsTable extends Migration\n{\n    public function up()\n    {\n        Schema::create('ratings', function (Blueprint $table) {\n            $table->bigIncrements('id');\n\n            $table->morphs('model');\n            $table->morphs('rateable');\n            $table->decimal('value', 2, 1);\n\n            $table->timestamps();\n        });\n    }\n\n    public function down()\n    {\n        Schema::dropIfExists('ratings');\n    }\n}\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit backupGlobals=\"false\"\n         backupStaticAttributes=\"false\"\n         bootstrap=\"vendor/autoload.php\"\n         colors=\"true\"\n         convertErrorsToExceptions=\"true\"\n         convertNoticesToExceptions=\"true\"\n         convertWarningsToExceptions=\"true\"\n         processIsolation=\"false\"\n         stopOnFailure=\"false\"\n         verbose=\"true\"\n>\n    <testsuites>\n        <testsuite name=\"Nagy Test Suite\">\n            <directory>tests</directory>\n        </testsuite>\n    </testsuites>\n    <coverage>\n        <include>\n            <directory suffix=\".php\">./src</directory>\n        </include>\n        <report>\n            <html outputDirectory=\"build/coverage\"/>\n            <text outputFile=\"build/coverage.txt\"/>\n            <clover outputFile=\"build/logs/clover.xml\"/>\n        </report>\n    </coverage>\n    <logging>\n        <junit outputFile=\"build/report.junit.xml\"/>\n    </logging>\n</phpunit>\n"
  },
  {
    "path": "psalm.xml.dist",
    "content": "<?xml version=\"1.0\"?>\n<psalm\n    errorLevel=\"4\"\n    findUnusedVariablesAndParams=\"true\"\n    resolveFromConfigFile=\"true\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xmlns=\"https://getpsalm.org/schema/config\"\n    xsi:schemaLocation=\"https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd\"\n>\n    <projectFiles>\n        <directory name=\"src\"/>\n        <ignoreFiles>\n            <directory name=\"vendor\"/>\n        </ignoreFiles>\n    </projectFiles>\n</psalm>\n"
  },
  {
    "path": "src/LaravelRating.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRating;\n\nuse Illuminate\\Database\\Eloquent\\Relations\\Relation;\n\nclass LaravelRating\n{\n    const TYPE_LIKE = 'like';\n    const TYPE_RATE = 'rate';\n    const TYPE_VOTE = 'vote';\n\n    public function rate($user, $rateable, $value, $type)\n    {\n        if ($this->isRated($user, $rateable, $type)) {\n            return $user->{$this->resolveTypeRelation($type)}()\n                        ->where('rateable_id', $rateable->id)\n                        ->where('type', $type)\n                        ->where('rateable_type', $this->getRateableByClass($rateable))\n                        ->update(['value' => $value]);\n        }\n\n        return $user->{$this->resolveTypeRelation($type)}()->create([\n            'rateable_id' => $rateable->id,\n            'rateable_type' => $this->getRateableByClass($rateable),\n            'value' => $value,\n            'type' => $type,\n        ]);\n    }\n\n    public function unRate($user, $rateable, $type)\n    {\n        if ($this->isRated($user, $rateable, $type)) {\n            return $user->{$this->resolveTypeRelation($type)}()\n                        ->where('rateable_id', $rateable->id)\n                        ->where('type', $type)\n                        ->where('rateable_type', $this->getRateableByClass($rateable))\n                        ->delete();\n        }\n\n        return false;\n    }\n\n    public function isRated($user, $rateable, $type)\n    {\n        $rating = $user->{$this->resolveTypeRelation($type)}()\n                        ->where('rateable_id', $rateable->id)\n                        ->where('rateable_type', $this->getRateableByClass($rateable))\n                        ->where('type', $type)\n                        ->first();\n\n        return $rating != null;\n    }\n\n    public function getRatingValue($user, $rateable, $type)\n    {\n        $rating = $user->{$this->resolveTypeRelation($type)}()\n                        ->where('rateable_id', $rateable->id)\n                        ->where('rateable_type', $this->getRateableByClass($rateable))\n                        ->where('type', $type)\n                        ->first();\n\n        return $rating != null ? $rating->value : null;\n    }\n\n    private function resolveTypeRelation($type)\n    {\n        $lookup = [\n              static::TYPE_LIKE => 'likes',\n              static::TYPE_RATE => 'ratings',\n              static::TYPE_VOTE => 'votes',\n        ];\n\n        return $lookup[$type];\n    }\n\n    public function resolveRatedItems($items)\n    {\n        $collection = collect();\n\n        foreach ($items as $item) {\n            $rateableClass = $this->getRateableByKey($item->rateable_type);\n            $collection->push((new $rateableClass)->find($item->rateable_id));\n        }\n\n        return $collection;\n    }\n\n    private function getRateableByClass($rateable)\n    {\n        $rateable = get_class($rateable);\n        if (in_array($rateable, Relation::$morphMap)) {\n            $rateable = array_search($rateable, Relation::$morphMap);\n        }\n\n        return $rateable;\n    }\n\n    private function getRateableByKey($rateable)\n    {\n        if (array_key_exists($rateable, Relation::$morphMap)) {\n            $rateable = Relation::$morphMap[$rateable];\n        }\n\n        return $rateable;\n    }\n}\n"
  },
  {
    "path": "src/LaravelRatingFacade.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRating;\n\nuse Illuminate\\Support\\Facades\\Facade;\n\n/**\n * @see \\Nagy\\LaravelRating\\LaravelRating\n */\nclass LaravelRatingFacade extends Facade\n{\n    protected static function getFacadeAccessor()\n    {\n        return 'laravelRating';\n    }\n}\n"
  },
  {
    "path": "src/LaravelRatingServiceProvider.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRating;\n\nuse Illuminate\\Support\\ServiceProvider;\n\nclass LaravelRatingServiceProvider extends ServiceProvider\n{\n    /**\n     * Bootstrap the application services.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        $this->publishes([\n            __DIR__.'/../database/migrations/create_ratings_table.php.stub' => app()->basePath().'/database/migrations/'.date('Y_m_d_His', time() + 1).'_create_ratings_table.php',\n\n            __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',\n        ], 'laravelRatings');\n    }\n\n    /**\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this->app->bind('laravelRating', function () {\n            return new LaravelRating();\n        });\n    }\n}\n"
  },
  {
    "path": "src/Models/Rating.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRating\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\n\nclass Rating extends Model\n{\n    protected $guarded = [];\n\n    protected $table = 'ratings';\n\n    public function model()\n    {\n        return $this->morphTo();\n    }\n\n    public function rateable()\n    {\n        return $this->morphTo();\n    }\n}\n"
  },
  {
    "path": "src/Traits/Like/CanLike.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRating\\Traits\\Like;\n\nuse Nagy\\LaravelRating\\LaravelRating;\nuse Nagy\\LaravelRating\\LaravelRatingFacade;\nuse Nagy\\LaravelRating\\Models\\Rating;\n\ntrait CanLike\n{\n    public function likes()\n    {\n        return $this->morphMany(Rating::class, 'model')->where('type', LaravelRating::TYPE_LIKE);\n    }\n\n    public function like($model)\n    {\n        return LaravelRatingFacade::rate($this, $model, 1, LaravelRating::TYPE_LIKE);\n    }\n\n    public function dislike($model)\n    {\n        return LaravelRatingFacade::rate($this, $model, 0, LaravelRating::TYPE_LIKE);\n    }\n\n    public function isLiked($model)\n    {\n        return LaravelRatingFacade::isRated($this, $model, LaravelRating::TYPE_LIKE);\n    }\n\n    public function liked()\n    {\n        $liked = $this->likes()->where('value', 1)->get();\n\n        return LaravelRatingFacade::resolveRatedItems($liked);\n    }\n\n    public function disliked()\n    {\n        $disliked = $this->likes()->where('value', 0)->get();\n\n        return LaravelRatingFacade::resolveRatedItems($disliked);\n    }\n\n    public function likedDisliked()\n    {\n        return LaravelRatingFacade::resolveRatedItems($this->likes);\n    }\n}\n"
  },
  {
    "path": "src/Traits/Like/Likeable.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRating\\Traits\\Like;\n\nuse Nagy\\LaravelRating\\Models\\Rating;\n\ntrait Likeable\n{\n    public function likes()\n    {\n        return $this->morphMany(Rating::class, 'rateable');\n    }\n\n    public function likesDislikesCount()\n    {\n        return $this->likes()->count();\n    }\n\n    public function likesCount()\n    {\n        return $this->likes()->where('value', 1)->count();\n    }\n\n    public function dislikesCount()\n    {\n        return $this->likes()->where('value', 0)->count();\n    }\n}\n"
  },
  {
    "path": "src/Traits/Rate/CanRate.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRating\\Traits\\Rate;\n\nuse Nagy\\LaravelRating\\LaravelRating;\nuse Nagy\\LaravelRating\\LaravelRatingFacade;\nuse Nagy\\LaravelRating\\Models\\Rating;\n\ntrait CanRate\n{\n    public function ratings()\n    {\n        return $this->morphMany(Rating::class, 'model')->where('type', LaravelRating::TYPE_RATE);\n    }\n\n    public function rate($model, $value)\n    {\n        if ($value === null || $value === false || $value === -1) {\n            return $this->unRate($model);\n        }\n\n        return LaravelRatingFacade::rate($this, $model, $value, LaravelRating::TYPE_RATE);\n    }\n\n    public function unRate($model)\n    {\n        return LaravelRatingFacade::unRate($this, $model, LaravelRating::TYPE_RATE);\n    }\n\n    public function getRatingValue($model)\n    {\n        return LaravelRatingFacade::getRatingValue($this, $model, LaravelRating::TYPE_RATE);\n    }\n\n    public function isRated($model)\n    {\n        return LaravelRatingFacade::isRated($this, $model, LaravelRating::TYPE_RATE);\n    }\n\n    public function rated()\n    {\n        return LaravelRatingFacade::resolveRatedItems($this->ratings);\n    }\n}\n"
  },
  {
    "path": "src/Traits/Rate/Rateable.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRating\\Traits\\Rate;\n\nuse Nagy\\LaravelRating\\Models\\Rating;\n\ntrait Rateable\n{\n    public function ratings()\n    {\n        return $this->morphMany(Rating::class, 'rateable');\n    }\n\n    public function ratingsAvg()\n    {\n        return $this->ratings()->avg('value');\n    }\n\n    public function ratingsCount()\n    {\n        return $this->ratings()->count();\n    }\n}\n"
  },
  {
    "path": "src/Traits/Vote/CanVote.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRating\\Traits\\Vote;\n\nuse Nagy\\LaravelRating\\LaravelRating;\nuse Nagy\\LaravelRating\\LaravelRatingFacade;\nuse Nagy\\LaravelRating\\Models\\Rating;\n\ntrait CanVote\n{\n    public function votes()\n    {\n        return $this->morphMany(Rating::class, 'model')->where('type', LaravelRating::TYPE_VOTE);\n    }\n\n    public function upVote($model)\n    {\n        return LaravelRatingFacade::rate($this, $model, 1, LaravelRating::TYPE_VOTE);\n    }\n\n    public function downVote($model)\n    {\n        return LaravelRatingFacade::rate($this, $model, 0, LaravelRating::TYPE_VOTE);\n    }\n\n    public function isVoted($model)\n    {\n        return LaravelRatingFacade::isRated($this, $model, LaravelRating::TYPE_VOTE);\n    }\n\n    public function getVotingValue($model)\n    {\n        return LaravelRatingFacade::getRatingValue($this, $model, LaravelRating::TYPE_VOTE);\n    }\n\n    public function upVoted()\n    {\n        $upVoted = $this->votes()->where('value', 1)->get();\n\n        return LaravelRatingFacade::resolveRatedItems($upVoted);\n    }\n\n    public function downVoted()\n    {\n        $downVoted = $this->votes()->where('value', 0)->get();\n\n        return LaravelRatingFacade::resolveRatedItems($downVoted);\n    }\n\n    public function voted()\n    {\n        return LaravelRatingFacade::resolveRatedItems($this->votes);\n    }\n}\n"
  },
  {
    "path": "src/Traits/Vote/Votable.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRating\\Traits\\Vote;\n\nuse Nagy\\LaravelRating\\Models\\Rating;\n\ntrait Votable\n{\n    public function votes()\n    {\n        return $this->morphMany(Rating::class, 'rateable');\n    }\n\n    public function totalVotesCount()\n    {\n        return $this->votes()->count();\n    }\n\n    public function upVotesCount()\n    {\n        return $this->votes()->where('value', 1)->count();\n    }\n\n    public function downVotesCount()\n    {\n        return $this->votes()->where('value', 0)->count();\n    }\n\n    public function votesDiff()\n    {\n        return $this->upVotesCount() - $this->downVotesCount();\n    }\n}\n"
  },
  {
    "path": "tests/LikeTest.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRatings\\Tests;\n\nuse Nagy\\LaravelRating\\Tests\\Models\\Post;\nuse Nagy\\LaravelRating\\Tests\\Models\\User;\nuse Nagy\\LaravelRating\\Tests\\TestCase;\n\nclass LikeTest extends TestCase\n{\n    public function setUp(): void\n    {\n        parent::setUp();\n    }\n\n    /** @test */\n    public function user_can_like_likable_model()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->like($post);\n        \n        $this->assertCount(1, $user->likes);\n    }\n    \n    /** @test */\n    public function user_can_dislike_likable_model()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->dislike($post);\n        \n        $this->assertCount(1, $user->likes);\n    }\n\n    /** @test */\n    public function user_can_return_total_likes_count()\n    {\n        $user = User::create(['name' => 'test']);\n        $user2 = User::create(['name' => 'test2']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->like($post);\n        $user2->like($post);\n        \n        $this->assertTrue($post->likesCount() == 2);\n    }\n\n    /** @test */\n    public function it_can_return_liked_items_for_a_user()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n        $post2 = Post::create(['name' => 'test post2']);\n\n        $user->like($post);\n        $user->dislike($post2);\n\n        $this->assertEquals('test post', $user->liked()->first()->name);\n    }\n\n    /** @test */\n    public function it_can_return_disliked_items_for_a_user()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n        $post2 = Post::create(['name' => 'test post2']);\n\n        $user->like($post);\n        $user->dislike($post2);\n\n        $this->assertEquals('test post2', $user->disliked()->first()->name);\n    }\n\n    /** @test */\n    public function it_can_return_all_liked_disliked_items_for_a_user()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n        $post2 = Post::create(['name' => 'test post2']);\n\n        $user->like($post);\n        $user->dislike($post2);\n\n        $this->assertCount(2, $user->likedDisliked());\n    }\n}\n"
  },
  {
    "path": "tests/Models/Post.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRating\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Nagy\\LaravelRating\\Traits\\Like\\Likeable;\nuse Nagy\\LaravelRating\\Traits\\Rate\\Rateable;\nuse Nagy\\LaravelRating\\Traits\\Vote\\Votable;\n\nclass Post extends Model\n{\n    use Rateable;\n    use Votable;\n    use Likeable;\n\n    protected $guarded = [];\n\n    protected $table = 'users';\n}\n"
  },
  {
    "path": "tests/Models/User.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRating\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Nagy\\LaravelRating\\Traits\\Like\\CanLike;\nuse Nagy\\LaravelRating\\Traits\\Rate\\CanRate;\nuse Nagy\\LaravelRating\\Traits\\Vote\\CanVote;\n\nclass User extends Model\n{\n    use CanRate;\n    use CanVote;\n    use CanLike;\n\n    protected $guarded = [];\n\n    protected $table = 'users';\n}\n"
  },
  {
    "path": "tests/RatingTest.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRatings\\Tests;\n\nuse Illuminate\\Database\\Eloquent\\Relations\\Relation;\nuse Nagy\\LaravelRating\\Tests\\Models\\Post;\nuse Nagy\\LaravelRating\\Tests\\Models\\User;\nuse Nagy\\LaravelRating\\Tests\\TestCase;\n\nclass RatingTest extends TestCase\n{\n    public function setUp(): void\n    {\n        parent::setUp();\n    }\n\n    /** @test */\n    public function user_can_rate_rateable_model()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->rate($post, 5);\n\n        $this->assertCount(1, $user->ratings);\n    }\n\n    /** @test */\n    public function user_can_unrate_rateable_model()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->rate($post, 5);\n        $user->unRate($post);\n\n        $this->assertCount(0, $user->ratings);\n    }\n\n    /** @test */\n    public function ratable_model_can_be_unrated_if_passed_false_or_null_to_rate_method()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->rate($post, 5);\n        $user->rate($post, -1);\n\n        $user->rate($post, 5);\n        $user->rate($post, null);\n\n        $user->rate($post, 5);\n        $user->rate($post, false);\n\n        $user->rate($post, 5);\n        $user->rate($post, 10);\n\n        $this->assertEquals(10, $user->getRatingValue($post));\n        $this->assertCount(1, $user->ratings);\n    }\n\n    /** @test */\n    public function it_can_return_rating_value_for_user_for_rateable_model()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->rate($post, 5);\n\n        $this->assertTrue($user->getRatingValue($post) == 5);\n    }\n\n    /** @test */\n    public function it_can_update_user_rating_if_already_rated()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->rate($post, 5);\n        $this->assertTrue($user->getRatingValue($post) == 5);\n\n        $user->rate($post, 10);\n        $this->assertTrue($user->getRatingValue($post) == 10);\n    }\n\n    /** @test */\n    public function it_can_return_avg_for_rateable_model()\n    {\n        $user = User::create(['name' => 'test']);\n        $user2 = User::create(['name' => 'test2']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->rate($post, 5);\n        $user2->rate($post, 10);\n\n        $this->assertTrue($post->ratingsAvg() == 7.5);\n    }\n\n    /** @test */\n    public function it_can_return_count_for_rateable_model()\n    {\n        $user = User::create(['name' => 'test']);\n        $user2 = User::create(['name' => 'test2']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->rate($post, 5);\n        $user2->rate($post, 10);\n\n        $this->assertTrue($post->ratingsCount() == 2);\n    }\n\n    /** @test */\n    public function it_can_return_rated_items_for_a_user()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n        $post2 = Post::create(['name' => 'test post2']);\n\n        $user->rate($post, 5);\n        $user->rate($post2, 10);\n\n        $this->assertCount(2, $user->rated());\n    }\n\n    /** @test */\n    public function it_can_work_with_morph_maps()\n    {\n        Relation::$morphMap = [\n            'post' => Post::class,\n            'user' => User::class,\n        ];\n\n\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->rate($post, 5);\n\n        $this->assertCount(1, $user->rated());\n    }\n}\n"
  },
  {
    "path": "tests/TestCase.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRating\\Tests;\n\nuse Nagy\\LaravelRating\\LaravelRatingServiceProvider;\nuse Orchestra\\Testbench\\TestCase as Orchestra;\n\nclass TestCase extends Orchestra\n{\n    public function setUp(): void\n    {\n        parent::setUp();\n    }\n\n    protected function getPackageProviders($app)\n    {\n        return [\n            LaravelRatingServiceProvider::class,\n        ];\n    }\n\n    public function getEnvironmentSetUp($app)\n    {\n        $app['config']->set('database.default', 'sqlite');\n        $app['config']->set('database.connections.sqlite', [\n            'driver' => 'sqlite',\n            'database' => ':memory:',\n            'prefix' => '',\n        ]);\n\n\n        include_once __DIR__.'/../database/migrations/create_ratings_table.php.stub';\n        include_once __DIR__.'/../database/migrations/add_type_column_to_ratings_table.php.stub';\n        include_once __DIR__.'/database/migrations/create_posts_table.php';\n        include_once __DIR__.'/database/migrations/create_users_table.php';\n\n        (new \\CreateRatingsTable())->up();\n        (new \\AddTypeColumnToRatingsTable())->up();\n        (new \\CreatePostsTable())->up();\n        (new \\CreateUsersTable())->up();\n    }\n}\n"
  },
  {
    "path": "tests/VotingTest.php",
    "content": "<?php\n\nnamespace Nagy\\LaravelRatings\\Tests;\n\nuse Nagy\\LaravelRating\\Tests\\Models\\Post;\nuse Nagy\\LaravelRating\\Tests\\Models\\User;\nuse Nagy\\LaravelRating\\Tests\\TestCase;\n\nclass VotingTest extends TestCase\n{\n    public function setUp(): void\n    {\n        parent::setUp();\n    }\n\n    /** @test */\n    public function user_can_up_vote_votable_model()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->upVote($post);\n\n\n        $this->assertCount(1, $user->votes);\n        $this->assertTrue($user->getVotingValue($post) == 1);\n    }\n\n    /** @test */\n    public function user_can_down_vote_votable_model()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->downVote($post);\n\n        $this->assertCount(1, $user->votes);\n        $this->assertTrue($user->getVotingValue($post) == 0);\n    }\n\n    /** @test */\n    public function it_returns_total_up_voting_count()\n    {\n        $user = User::create(['name' => 'test']);\n        $user2 = User::create(['name' => 'test2']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->upVote($post);\n        $user2->upVote($post);\n\n        $this->assertTrue($post->upVotesCount() == 2);\n    }\n\n    /** @test */\n    public function it_returns_total_down_voting_count()\n    {\n        $user = User::create(['name' => 'test']);\n        $user2 = User::create(['name' => 'test2']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->downVote($post);\n        $user2->downVote($post);\n\n        $this->assertTrue($post->downVotesCount() == 2);\n    }\n\n    /** @test */\n    public function it_returns_total_votes_count()\n    {\n        $user = User::create(['name' => 'test']);\n        $user2 = User::create(['name' => 'test2']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->upVote($post);\n        $user2->downVote($post);\n\n        $this->assertTrue($post->totalVotesCount() == 2);\n    }\n\n    /** @test */\n    public function it_returns_votes_diff()\n    {\n        $user = User::create(['name' => 'test']);\n        $user2 = User::create(['name' => 'test2']);\n        $post = Post::create(['name' => 'test post']);\n\n        $user->upVote($post);\n        $user2->downVote($post);\n\n        $this->assertTrue($post->votesDiff() == 0);\n    }\n\n    /** @test */\n    public function it_can_return_up_voted_items_for_a_user()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n        $post2 = Post::create(['name' => 'test post2']);\n\n        $user->upVote($post);\n        $user->downVote($post2);\n\n        $this->assertEquals('test post', $user->upVoted()->first()->name);\n    }\n\n    /** @test */\n    public function it_can_return_downvoted_items_for_a_user()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n        $post2 = Post::create(['name' => 'test post2']);\n\n        $user->upVote($post);\n        $user->downVote($post2);\n\n        $this->assertEquals('test post2', $user->downVoted()->first()->name);\n    }\n\n    /** @test */\n    public function it_can_return_all_voted_items_for_a_user()\n    {\n        $user = User::create(['name' => 'test']);\n        $post = Post::create(['name' => 'test post']);\n        $post2 = Post::create(['name' => 'test post2']);\n\n        $user->upVote($post);\n        $user->downVote($post2);\n\n        $this->assertCount(2, $user->voted());\n    }\n}\n"
  },
  {
    "path": "tests/database/migrations/create_posts_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass CreatePostsTable extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('posts', function (Blueprint $table) {\n            $table->bigIncrements('id');\n            $table->string('name');\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('posts');\n    }\n}\n"
  },
  {
    "path": "tests/database/migrations/create_users_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass CreateUsersTable extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('users', function (Blueprint $table) {\n            $table->bigIncrements('id');\n            $table->string('name');\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('users');\n    }\n}\n"
  }
]