overtrue / laravel-vote
User Vote features for Laravel Application.
Fund package maintenance!
overtrue
Installs: 7 040
Dependents: 0
Suggesters: 0
Security: 0
Stars: 112
Watchers: 3
Forks: 8
Open Issues: 2
Requires
- laravel/framework: ^9.0|^10.0|^11.0
Requires (Dev)
- brainmaestro/composer-git-hooks: dev-master
- friendsofphp/php-cs-fixer: ^3.6
- laravel/pint: ^1.5
- mockery/mockery: ^1.4
- orchestra/testbench: ^8.0
- phpunit/phpunit: ^10.0
README
⬆️ ⬇️ User vote system for Laravel Application.
Installing
composer require overtrue/laravel-vote -vvv
Configuration & Migrations
php artisan vendor:publish
then create tables:
php artisan migrate
Usage
Traits
Overtrue\LaravelVote\Traits\Voter
use Illuminate\Notifications\Notifiable; use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Foundation\Auth\User as Authenticatable; use Overtrue\LaravelVote\Traits\Voter; class User extends Authenticatable { use Voter; <...> }
Overtrue\LaravelVote\Traits\Voteable
use Illuminate\Database\Eloquent\Model; use Overtrue\LaravelVote\Traits\Votable; class Idea extends Model { use Votable; <...> }
API
$user = User::find(1); $idea = Idea::find(2); $user->vote($idea, 1); // upvote $user->vote($idea, -1); // downvote $user->upvote($idea); $user->downvote($idea); // with custom number of votes $user->upvote($idea, 3); $user->downvote($idea, 3); // cancel vote $user->cancelVote($idea); // get my voted items $user->getVotedItems(Idea::class) // Illuminate\Database\Eloquent\Builder // state $user->hasVoted($idea); $idea->hasBeenVotedBy($user);
Get model voters:
foreach($idea->voters as $user) { // echo $user->name; }
Get user voted items.
User can easy to get Votable models to do what you want.
*note: this method will return a Illuminate\Database\Eloquent\Builder
*
$votedItemsQuery = $user->getVotedItems(); // filter votable_type $votedIdeasQuery = $user->getVotedItems(Idea::class); // fetch results $votedIdeas = $user->getVoteItems(Idea::class)->get(); $votedIdeas = $user->getVoteItems(Idea::class)->paginate(); $votedIdeas = $user->getVoteItems(Idea::class)->where('title', 'Laravel-Vote')->get();
Aggregations
count relations
// all $user->votes()->count(); // filter votable_type $user->votes()->ofType(Idea::class)->count(); // voters count $idea->voters()->count();
List with *_count
attribute:
// for Voter models: $users = User::withCount('votes')->get(); // or $users = User::withCount('upvotes')->get(); // or $users = User::withCount('downvotes')->get(); // or $users = User::withCount(['votes', 'upvotes', 'downvotes'])->get(); foreach($users as $user) { echo $user->votes_count; echo $user->upvotes_count; echo $user->downvotes_count; } // for Votable models: $ideas = Idea::withCount('voters')->get(); // or $ideas = Idea::withCount('upvoters')->get(); $ideas = Idea::withCount('downvoters')->get(); // or $ideas = Idea::withCount(['voters', 'upvoters', 'downvoters'])->get(); foreach($ideas as $idea) { echo $idea->voters_count; echo $idea->upvoters_count; echo $idea->downvoters_count; }
Votable sum votes
$user1->upvote($idea); // 1 (up) $user2->upvote($idea); // 2 (up) $user3->upvote($idea); // 3 (up) $user4->downvote($idea); // -1 (down) // sum(votes) $idea->totalVotes(); // 2(3 - 1) // sum(votes) where votes > 0 $idea->totalUpvotes(); // 3 // abs(sum(votes)) where votes < 0 $idea->totalDownvotes(); // 1 // appends aggregations attributes $idea->appendsVotesAttributes(); $idea->toArray(); // result [ "id" => 1 "title" => "Add socialite login support." "created_at" => "2021-05-20T03:26:16.000000Z" "updated_at" => "2021-05-20T03:26:16.000000Z" // these aggregations attributes will be appends. "total_votes" => 2 "total_upvotes" => 3 "total_downvotes" => 1 ],
Attach voter vote status to votable collection
You can use Voter::attachVoteStatus(Collection $votables)
to attach the voter vote status, it will set has_voted
,has_upvoted
and has_downvoted
attributes to each model of $votables
:
For model
$idea = Idea::find(1); $user->attachVoteStatus($idea); // result [ "id" => 1 "title" => "Add socialite login support." "created_at" => "2021-05-20T03:26:16.000000Z" "updated_at" => "2021-05-20T03:26:16.000000Z" "has_voted" => true "has_upvoted" => true "has_downvoted" => false ],
For Collection | Paginator | LengthAwarePaginator | array
:
$ideas = Idea::oldest('id')->get(); $user->attachVoteStatus($ideas); $ideas = $ideas->toArray(); // result [ [ "id" => 1 "title" => "Add socialite login support." "created_at" => "2021-05-20T03:26:16.000000Z" "updated_at" => "2021-05-20T03:26:16.000000Z" "has_voted" => true "has_upvoted" => true "has_downvoted" => false ], [ "id" => 2 "title" => "Add php8 support." "created_at" => "2021-05-20T03:26:16.000000Z" "updated_at" => "2021-05-20T03:26:16.000000Z" "has_voted" => true "has_upvoted" => false "has_downvoted" => true ], [ "id" => 3 "title" => "Add qrcode support." "created_at" => "2021-05-20T03:26:16.000000Z" "updated_at" => "2021-05-20T03:26:16.000000Z" "has_voted" => false "has_upvoted" => false "has_downvoted" => false ], ]
For pagination
$ideas = Idea::paginate(20); $user->attachVoteStatus($ideas->getCollection());
N+1 issue
To avoid the N+1 issue, you can use eager loading to reduce this operation to just 2 queries. When querying, you may specify which relationships should be eager loaded using the with
method:
// Voter use Tests\Idea;$users = User::with('votes')->get(); foreach($users as $user) { $user->hasVoted($idea); } // Votable $ideas = Idea::with('voters')->get(); foreach($ideas as $idea) { $idea->hasBeenVotedBy($user); } // Votable votes $ideas = Idea::withTotalVotes() // total_votes ->withTotalUpvotes() // total_upvotes ->withTotalDownvotes() // total_downvotes ->get(); // same as // withVotesAttributes() = withTotalVotes() + withTotalUpvotes() + withTotalDownvotes() $ideas = Idea::withVotesAttributes()->get(); // result [ [ "id" => 1 "title" => "Add socialite login support." "created_at" => "2021-05-19T07:01:10.000000Z" "updated_at" => "2021-05-19T07:01:10.000000Z" "total_votes" => 2 "total_upvotes" => 3 "total_downvotes" => 1 ], [ "id" => 2 "title" => "Add PHP8 support." "created_at" => "2021-05-20T07:01:10.000000Z" "updated_at" => "2021-05-20T07:01:10.000000Z" "total_votes" => 1 "total_upvotes" => 2 "total_downvotes" => 1 ] ]
Events
Related packages
- Follow: overtrue/laravel-follow
- Like: overtrue/laravel-like
- Vote: overtrue/laravel-vote
- Subscribe: overtrue/laravel-subscribe
- Bookmark: overtrue/laravel-bookmark (working in progress)
❤️ Sponsor me
如果你喜欢我的项目并想支持它,点击这里 ❤️
Project supported by JetBrains
Many thanks to Jetbrains for kindly providing a license for me to work on this and other open-source projects.
Contributing
You can contribute in one of three ways:
- File bug reports using the issue tracker.
- Answer questions or fix bugs on the issue tracker.
- Contribute new features or update the wiki.
The code contribution process is not very formal. You just need to make sure that you follow the PSR-0, PSR-1, and PSR-2 coding guidelines. Any new code contributions must be accompanied by unit tests where applicable.
PHP 扩展包开发
想知道如何从零开始构建 PHP 扩展包?
请关注我的实战课程,我会在此课程中分享一些扩展开发经验 —— 《PHP 扩展包实战教程 - 从入门到发布》
License
MIT