From 1a539dfcc139b90f31e330b5ea037fc79c351408 Mon Sep 17 00:00:00 2001 From: overtrue Date: Wed, 6 Apr 2022 15:25:07 +0800 Subject: [PATCH] Added Fixed #167 --- .gitignore | 1 + README.md | 13 +++++++++++++ src/Followable.php | 38 ++++++++++++++++++++++++++++++-------- src/UserFollower.php | 1 + tests/FeatureTest.php | 29 +++++++++++++++++++++++++++-- tests/PrivacyTest.php | 25 +++++++++++++++++++++++++ tests/User.php | 2 +- 7 files changed, 98 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 3313884..74f462d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ composer.lock .phpunit.result.cache cghooks.lock +.php-cs-fixer.cache diff --git a/README.md b/README.md index 2d44524..c34bf77 100644 --- a/README.md +++ b/README.md @@ -76,12 +76,16 @@ $user1->areFollowingEachOther($user2); ```php $user->followings; +$user->approvedFollowings; +$user->notApprovedFollowings; ``` #### Get followers: ```php $user->followers; +$user->approvedFollowers; +$user->notApprovedFollowers; ``` ### Follow Requests @@ -101,22 +105,31 @@ public function needsToApproveFollowRequests() ```php // followings count $user->followings()->count(); +$user->approvedFollowings()->count(); +$user->notApprovedFollowings()->count(); // with query where $user->followings()->where('gender', 'female')->count(); // followers count $user->followers()->count(); +$user->approvedFollowers()->count(); +$user->notApprovedFollowers()->count(); ``` List with `*_count` attribute: ```php $users = User::withCount(['followings', 'followers'])->get(); +// or +$users = User::withCount(['approvedFollowings', 'approvedFollowers'])->get(); foreach($users as $user) { // $user->followings_count; // $user->followers_count; + // or + // $user->approved_followings_count; + // $user->approved_followers_count; } ``` diff --git a/src/Followable.php b/src/Followable.php index 861b875..799185a 100644 --- a/src/Followable.php +++ b/src/Followable.php @@ -3,10 +3,12 @@ namespace Overtrue\LaravelFollow; use Illuminate\Contracts\Pagination\Paginator; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; +use Illuminate\Pagination\CursorPaginator; use Illuminate\Pagination\LengthAwarePaginator; -use Illuminate\Support\Collection; -use Overtrue\LaravelFavorite\Traits\Favoriteable; +use Illuminate\Support\Enumerable; +use Illuminate\Support\LazyCollection; /** * @property \Illuminate\Database\Eloquent\Collection $followings @@ -29,6 +31,7 @@ public function needsToApproveFollowRequests(): bool */ public function follow($user): array { + /** @var \Illuminate\Database\Eloquent\Model|\Overtrue\LaravelFollow\Followable $user */ $isPending = $user->needsToApproveFollowRequests() ?: false; $this->followings()->attach($user, [ @@ -80,7 +83,6 @@ public function hasRequestedToFollow($user): bool $user = $user->getKey(); } - /* @var \Illuminate\Database\Eloquent\Model $this */ if ($this->relationLoaded('followings')) { return $this->followings ->where('pivot.accepted_at', '===', null) @@ -102,7 +104,6 @@ public function isFollowing($user): bool $user = $user->getKey(); } - /* @var \Illuminate\Database\Eloquent\Model $this */ if ($this->relationLoaded('followings')) { return $this->followings ->where('pivot.accepted_at', '!==', null) @@ -124,7 +125,6 @@ public function isFollowedBy($user): bool $user = $user->getKey(); } - /* @var \Illuminate\Database\Eloquent\Model $this */ if ($this->relationLoaded('followers')) { return $this->followers ->where('pivot.accepted_at', '!==', null) @@ -163,7 +163,6 @@ public function scopeOrderByFollowersCountAsc($query) public function followers(): \Illuminate\Database\Eloquent\Relations\BelongsToMany { - /* @var \Illuminate\Database\Eloquent\Model $this */ return $this->belongsToMany( __CLASS__, \config('follow.relation_table', 'user_follower'), @@ -174,7 +173,6 @@ public function followers(): \Illuminate\Database\Eloquent\Relations\BelongsToMa public function followings(): \Illuminate\Database\Eloquent\Relations\BelongsToMany { - /* @var \Illuminate\Database\Eloquent\Model $this */ return $this->belongsToMany( __CLASS__, \config('follow.relation_table', 'user_follower'), @@ -183,6 +181,26 @@ public function followings(): \Illuminate\Database\Eloquent\Relations\BelongsToM )->withPivot('accepted_at')->withTimestamps()->using(UserFollower::class); } + public function scopeApprovedFollowers(Builder $query): \Illuminate\Database\Eloquent\Relations\BelongsToMany + { + return $this->followers()->wherePivotNotNull('accepted_at'); + } + + public function scopeNotApprovedFollowers(Builder $query): \Illuminate\Database\Eloquent\Relations\BelongsToMany + { + return $this->followers()->wherePivotNull('accepted_at'); + } + + public function scopeApprovedFollowings(Builder $query): \Illuminate\Database\Eloquent\Relations\BelongsToMany + { + return $this->followings()->wherePivotNotNull('accepted_at'); + } + + public function scopeNotApprovedFollowings(Builder $query): \Illuminate\Database\Eloquent\Relations\BelongsToMany + { + return $this->followings()->wherePivotNull('accepted_at'); + } + public function attachFollowStatus($followables, callable $resolver = null) { $returnFirst = false; @@ -196,14 +214,18 @@ public function attachFollowStatus($followables, callable $resolver = null) $followables = $followables->getCollection(); break; case $followables instanceof Paginator: + case $followables instanceof CursorPaginator: $followables = \collect($followables->items()); break; + case $followables instanceof LazyCollection: + $followables = \collect(\iterator_to_array($followables->getIterator())); + break; case \is_array($followables): $followables = \collect($followables); break; } - \abort_if(!($followables instanceof Collection), 422, 'Invalid $followables type.'); + \abort_if(!($followables instanceof Enumerable), 422, 'Invalid $followables type.'); $followed = UserFollower::where('follower_id', $this->getKey())->get(); diff --git a/src/UserFollower.php b/src/UserFollower.php index 3ecfee8..67b4638 100644 --- a/src/UserFollower.php +++ b/src/UserFollower.php @@ -2,6 +2,7 @@ namespace Overtrue\LaravelFollow; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\Pivot; use Overtrue\LaravelFollow\Events\Followed; use Overtrue\LaravelFollow\Events\Unfollowed; diff --git a/tests/FeatureTest.php b/tests/FeatureTest.php index 346a4f1..ee43e4a 100644 --- a/tests/FeatureTest.php +++ b/tests/FeatureTest.php @@ -3,11 +3,9 @@ namespace Tests; use Illuminate\Support\Carbon; -use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Event; use Overtrue\LaravelFollow\Events\Followed; use Overtrue\LaravelFollow\Events\Unfollowed; -use Overtrue\LaravelFollow\UserFollower; class FeatureTest extends TestCase { @@ -214,6 +212,33 @@ function () use ($user1, $users) { $this->assertTrue($users[2]->has_followed); $this->assertTrue($users[3]->has_followed); + // paginator + $users = User::paginate(); + $user1->attachFollowStatus($users); + + $users = $users->toArray()['data']; + $this->assertFalse($users[0]['has_followed']); + $this->assertTrue($users[1]['has_followed']); + $this->assertTrue($users[2]['has_followed']); + $this->assertTrue($users[3]['has_followed']); + + // cursor paginator + $users = User::cursorPaginate(); + $user1->attachFollowStatus($users); + + $users = $users->toArray()['data']; + $this->assertFalse($users[0]['has_followed']); + $this->assertTrue($users[1]['has_followed']); + $this->assertTrue($users[2]['has_followed']); + $this->assertTrue($users[3]['has_followed']); + + // cursor + $users = User::cursor(); + $users = $user1->attachFollowStatus($users)->toArray(); + $this->assertFalse($users[0]['has_followed']); + $this->assertTrue($users[1]['has_followed']); + $this->assertTrue($users[2]['has_followed']); + $this->assertTrue($users[3]['has_followed']); // with custom resolver $users = \collect(['creator' => $user2], ['creator' => $user3], ['creator' => $user4]); diff --git a/tests/PrivacyTest.php b/tests/PrivacyTest.php index c3e98db..24c9878 100644 --- a/tests/PrivacyTest.php +++ b/tests/PrivacyTest.php @@ -64,4 +64,29 @@ public function test_following_private_user_sets_request_pending_with_eager_load $this->assertTrue($user1->hasRequestedToFollow($user2)); $this->assertFalse($user2->isFollowedBy($user1)); } + + public function test_approved_scopes() + { + $user1 = User::create(['name' => 'user1']); + $user2 = User::create(['name' => 'user2', 'private' => true]); + + $user1->follow($user2); + + $this->assertCount(1, $user1->followings()->get()); + $this->assertCount(0, $user1->approvedFollowings()->get()); + $this->assertCount(1, $user1->notApprovedFollowings()->get()); + + $this->assertCount(1, $user2->followers()->get()); + $this->assertCount(0, $user2->approvedFollowers()->get()); + $this->assertCount(1, $user2->notApprovedFollowers()->get()); + + $user2->acceptFollowRequestFrom($user1); + + $this->assertCount(1, $user1->followings()->get()); + $this->assertCount(1, $user1->approvedFollowings()->get()); + $this->assertCount(0, $user1->notApprovedFollowings()->get()); + $this->assertCount(1, $user2->followers()->get()); + $this->assertCount(1, $user2->approvedFollowers()->get()); + $this->assertCount(0, $user2->notApprovedFollowers()->get()); + } } diff --git a/tests/User.php b/tests/User.php index 262c047..751bc07 100644 --- a/tests/User.php +++ b/tests/User.php @@ -18,7 +18,7 @@ class User extends Model /** * @return bool */ - public function needsToApproveFollowRequests() + public function needsToApproveFollowRequests(): bool { return $this->private ?? false; }