Passed
Push — master ( 0cb418...eb2129 )
by Burak
06:58
created

MessageService::threadParticipant()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 1
b 1
f 0
ccs 0
cts 2
cp 0
crap 2
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
     * @param ContactServiceInterface $contactService
29
     */
30 13
    public function __construct(ContactServiceInterface $contactService)
31
    {
32 13
        $this->contactService = $contactService;
33 13
    }
34
35
    /**
36
     * All threads that user is participating in.
37
     *
38
     * @param User $user
39
     * @return LengthAwarePaginator
40
     */
41 3
    public function threads(User $user): LengthAwarePaginator
42
    {
43 3
        return Thread::forUser($user->id)->with('participants.user')->latest('updated_at')->paginate();
44
    }
45
46
    /**
47
     * All threads that user is participating in, with new messages.
48
     *
49
     * @param User $user
50
     * @return Collection
51
     */
52 3
    public function unreadThreads(User $user): Collection
53
    {
54 3
        return Thread::forUserWithNewMessages($user->id)->latest('updated_at')->get();
55
    }
56
57
    /**
58
     * Retrieve a thread.
59
     *
60
     * @param string $thread_id
61
     * @return Thread
62
     * @throws ModelNotFoundException
63
     */
64 6
    public function thread(string $thread_id): Thread
65
    {
66 6
        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...
67
    }
68
69
    /**
70
     * User ids that are associated with the thread.
71
     *
72
     * @param string $thread_id
73
     * @return Collection
74
     */
75
    public function threadParticipant(string $thread_id): Collection
76
    {
77
        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...
78
    }
79
80
    /**
81
     * User ids that are associated with the thread.
82
     *
83
     * @param string $thread_id
84
     * @return Collection
85
     */
86 2
    public function threadParticipants(string $thread_id): Collection
87
    {
88 2
        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...
89
    }
90
91
    /**
92
     * New message thread.
93
     *
94
     * @param string $subject
95
     * @param User $user
96
     * @param array $content
97
     * @param null|array $recipients
98
     * @return Thread
99
     */
100 9
    public function newThread(string $subject, User $user, array $content, ?array $recipients = []): Thread
101
    {
102
        /** @var $thread Thread */
103 9
        $thread = Thread::create([
104 9
            'subject' => $subject,
105
        ]);
106
107 9
        $message = $this->newMessage($thread, $user, $content);
108
109
        // Recipients are participants too
110 9
        $recipients = collect($recipients)
111 9
            ->map(function ($recipient) {
112 5
                return User::find($recipient);
113 9
            })
114 9
            ->add($user)
115 9
            ->unique('id')
116 9
            ->map(function ($recipient) use ($thread) {
117 9
                return $this->addParticipant($thread, $recipient);
118 9
            });
119
120 9
        $thread->setRelation('messages', collect([$message]));
121 9
        $thread->setRelation('participants', $recipients);
122 9
        $users = User::find($recipients->pluck('user_id'));
123 9
        Notification::send($users, new ThreadCreated($thread));
124
125 9
        return $thread;
126
    }
127
128
    /**
129
     * New message.
130
     *
131
     * @param Thread $thread
132
     * @param User $user
133
     * @param array $content
134
     * @return Message
135
     */
136 11
    public function newMessage(Thread $thread, User $user, array $content): Message
137
    {
138 11
        $message = Message::create([
139 11
            'thread_id' => $thread->id,
140 11
            'user_id' => $user->id,
141 11
            'body' => $content,
142
        ]);
143
144 11
        $participants = $thread->participants()->get();
145 11
        $recipients = User::find($participants);
146
147 11
        Notification::send($recipients, new MessageCreated($message));
148
149 11
        return $message;
150
    }
151
152
    /**
153
     * Mark as read a tread of a user.
154
     *
155
     * @param Thread $thread
156
     * @param User $user
157
     * @return Participant
158
     */
159 1
    public function markAsRead(Thread $thread, User $user): Participant
160
    {
161 1
        $thread->markAsRead($user->id);
162 1
        return $thread->participants()->where('user_id', $user->id)->first();
163
    }
164
165
    /**
166
     * Mark as read all messages of a user.
167
     *
168
     * @param User $user
169
     * @return bool
170
     */
171 1
    public function markAsReadAll(User $user): bool
172
    {
173 1
        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...
174 1
            'user_id' => $user->id,
175 1
        ])->update([
176 1
            'last_read' => now(),
177
        ]);
178
    }
179
180
    /**
181
     * Mark as read all messages of a user.
182
     *
183
     * @param Thread $thread
184
     * @param User $user
185
     * @param bool $mark_as_read
186
     * @return Participant
187
     */
188 9
    public function addParticipant(Thread $thread, User $user, bool $mark_as_read = false): Participant
189
    {
190 9
        $return = $thread->participants()->updateOrCreate([
191 9
            'user_id' => $user->id,
192 9
            'thread_id' => $thread->id,
193
        ],
194 9
            $mark_as_read ? ['last_read' => now()] : []);
195
196 9
        $users = $thread->users()->get();
197
198 9
        $this->contactService->setContacts($users);
199
200 9
        Notification::send($users, new ParticipantCreated($return));
201
202 9
        return $return;
203
    }
204
}
205