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;
7
8use App\Libraries\MorphMap;
9use App\Traits\Validatable;
10
11/**
12 * @property int $id
13 * @property int $user_id
14 * @property string $notifiable_type
15 * @property int $notifiable_id
16 * @property string $subtype
17 */
18class Follow extends Model
19{
20 use Validatable;
21
22 const DEFAULT_SUBTYPE = 'forum_topic';
23
24 const SUBTYPES = [
25 'comment' => Comment::COMMENTABLES,
26
27 'mapping' => [
28 MorphMap::MAP[User::class],
29 ],
30 ];
31
32 public function scopeWhereNotifiable($query, $notifiable)
33 {
34 $query->where([
35 'notifiable_type' => $notifiable->getMorphClass(),
36 'notifiable_id' => $notifiable->getKey(),
37 ]);
38 }
39
40 public function notifiable()
41 {
42 return $this->morphTo();
43 }
44
45 public function user()
46 {
47 return $this->belongsTo(User::class, 'user_id');
48 }
49
50 public function setNotifiableAttribute($value)
51 {
52 $this->notifiable()->associate($value);
53 }
54
55 public function setNotifiableTypeAttribute($value)
56 {
57 if (MorphMap::getClass($value) === null) {
58 return;
59 }
60
61 $this->attributes['notifiable_type'] = $value;
62 }
63
64 public function setUserAttribute($value)
65 {
66 $this->user()->associate($value);
67 }
68
69 public function validationErrorsTranslationPrefix(): string
70 {
71 return 'follow';
72 }
73
74 public function isValid()
75 {
76 $this->validationErrors()->reset();
77
78 if ($this->notifiable === null) {
79 $this->validationErrors()->add('notifiable', 'required');
80 }
81
82 if (!in_array($this->notifiable_type, static::SUBTYPES[$this->subtype] ?? [], true)) {
83 $this->validationErrors()->add('subtype', '.invalid');
84 }
85
86 return $this->validationErrors()->isEmpty();
87 }
88
89 public function save(array $options = [])
90 {
91 return $this->isValid() && parent::save($options);
92 }
93}