Issues (28)

src/Reacter/Models/Reacter.php (1 issue)

Labels
Severity
1
<?php
2
3
/*
4
 * This file is part of Laravel Love.
5
 *
6
 * (c) Anton Komarev <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Cog\Laravel\Love\Reacter\Models;
15
16
use Cog\Contracts\Love\Reactant\Exceptions\ReactantInvalid;
17
use Cog\Contracts\Love\Reactant\Models\Reactant as ReactantInterface;
18
use Cog\Contracts\Love\Reacter\Exceptions\NotAssignedToReacterable;
19
use Cog\Contracts\Love\Reacter\Models\Reacter as ReacterInterface;
20
use Cog\Contracts\Love\Reacterable\Models\Reacterable as ReacterableInterface;
21
use Cog\Contracts\Love\Reaction\Exceptions\ReactionAlreadyExists;
22
use Cog\Contracts\Love\Reaction\Exceptions\ReactionNotExists;
23
use Cog\Contracts\Love\Reaction\Models\Reaction as ReactionInterface;
24
use Cog\Contracts\Love\ReactionType\Models\ReactionType as ReactionTypeInterface;
25
use Cog\Laravel\Love\Reaction\Models\Reaction;
26
use Cog\Laravel\Love\Support\Database\Eloquent\Model;
27
use Illuminate\Database\Eloquent\Casts\Attribute;
28
use Illuminate\Database\Eloquent\Factories\HasFactory;
29
use Illuminate\Database\Eloquent\Relations\HasMany;
30
use Illuminate\Database\Eloquent\Relations\MorphTo;
31
32
final class Reacter extends Model implements
33
    ReacterInterface
34
{
35
    use HasFactory;
36
37
    protected $table = 'love_reacters';
38
39
    protected static $unguarded = true;
40
41
    public function id(): Attribute
42
    {
43
        return new Attribute(
44
            get: fn (string | null $value) => $value,
45
            set: fn (string | null $value) => $value,
46
        );
47
    }
48
49
    public function reacterable(): MorphTo
50
    {
51
        return $this->morphTo('reacterable', 'type', 'id', 'love_reacter_id');
52
    }
53
54
    public function reactions(): HasMany
55
    {
56
        return $this->hasMany(Reaction::class, 'reacter_id');
57
    }
58
59
    public function getId(): string
60
    {
61
        return $this->getAttributeValue('id');
62
    }
63
64
    public function getReacterable(): ReacterableInterface
65
    {
66
        $reacterable = $this->getAttribute('reacterable');
67
68
        if ($reacterable === null) {
69
            throw new NotAssignedToReacterable();
70
        }
71
72
        return $reacterable;
73
    }
74
75
    public function getReactions(): iterable
76
    {
77
        return $this->getAttribute('reactions');
78
    }
79
80
    public function reactTo(
81
        ReactantInterface $reactant,
82
        ReactionTypeInterface $reactionType,
83
        float | null $rate = null,
84
    ): void {
85
        if ($reactant->isNull()) {
86
            throw ReactantInvalid::notExists();
87
        }
88
89
        $reaction = $this->findReaction($reactant, $reactionType);
90
91
        if ($reaction === null) {
92
            $this->createReaction($reactant, $reactionType, $rate);
93
94
            return;
95
        }
96
97
        if ($rate === null) {
98
            throw ReactionAlreadyExists::ofType($reactionType);
99
        }
100
101
        $reaction->changeRate($rate);
102
    }
103
104
    public function unreactTo(
105
        ReactantInterface $reactant,
106
        ReactionTypeInterface $reactionType,
107
    ): void {
108
        if ($reactant->isNull()) {
109
            throw ReactantInvalid::notExists();
110
        }
111
112
        $reaction = $this->findReaction($reactant, $reactionType);
113
114
        if ($reaction === null) {
115
            throw ReactionNotExists::ofType($reactionType);
116
        }
117
118
        $reaction->delete();
0 ignored issues
show
The method delete() does not exist on Cog\Contracts\Love\Reaction\Models\Reaction. Since it exists in all sub-types, consider adding an abstract or default implementation to Cog\Contracts\Love\Reaction\Models\Reaction. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

118
        $reaction->/** @scrutinizer ignore-call */ 
119
                   delete();
Loading history...
119
    }
120
121
    public function hasReactedTo(
122
        ReactantInterface $reactant,
123
        ReactionTypeInterface | null $reactionType = null,
124
        float | null $rate = null,
125
    ): bool {
126
        if ($reactant->isNull()) {
127
            return false;
128
        }
129
130
        return $reactant->isReactedBy($this, $reactionType, $rate);
131
    }
132
133
    public function hasNotReactedTo(
134
        ReactantInterface $reactant,
135
        ReactionTypeInterface | null $reactionType = null,
136
        float | null $rate = null,
137
    ): bool {
138
        return $reactant->isNotReactedBy($this, $reactionType, $rate);
139
    }
140
141
    public function isEqualTo(
142
        ReacterInterface $that,
143
    ): bool {
144
        return $that->isNotNull()
145
            && $this->getId() === $that->getId();
146
    }
147
148
    public function isNotEqualTo(
149
        ReacterInterface $that,
150
    ): bool {
151
        return !$this->isEqualTo($that);
152
    }
153
154
    public function isNull(): bool
155
    {
156
        return !$this->exists;
157
    }
158
159
    public function isNotNull(): bool
160
    {
161
        return $this->exists;
162
    }
163
164
    private function createReaction(
165
        ReactantInterface $reactant,
166
        ReactionTypeInterface $reactionType,
167
        float | null $rate = null,
168
    ): void {
169
        $this->reactions()->create([
170
            'reaction_type_id' => $reactionType->getId(),
171
            'reactant_id' => $reactant->getId(),
172
            'rate' => $rate,
173
        ]);
174
    }
175
176
    /**
177
     * @param \Cog\Contracts\Love\Reactant\Models\Reactant $reactant
178
     * @param \Cog\Contracts\Love\ReactionType\Models\ReactionType $reactionType
179
     * @return \Cog\Contracts\Love\Reaction\Models\Reaction|\Illuminate\Database\Eloquent\Model|null
180
     */
181
    private function findReaction(
182
        ReactantInterface $reactant,
183
        ReactionTypeInterface $reactionType,
184
    ): ReactionInterface | null {
185
        return $this
186
            ->reactions()
187
            ->where('reactant_id', $reactant->getId())
188
            ->where('reaction_type_id', $reactionType->getId())
189
            ->first();
190
    }
191
}
192