Completed
Push — master ( 423a77...7e6e45 )
by Christopher
13:19
created

Friendable::sendFriendRequestTo()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 43
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 6.0029

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 43
rs 8.439
ccs 22
cts 23
cp 0.9565
cc 6
eloc 21
nc 5
nop 1
crap 6.0029
1
<?php
2
3
/**
4
 * This file is part of Friends.
5
 *
6
 * (c) Christopher Lass <[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
namespace Arubacao\Friends\Traits;
12
13
use Arubacao\Friends\Status;
14
use Illuminate\Support\Facades\Config;
15
16
trait Friendable
17
{
18
    /**
19
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
20
     */
21 22 View Code Duplication
    public function friends_i_am_sender()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
22
    {
23 22
        return $this->belongsToMany(
0 ignored issues
show
Bug introduced by
It seems like belongsToMany() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
24 22
            Config::get('friends.user_model'),
25 22
            'friends',
26 22
            'sender_id', 'recipient_id')
27 22
            ->withTimestamps()
28 22
            ->withPivot([
29 22
                'status',
30 22
            ])
31 22
            ->orderBy('updated_at', 'desc');
32
    }
33
34
    /**
35
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
36
     */
37 22 View Code Duplication
    public function friends_i_am_recipient()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
38
    {
39 22
        return $this->belongsToMany(
0 ignored issues
show
Bug introduced by
It seems like belongsToMany() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
40 22
            Config::get('friends.user_model'),
41 22
            'friends',
42 22
            'recipient_id', 'sender_id')
43 22
            ->withTimestamps()
44 22
            ->withPivot([
45 22
                'status',
46 22
            ])
47 22
            ->orderBy('updated_at', 'desc');
48
    }
49
50
    /**
51
     * @return \Illuminate\Database\Eloquent\Builder
52
     */
53 1
    public function scopeIncludeRelationshipsWith($query, $user)
54
    {
55 1
        $userId = $this->retrieveUserId($user);
56
57 1
        return $query->with([
58
            'friends_i_am_sender' => function ($queryIn) use ($userId) {
59 1
                $queryIn->where('recipient_id', $userId)
60 1
                    ->get();
61 1
            },
62
            'friends_i_am_recipient' => function ($queryIn) use ($userId) {
63 1
                $queryIn->where('sender_id', $userId)
64 1
                    ->get();
65 1
            },
66 1
        ]);
67
    }
68
69
    /**
70
     * @return \Illuminate\Database\Eloquent\Collection
71
     */
72 10
    public function friends()
73
    {
74 10
        $me = $this->with([
0 ignored issues
show
Bug introduced by
It seems like with() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
75
            'friends_i_am_sender' => function ($query) {
76 10
                $query->where('status', Status::ACCEPTED)
77 10
                    ->get();
78 10
            },
79
            'friends_i_am_recipient' => function ($query) {
80 10
                $query->where('status', Status::ACCEPTED)
81 10
                    ->get();
82 10
            },
83 10
        ])
84 10
            ->where('id', '=', $this->getKey())
0 ignored issues
show
Bug introduced by
It seems like getKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
85 10
            ->first();
86
87 10
        $friends = $this->mergedFriends($me);
88
89 10
        return $friends;
90
    }
91
92
    /**
93
     * @return \Illuminate\Database\Eloquent\Collection
94
     */
95 2 View Code Duplication
    public function incoming_friends()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
96
    {
97 2
        $me = $this->with([
0 ignored issues
show
Bug introduced by
It seems like with() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
98 2
            'friends_i_am_recipient' => function ($query) {
99 2
                $query->where('status', Status::PENDING)
100 2
                    ->get();
101 2
            },
102 2
        ])
103 2
            ->where('id', '=', $this->getKey())
0 ignored issues
show
Bug introduced by
It seems like getKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
104 2
            ->first();
105
106 2
        return $me->friends_i_am_recipient;
107
    }
108
109
    /**
110
     * @return \Illuminate\Database\Eloquent\Collection
111
     */
112 11 View Code Duplication
    public function any_friends()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
