the browser-facing portion of osu!
at master 4.1 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\Models\User; 9 10/** 11 * @property bool $mail 12 * @property bool $notify_status 13 * @property Topic $topic 14 * @property int $topic_id 15 * @property User $user 16 * @property int $user_id 17 */ 18class TopicWatch extends Model 19{ 20 public $incrementing = false; 21 public $timestamps = false; 22 23 protected $casts = [ 24 'notify_status' => 'boolean', 25 'mail' => 'boolean', 26 ]; 27 protected $table = 'phpbb_topics_watch'; 28 protected $primaryKey = ':composite'; 29 protected $primaryKeys = ['topic_id', 'user_id']; 30 31 public static function unreadCount($user) 32 { 33 if ($user === null) { 34 return 0; 35 } 36 37 $watch = new static(); 38 $topic = new Topic(); 39 $track = new TopicTrack(); 40 41 return static 42 ::join($topic->getTable(), $topic->qualifyColumn('topic_id'), '=', $watch->qualifyColumn('topic_id')) 43 ->leftJoin($track->getTable(), function ($join) use ($track, $watch) { 44 $join 45 ->on($track->qualifyColumn('topic_id'), '=', $watch->qualifyColumn('topic_id')) 46 ->on($track->qualifyColumn('user_id'), '=', $watch->qualifyColumn('user_id')); 47 }) 48 ->where($watch->qualifyColumn('user_id'), '=', $user->user_id) 49 ->where(function ($query) use ($topic, $track) { 50 $query 51 ->whereRaw("{$topic->qualifyColumn('topic_last_post_time')} > {$track->qualifyColumn('mark_time')}") 52 ->orWhereNull($track->qualifyColumn('mark_time')); 53 }) 54 ->count(); 55 } 56 57 public static function watchStatus($user, $topics) 58 { 59 return static::where('user_id', '=', $user->getKey()) 60 ->whereIn('topic_id', $topics->pluck('topic_id')) 61 ->get() 62 ->keyBy('topic_id'); 63 } 64 65 public static function lookup($topic, $user) 66 { 67 if ($user === null) { 68 return new static(['topic_id' => $topic->getKey()]); 69 } else { 70 return static::lookupQuery($topic, $user)->first() ?? new static([ 71 'topic_id' => $topic->getKey(), 72 'user_id' => $user->getKey(), 73 ]); 74 } 75 } 76 77 public static function setState($topic, $user, $state) 78 { 79 $tries = 0; 80 81 while (true) { 82 $watch = static::lookup($topic, $user); 83 84 try { 85 if ($state === 'not_watching') { 86 $watch->delete(); 87 } else { 88 $watch->fill(['mail' => $state === 'watching_mail'])->saveOrExplode(); 89 } 90 91 return $watch; 92 } catch (\Throwable $e) { 93 if (is_sql_unique_exception($e) && $tries < 2) { 94 $tries++; 95 } else { 96 throw $e; 97 } 98 } 99 } 100 } 101 102 public function topic() 103 { 104 return $this->belongsTo(Topic::class, 'topic_id'); 105 } 106 107 public function user() 108 { 109 return $this->belongsTo(User::class, 'user_id'); 110 } 111 112 public function scopeLookupQuery($query, $topic, $user) 113 { 114 if ($user instanceof User) { 115 $userId = $user->getKey(); 116 } elseif (is_string($user) || is_int($user)) { 117 $userId = (int) $user; 118 } else { 119 return $query->none(); 120 } 121 122 if ($topic instanceof Topic) { 123 $topicId = $topic->getKey(); 124 } elseif (is_string($topic) || is_int($topic)) { 125 $topicId = (int) $topic; 126 } else { 127 return $query->none(); 128 } 129 130 return $query->where([ 131 'topic_id' => $topicId, 132 'user_id' => $userId, 133 ]); 134 } 135 136 public function stateText() 137 { 138 if ($this->exists) { 139 return $this->mail ? 'watching_mail' : 'watching'; 140 } else { 141 return 'not_watching'; 142 } 143 } 144}