the browser-facing portion of osu!
at master 3.7 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6namespace App\Models\Forum; 7 8use App\Libraries\BBCodeForDB; 9use DB; 10 11/** 12 * @property int $poll_option_id 13 * @property string $poll_option_text 14 * @property int $poll_option_total 15 * @property Post $post 16 * @property Topic $topic 17 * @property int $topic_id 18 * @property \Illuminate\Database\Eloquent\Collection $votes PollVote 19 */ 20class PollOption extends Model 21{ 22 protected $table = 'phpbb_poll_options'; 23 protected $primaryKey = null; 24 public $incrementing = false; 25 public $timestamps = false; 26 27 public function getKey(): string 28 { 29 return $this->topic_id.'-'.$this->poll_option_id; 30 } 31 32 // For bbcode_uid, the first post (even if the post is deleted). 33 public function post() 34 { 35 return $this 36 ->belongsTo(Post::class, 'topic_id', 'topic_id') 37 ->withTrashed() 38 ->orderBy('post_id', 'ASC') 39 ->limit(1); 40 } 41 42 public function topic() 43 { 44 return $this->belongsTo(Topic::class, 'topic_id'); 45 } 46 47 public function votes() 48 { 49 return $this->hasMany(PollVote::class, 'poll_option_id', 'poll_option_id')->where('topic_id', $this->topic_id); 50 } 51 52 public static function summary($topic, $user) 53 { 54 $summary = [ 55 'options' => [], 56 'total' => 0, 57 'user_votes' => 0, 58 ]; 59 60 if ($topic->poll()->exists()) { 61 if ($user === null) { 62 $userVotes = []; 63 } else { 64 $userVotes = array_flip(model_pluck($topic->pollVotes()->where('vote_user_id', $user->getKey()), 'poll_option_id')); 65 } 66 67 foreach ($topic->pollOptions as $poll) { 68 $votedByUser = array_key_exists($poll->poll_option_id, $userVotes); 69 70 $summary['options'][$poll->poll_option_id] = [ 71 'textHTML' => $poll->optionTextHTML(), 72 'total' => $poll->poll_option_total, 73 'voted_by_user' => $votedByUser, 74 ]; 75 76 $summary['total'] += $poll->poll_option_total; 77 $summary['user_votes'] += $votedByUser ? 1 : 0; 78 } 79 } 80 81 return $summary; 82 } 83 84 public static function updateTotals($filters) 85 { 86 $staticTable = (new static())->table; 87 $countQuery = PollVote::where([ 88 'topic_id' => DB::raw($staticTable.'.topic_id'), 89 'poll_option_id' => DB::raw($staticTable.'.poll_option_id'), 90 ]) 91 // raw because ->count() immediately executes the query. 92 // DISTINCT because lack of unique index causing duplicated votes. 93 ->select(DB::raw('COUNT(DISTINCT vote_user_id)')) 94 ->toSql(); 95 96 return static::where($filters) 97 ->update(['poll_option_total' => DB::raw("({$countQuery})")]); 98 } 99 100 public function userHasVoted($user) 101 { 102 if ($user === null) { 103 return false; 104 } 105 106 return $this->votes()->where('vote_user_id', $user->user_id)->exists(); 107 } 108 109 public function setPollOptionTextAttribute($value) 110 { 111 $this->attributes['poll_option_text'] = (new BBCodeForDB($value))->generate(); 112 } 113 114 public function optionTextHTML() 115 { 116 return bbcode( 117 $this->poll_option_text, 118 $this->post->bbcode_uid, 119 ['withGallery' => true] 120 ); 121 } 122 123 public function optionTextRaw() 124 { 125 return bbcode_for_editor($this->poll_option_text, $this->post->bbcode_uid); 126 } 127}