Issues (85)

app/Services/MessageService.php (4 issues)

1
<?php
2
3
namespace App\Services;
4
5
use App\Interfaces\ContactServiceInterface;
6
use App\Interfaces\MessageServiceInterface;
7
use App\Models\Message;
8
use App\Models\Participant;
9
use App\Models\Thread;
10
use App\Models\User;
11
use App\Notifications\MessageCreated;
12
use App\Notifications\ParticipantCreated;
13
use App\Notifications\ThreadCreated;
14
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
15
use Illuminate\Database\Eloquent\ModelNotFoundException;
16
use Illuminate\Support\Collection;
17
use Illuminate\Support\Facades\Notification;
18
19
class MessageService implements MessageServiceInterface
20
{
21
    /**
22
     * @var ContactServiceInterface
23
     */
24
    public ContactServiceInterface $contactService;
25
26
    /**
27
     * MessageService constructor.
28
     *
29
     * @param  ContactServiceInterface  $contactService
30
     */
31
    public function __construct(ContactServiceInterface $contactService)
32
    {
33
        $this->contactService = $contactService;
34
    }
35
36
    /**
37
     * All threads that user is participating in.
38
     *
39
     * @param  User  $user
40
     * @return LengthAwarePaginator
41
     */
42
    public function threads(User $user): LengthAwarePaginator
43
    {
44
        return Thread::forUser($user->id)->with('participants.user')->latest('updated_at')->paginate();
45
    }
46
47
    /**
48
     * All threads that user is participating in, with new messages.
49
     *
50
     * @param  User  $user
51
     * @return Collection
52
     */
53
    public function unreadThreads(User $user): Collection
54
    {
55
        return Thread::forUserWithNewMessages($user->id)->latest('updated_at')->get();
56
    }
57
58
    /**
59
     * Retrieve a thread.
60
     *
61
     * @param  string  $thread_id
62
     * @return Thread
63
     *
64
     * @throws ModelNotFoundException
65
     */
66
    public function thread(string $thread_id): Thread
67
    {
68
        return Thread::with(['messages', 'participants.user'])->find($thread_id);
0 ignored issues
show
Bug Best Practice introduced by
The expression return App\Models\Thread...er'))->find($thread_id) could return the type null which is incompatible with the type-hinted return App\Models\Thread. Consider adding an additional type-check to rule them out.
Loading history...
69
    }
70
71
    /**
72
     * User ids that are associated with the thread.
73
     *
74
     * @param  string  $thread_id
75
     * @return Collection
76
     */
77
    public function threadParticipant(string $thread_id): Collection
78
    {
79
        return Thread::with('participants.user')->find($thread_id)->participants;
0 ignored issues
show
Bug Best Practice introduced by
The property participants does not exist on App\Models\Thread. Since you implemented __get, consider adding a @property annotation.
Loading history...
80
    }
81
82
    /**
83
     * User ids that are associated with the thread.
84
     *
85
     * @param  string  $thread_id
86
     * @return Collection
87
     */
88
    public function threadParticipants(string $thread_id): Collection
89
    {
90
        return Thread::with('participants.user')->find($thread_id)->participants;
0 ignored issues
show
Bug Best Practice introduced by
The property participants does not exist on App\Models\Thread. Since you implemented __get, consider adding a @property annotation.
Loading history...
91
    }
92
93
    /**
94
     * New message thread.
95
     *
96
     * @param  string  $subject
97
     * @param  User  $user
98
     * @param  array  $content
99
     * @param  null|array  $recipients
100
     * @return Thread
101
     */
102
    public function newThread(string $subject, User $user, array $content, ?array $recipients = []): Thread
103
    {
104
        /** @var $thread Thread */
105
        $thread = Thread::create([
106
            'subject' => $subject,
107
        ]);
108
109
        $message = $this->newMessage($thread, $user, $content);
110
111
        // Recipients are participants too
112
        $recipients = collect($recipients)
113
            ->map(function ($recipient) {
114
                return User::find($recipient);
115
            })
116
            ->add($user)
117
            ->unique('id')
118
            ->map(function ($recipient) use ($thread) {
119
                return $this->addParticipant($thread, $recipient);
120
            });
121
122
        $thread->setRelation('messages', collect([$message]));
123
        $thread->setRelation('participants', $recipients);
124
        $users = User::find($recipients->pluck('user_id'));
125
        Notification::send($users, new ThreadCreated($thread));
126
127
        return $thread;
128
    }
129
130
    /**
131
     * New message.
132
     *
133
     * @param  Thread  $thread
134
     * @param  User  $user
135
     * @param  array  $content
136
     * @return Message
137
     */
138
    public function newMessage(Thread $thread, User $user, array $content): Message
139
    {
140
        $message = Message::create([
141
            'thread_id' => $thread->id,
142
            'user_id' => $user->id,
143
            'body' => $content,
144
        ]);
145
146
        $recipients = $thread->users()->get();
147
148
        Notification::send($recipients, new MessageCreated($message));
149
150
        return $message;
151
    }
152
153
    /**
154
     * Mark as read a tread of a user.
155
     *
156
     * @param  Thread  $thread
157
     * @param  User  $user
158
     * @return Participant
159
     */
160
    public function markAsRead(Thread $thread, User $user): Participant
161
    {
162
        $thread->markAsRead($user->id);
163
164
        return $thread->participants()->where('user_id', $user->id)->first();
165
    }
166
167
    /**
168
     * Mark as read all messages of a user.
169
     *
170
     * @param  User  $user
171
     * @return bool
172
     */
173
    public function markAsReadAll(User $user): bool
174
    {
175
        return Participant::where([
0 ignored issues
show
Bug Best Practice introduced by
The expression return App\Models\Partic...('last_read' => now())) returns the type integer which is incompatible with the type-hinted return boolean.
Loading history...
176
            'user_id' => $user->id,
177
        ])->update([
178
            'last_read' => now(),
179
        ]);
180
    }
181
182
    /**
183
     * Mark as read all messages of a user.
184
     *
185
     * @param  Thread  $thread
186
     * @param  User  $user
187
     * @param  bool  $mark_as_read
188
     * @return Participant
189
     */
190
    public function addParticipant(Thread $thread, User $user, bool $mark_as_read = false): Participant
191
    {
192
        $return = $thread->participants()->updateOrCreate([
193
            'user_id' => $user->id,
194
            'thread_id' => $thread->id,
195
        ],
196
            $mark_as_read ? ['last_read' => now()] : []);
197
198
        $users = $thread->users()->get();
199
200
        $this->contactService->setContacts($users);
201
202
        Notification::send($users, new ParticipantCreated($return));
203
204
        return $return;
205
    }
206
}
207