113
    {
114 11
        $me = $this->with([
0 ignored issues
show
Bug introduced by
It seems like with() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
115 11
            'friends_i_am_sender',
116 11
            'friends_i_am_recipient',
117 11
        ])
118 11
            ->where('id', '=', $this->getKey())
0 ignored issues
show
Bug introduced by
It seems like getKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
119 11
            ->first();
120
121 11
        $any_friends = $this->mergedFriends($me);
122
123 11
        return $any_friends;
124
    }
125
126
    /**
127
     * Alias to eloquent many-to-many relation's attach() method.
128
     *
129
     * @param int|User $user
130
     * @return bool
131
     */
132 21
    public function sendFriendRequestTo($user)
133
    {
134 21
        $userId = $this->retrieveUserId($user);
135
136 21
        if ($userId == $this->getKey()) {
0 ignored issues
show
Bug introduced by
It seems like getKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
137
            // Method not allowed on self
138 1
            return false;
139
        }
140
141 20
        $relationship = $this->getRelationshipWith($userId, [
142 20
            Status::PENDING,
143 20
            Status::ACCEPTED,
144 20
        ]);
145
146 20
        if (! is_null($relationship)) {
147 4
            if ($relationship->pivot->status === Status::ACCEPTED) {
148
                // Already friends
149
                return false;
150
            }
151 4
            if ($relationship->pivot->status == Status::PENDING &&
152 4
                $relationship->pivot->recipient_id == $this->getKey()) {
0 ignored issues
show
Bug introduced by
It seems like getKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
153
                // Recipient already sent a friend request
154
                // Accept pending friend request
155 1
                $relationship->pivot->status = Status::ACCEPTED;
156 1
                $relationship->pivot->save();
157
                /* @todo: fire event friend request accepted */
158 1
                $this->reload();
159
160 1
                return true;
161
            }
162
163 3
            return false;
164
        }
165
166 20
        $this->friends_i_am_sender()->attach($userId, [
167 20
            'status' => Status::PENDING,
168 20
        ]);
169
        /* @todo: fire event friend request sent */
170
171 20
        $this->reload();
172
173 20
        return true;
174
    }
175
176
    /**
177
     * @param int|User $user
178
     * @return bool
179
     */
180 14 View Code Duplication
    public function acceptFriendRequestFrom($user)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181
    {
182 14
        $userId = $this->retrieveUserId($user);
183
184 14
        if ($userId == $this->getKey()) {
0 ignored issues
show
Bug introduced by
It seems like getKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
185
            // Method not allowed on self
186
            return false;
187
        }
188
189 14
        $relationship = $this->getPendingRequestFrom($userId);
190
191 14
        if (! is_null($relationship)) {
192 13
            $relationship->pivot->status = Status::ACCEPTED;
193 13
            $relationship->pivot->save();
194
            /* @todo: fire event friend request accepted */
195 13
            $this->reload();
196
197 13
            return true;
198
        }
199
200 1
        return false;
201
    }
202
203
    /**
204
     * @param int|User $user
205
     * @return bool
206
     */
207 2 View Code Duplication
    public function denyFriendRequestFrom($user)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
208
    {
209 2
        $userId = $this->retrieveUserId($user);
210
211 2
        if ($userId == $this->getKey()) {
0 ignored issues
show
Bug introduced by
It seems like getKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
212
            // Method not allowed on self
213
            return false;
214
        }
215
216 2
        $relationship = $this->getPendingRequestFrom($userId);
217
218 2
        if (! is_null($relationship)) {
219 2
            $relationship->pivot->delete();
220
            /* @todo: fire event friend request denied */
221 2
            $this->reload();
222
223 2
            return true;
224
        }
225
226
        return false;
227
    }
228
229
    /**
230
     * @param int|User $user
231
     * @return bool
232
     */
233 1
    public function deleteFriend($user)
234
    {
235 1
        $userId = $this->retrieveUserId($user);
236
237 1
        if ($userId == $this->getKey()) {
0 ignored issues
show
Bug introduced by
It seems like getKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
238
            // Method not allowed on self
239
            return false;
240
        }
241
242 1
        while ($relationship = $this->getRelationshipWith($userId, [
243 1
            Status::ACCEPTED,
244 1
            Status::PENDING,
245 1
        ])) {
246 1
            $relationship->pivot->delete();
247
            /* @todo: fire event friend deleted */
248 1
        }
249 1
        $this->reload();
250
251 1
        return true;
252
    }
