Issues (10)

src/Followable.php (5 issues)

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
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
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()
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()
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
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()
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 scopeOrderByFollowersCount($query, string $direction = 'desc')
150
    {
151
        return $query->withCount('followers')->orderBy('followers_count', $direction);
152
    }
153
154
    public function scopeOrderByFollowersCountDesc($query)
155
    {
156
        return $this->scopeOrderByFollowersCount($query, 'desc');
157
    }
158
159
    public function scopeOrderByFollowersCountAsc($query)
160
    {
161
        return $this->scopeOrderByFollowersCount($query, 'asc');
162
    }
163
164
    public function followers(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
165
    {
166
        /* @var \Illuminate\Database\Eloquent\Model $this */
167
        return $this->belongsToMany(
168
            __CLASS__,
169
            \config('follow.relation_table', 'user_follower'),
170
            'following_id',
171
            'follower_id'
172
        )->withPivot('accepted_at')->withTimestamps()->using(UserFollower::class);
173
    }
174
175
    public function followings(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
176
    {
177
        /* @var \Illuminate\Database\Eloquent\Model $this */
178
        return $this->belongsToMany(
179
            __CLASS__,
180
            \config('follow.relation_table', 'user_follower'),
181
            'follower_id',
182
            'following_id'
183
        )->withPivot('accepted_at')->withTimestamps()->using(UserFollower::class);
184
    }
185
186
    public function attachFollowStatus($followables, callable $resolver = null)
187
    {
188
        $returnFirst = false;
189
190
        switch (true) {
191
            case $followables instanceof Model:
192
                $returnFirst = true;
193
                $followables = \collect([$followables]);
194
                break;
195
            case $followables instanceof LengthAwarePaginator:
196
                $followables = $followables->getCollection();
197
                break;
198
            case $followables instanceof Paginator:
199
                $followables = \collect($followables->items());
200
                break;
201
            case \is_array($followables):
202
                $followables = \collect($followables);
203
                break;
204
        }
205
206
        \abort_if(!($followables instanceof Collection), 422, 'Invalid $followables type.');
207
208
        $followed = UserFollower::where('follower_id', $this->getKey())->get();
0 ignored issues
show
It seems like getKey() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

208
        $followed = UserFollower::where('follower_id', $this->/** @scrutinizer ignore-call */ getKey())->get();
Loading history...
209
210
        $followables->map(function ($followable) use ($followed, $resolver) {
211
            $resolver = $resolver ?? fn ($m) => $m;
212
            $followable = $resolver($followable);
213
214
            if ($followable && \in_array(Followable::class, \class_uses($followable))) {
215
                $item = $followed->where('following_id', $followable->getKey())->first();
216
                $followable->setAttribute('has_followed', !!$item);
217
                $followable->setAttribute('followed_at', $item ? $item->created_at : null);
218
                $followable->setAttribute('follow_accepted_at', $item ? $item->accepted_at : null);
0 ignored issues
show
The property accepted_at does not seem to exist on Overtrue\LaravelFollow\UserFollower. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
219
            }
220
        });
221
222
        return $returnFirst ? $followables->first() : $followables;
223
    }
224
}
225