Test Failed
Push — master ( d40ff9...52bb0d )
by Carlos
08:40
created

Followable::attachFollowStatus()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 34
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 23
c 1
b 0
f 0
nc 10
nop 2
dl 0
loc 34
rs 8.4444
1
<?php
2
3
namespace Overtrue\LaravelFollow;
4
5
use Illuminate\Contracts\Pagination\Paginator;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Pagination\LengthAwarePaginator;
8
use Illuminate\Support\Collection;
9
use Overtrue\LaravelFavorite\Traits\Favoriteable;
0 ignored issues
show
Bug introduced by
The type Overtrue\LaravelFavorite\Traits\Favoriteable was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
11
/**
12
 * @property \Illuminate\Database\Eloquent\Collection $followings
13
 * @property \Illuminate\Database\Eloquent\Collection $followers
14
 */
15
trait Followable
16
{
17
    /**
18
     * @return bool
19
     */
20
    public function needsToApproveFollowRequests(): bool
21
    {
22
        return false;
23
    }
24
25
    /**
26
     * @param \Illuminate\Database\Eloquent\Model|int $user
27
     *
28
     * @return array
29
     */
30
    public function follow($user): array
31
    {
32
        $isPending = $user->needsToApproveFollowRequests() ?: false;
33
34
        $this->followings()->attach($user, [
35
            'accepted_at' => $isPending ? null : now()
36
        ]);
37
38
        return ['pending' => $isPending];
39
    }
40
41
    /**
42
     * @param \Illuminate\Database\Eloquent\Model|int $user
43
     */
44
    public function unfollow($user)
45
    {
46
        $this->followings()->detach($user);
47
    }
48
49
    /**
50
     * @param \Illuminate\Database\Eloquent\Model|int $user
51
     *
52
     */
53
    public function toggleFollow($user)
54
    {
55
        $this->isFollowing($user) ? $this->unfollow($user) : $this->follow($user);
56
    }
57
58
    /**
59
     * @param \Illuminate\Database\Eloquent\Model|int $user
60
     */
61
    public function rejectFollowRequestFrom($user)
62
    {
63
        $this->followers()->detach($user);
64
    }
65
66
    /**
67
     * @param \Illuminate\Database\Eloquent\Model|int $user
68
     */
69
    public function acceptFollowRequestFrom($user)
70
    {
71
        $this->followers()->updateExistingPivot($user, ['accepted_at' => now()]);
72
    }
73
74
    /**
75
     * @param \Illuminate\Database\Eloquent\Model|int $user
76
     */
77
    public function hasRequestedToFollow($user): bool
78
    {
79
        if ($user instanceof Model) {
80
            $user = $user->getKey();
81
        }
82
83
        /* @var \Illuminate\Database\Eloquent\Model $this */
84
        if ($this->relationLoaded('followings')) {
85
            return $this->followings
86
                ->where('pivot.accepted_at', '===', null)
0 ignored issues
show
Bug introduced by
The method where() does not exist on null. ( Ignorable by Annotation )

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

86
                ->/** @scrutinizer ignore-call */ where('pivot.accepted_at', '===', null)

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
87
                ->contains($user);
88
        }
89
90
        return $this->followings()
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->followings...ame(), $user)->exists() could return the type Illuminate\Database\Eloquent\Builder which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
91
            ->wherePivot('accepted_at', null)
92
            ->where($this->getQualifiedKeyName(), $user)
93
            ->exists();
94
    }
95
96
    /**
97
     * @param \Illuminate\Database\Eloquent\Model|int $user
98
     */
99
    public function isFollowing($user): bool
100
    {
101
        if ($user instanceof Model) {
102
            $user = $user->getKey();
103
        }
104
105
        /* @var \Illuminate\Database\Eloquent\Model $this */
106
        if ($this->relationLoaded('followings')) {
107
            return $this->followings
108
                ->where('pivot.accepted_at', '!==', null)
109
                ->contains($user);
110
        }
111
112
        return $this->followings()
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->followings...ame(), $user)->exists() could return the type Illuminate\Database\Eloquent\Builder which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
113
            ->wherePivot('accepted_at', '!=', null)
114
            ->where($this->getQualifiedKeyName(), $user)
115
            ->exists();
116
    }
117
118
    /**
119
     * @param \Illuminate\Database\Eloquent\Model|int $user
120
     */
121
    public function isFollowedBy($user): bool
122
    {
123
        if ($user instanceof Model) {
124
            $user = $user->getKey();
125
        }
126
127
        /* @var \Illuminate\Database\Eloquent\Model $this */
128
        if ($this->relationLoaded('followers')) {
129
            return $this->followers
130
                ->where('pivot.accepted_at', '!==', null)
0 ignored issues
show
Bug introduced by
The method where() does not exist on null. ( Ignorable by Annotation )

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

130
                ->/** @scrutinizer ignore-call */ where('pivot.accepted_at', '!==', null)

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
131
                ->contains($user);
132
        }
133
134
        return $this->followers()
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->followers(...ame(), $user)->exists() could return the type Illuminate\Database\Eloquent\Builder which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
135
            ->wherePivot('accepted_at', '!=', null)
136
            ->where($this->getQualifiedKeyName(), $user)
137
            ->exists();
138
    }
139
140
    /**
141
     * @param \Illuminate\Database\Eloquent\Model|int $user
142
     */
143
    public function areFollowingEachOther($user): bool
144
    {
145
        /* @var \Illuminate\Database\Eloquent\Model $user*/
146
        return $this->isFollowing($user) && $this->isFollowedBy($user);
147
    }
148
149
    public function followers(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
150
    {
151
        /* @var \Illuminate\Database\Eloquent\Model $this */
152
        return $this->belongsToMany(
153
            __CLASS__,
154
            \config('follow.relation_table', 'user_follower'),
155
            'following_id',
156
            'follower_id'
157
        )->withPivot('accepted_at')->withTimestamps()->using(UserFollower::class);
158
    }
159
160
    public function followings(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
161
    {
162
        /* @var \Illuminate\Database\Eloquent\Model $this */
163
        return $this->belongsToMany(
164
            __CLASS__,
165
            \config('follow.relation_table', 'user_follower'),
166
            'follower_id',
167
            'following_id'
168
        )->withPivot('accepted_at')->withTimestamps()->using(UserFollower::class);
169
    }
170
171
    public function attachFollowStatus($followables, callable $resolver = null)
172
    {
173
        $returnFirst = false;
174
175
        switch (true) {
176
            case $followables instanceof Model:
177
                $returnFirst = true;
178
                $followables = \collect([$followables]);
179
                break;
180
            case $followables instanceof LengthAwarePaginator:
181
                $followables = $followables->getCollection();
182
                break;
183
            case $followables instanceof Paginator:
184
                $followables = \collect($followables->items());
185
                break;
186
            case \is_array($followables):
187
                $followables = \collect($followables);
188
                break;
189
        }
190
191
        \abort_if(!($followables instanceof Collection), 422, 'Invalid $followables type.');
192
193
        $followed = $this->followings()->wherePivot('accepted_at', '!=', null)->pluck('following_id');
194
195
        $followables->map(function ($followable) use ($followed, $resolver) {
196
            $resolver = $resolver ?? fn ($m) => $m;
197
            $followable = $resolver($followable);
198
199
            if ($followable && \in_array(Followable::class, \class_uses($followable))) {
200
                $followable->setAttribute('has_followed', $followed->contains($followable->getKey()));
201
            }
202
        });
203
204
        return $returnFirst ? $followables->first() : $followables;
205
    }
206
}
207