253
254
    /**
255
     * @param int|array|User $user
256
     * @return bool
257
     */
258 2
    public function isFriendWith($user)
259
    {
260 2
        $userId = $this->retrieveUserId($user);
261
262 2
        return $this->hasRelationshipWith($userId, [Status::ACCEPTED]);
263
    }
264
265
    /**
266
     * @param int|array|User $user
267
     * @param array $status
268
     * @return bool
269
     */
270 2
    public function hasRelationshipWith($user, $status)
271
    {
272 2
        $userId = $this->retrieveUserId($user);
273
274 2
        $relationship = $this->getRelationshipWith($userId, $status);
275
276 2
        return (is_null($relationship)) ? false : true;
277
    }
278
279
    /**
280
     * @param int|array|User $user
281
     * @param array $status
282
     * @return mixed
283
     */
284 20
    public function getRelationshipWith($user, $status)
285
    {
286 20
        $userId = $this->retrieveUserId($user);
287
288 20
        if ($userId == $this->getKey()) {
0 ignored issues
show
Bug introduced by
It seems like getKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
289
            // Method not allowed on self
290
            return;
291
        }
292
293 20
        $attempt1 = $this->friends_i_am_recipient()
294 20
            ->wherePivotIn('status', $status)
295 20
            ->wherePivot('sender_id', $userId)
296 20
            ->first();
297
298 20
        if (! is_null($attempt1)) {
299 3
            return $attempt1;
300
        }
301
302 20
        $attempt2 = $this->friends_i_am_sender()
303 20
            ->wherePivotIn('status', $status)
304 20
            ->wherePivot('recipient_id', $userId)
305 20
            ->first();
306
307 20
        if (! is_null($attempt2)) {
308 4
            return $attempt2;
309
        }
310 20
    }
311
312
    /**
313
     * @param int|array|User $user
314
     * @return bool
315
     */
316 4
    public function hasPendingRequestFrom($user)
317
    {
318 4
        $userId = $this->retrieveUserId($user);
319
320 4
        if ($userId == $this->getKey()) {
0 ignored issues
show
Bug introduced by
It seems like getKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
321
            // Method not allowed on self
322
            return false;
323
        }
324
325 4
        $relationship = $this->getPendingRequestFrom($userId);
326
327 4
        if (! is_null($relationship)) {
328 2
            return true;
329
        }
330
331 4
        return false;
332
    }
333
334
    /**
335
     * @param int|array|User $user
336
     * @return int|null
337
     */
338 25
    private function retrieveUserId($user)
339
    {
340 25
        if (is_object($user)) {
341 23
            return $user->getKey();
342
        }
343 22
        if (is_array($user) && isset($user['id'])) {
344 1
            return $user['id'];
345
        }
346
347 21
        return $user;
348
    }
349
350
    /**
351
     * @param int $userId
352
     * @return mixed
353
     */
354 17
    private function getPendingRequestFrom($userId)
355
    {
356 17
        return $this->friends_i_am_recipient()
357 17
            ->wherePivot('status', Status::PENDING)
358 17
            ->wherePivot('sender_id', $userId)
359 17
            ->first();
360
    }
361
362
    /**
363
     * Eager load relations on the model.
364
     */
365 20
    private function reload()
366
    {
367 20
        $this->load('friends_i_am_recipient', 'friends_i_am_sender');
0 ignored issues
show
Bug introduced by
It seems like load() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
368 20
    }
369
370
    /**
371
     * @param User $me
372
     * @return \Illuminate\Database\Eloquent\Collection
373
     */
374 18
    private function mergedFriends($me)
375
    {
376 18
        $friends = collect([]);
377 18
        $friends->push($me->friends_i_am_sender);
378 18
        $friends->push($me->friends_i_am_recipient);
379 18
        $friends = $friends->flatten();
380
381 18
        return $friends;
382
    }
383
}
384