Extract following-ids lookup into FollowerService::getFollowingIds

The Cache::remember('profile:following:'.$pid, ...) block that plucks
following_id and appends the caller's own id was copy-pasted across four
call sites, with inconsistent TTLs (1440 minutes vs 1209600 seconds).

Add FollowerService::getFollowingIds($pid), which owns the cache key that
add()/remove() already invalidate, and use it from InternalApiController,
PublicApiController, ApiV1Controller and HashtagUnfollowPipeline. Removes
the now-unused Follower/Cache imports left behind.

Adds a test covering the followed-ids-plus-self result and the
follows-nobody case.
pull/7045/head
Your Name 3 weeks ago
parent ed07f9bfec
commit 667f6e2fc9

@ -2802,11 +2802,7 @@ class ApiV1Controller extends Controller
return $this->json($res->toArray(), 200, $headers);
}
$following = Cache::remember('profile:following:'.$pid, 1209600, function () use ($pid) {
$following = Follower::whereProfileId($pid)->pluck('following_id');
return $following->push($pid)->toArray();
});
$following = FollowerService::getFollowingIds($pid);
$muted = UserFilterService::mutes($pid);

@ -7,7 +7,6 @@ use App\Models\AccountInterstitial;
use App\Models\Bookmark;
use App\Models\DirectMessage;
use App\Models\DiscoverCategory;
use App\Models\Follower;
use App\Models\Profile;
use App\Models\Status;
use App\Models\User;
@ -23,7 +22,6 @@ use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;
use Illuminate\Validation\Rule;
use League\Fractal;
@ -312,20 +310,12 @@ class InternalApiController extends Controller
return response()->json([]);
}
$pid = $request->user()->profile->id;
$following = Cache::remember('profile:following:'.$pid, now()->addMinutes(1440), function () use ($pid) {
$following = Follower::whereProfileId($pid)->pluck('following_id');
return $following->push($pid)->toArray();
});
$following = FollowerService::getFollowingIds($pid);
$visibility = in_array($profile->id, $following) == true ? ['public', 'unlisted', 'private'] : [];
} else {
if ($request->user() !== null) {
$pid = $request->user()->profile->id;
$following = Cache::remember('profile:following:'.$pid, now()->addMinutes(1440), function () use ($pid) {
$following = Follower::whereProfileId($pid)->pluck('following_id');
return $following->push($pid)->toArray();
});
$following = FollowerService::getFollowingIds($pid);
$visibility = in_array($profile->id, $following) == true ? ['public', 'unlisted', 'private'] : ['public', 'unlisted'];
} else {
$visibility = ['public', 'unlisted'];

@ -2,7 +2,6 @@
namespace App\Http\Controllers;
use App\Models\Follower;
use App\Models\Profile;
use App\Models\Status;
use App\Services\AccountService;
@ -390,11 +389,7 @@ class PublicApiController extends Controller
$pid = $user->profile_id;
$following = Cache::remember('profile:following:'.$pid, 1209600, function () use ($pid) {
$following = Follower::whereProfileId($pid)->pluck('following_id');
return $following->push($pid)->toArray();
});
$following = FollowerService::getFollowingIds($pid);
$filtered = $user ? UserFilterService::filters($user->profile_id) : [];
$types = ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'];

@ -2,8 +2,8 @@
namespace App\Jobs\HomeFeedPipeline;
use App\Models\Follower;
use App\Models\Hashtag;
use App\Services\FollowerService;
use App\Services\HomeTimelineService;
use App\Services\StatusService;
use Illuminate\Bus\Queueable;
@ -11,7 +11,6 @@ use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class HashtagUnfollowPipeline implements ShouldQueue
@ -76,11 +75,7 @@ class HashtagUnfollowPipeline implements ShouldQueue
$statusIds = HomeTimelineService::get($pid, 0, -1);
$followingIds = Cache::remember('profile:following:'.$pid, 1209600, function () use ($pid) {
$following = Follower::whereProfileId($pid)->pluck('following_id');
return $following->push($pid)->toArray();
});
$followingIds = FollowerService::getFollowingIds($pid);
foreach ($statusIds as $id) {
$status = StatusService::get($id, false);

@ -79,6 +79,23 @@ class FollowerService
return Redis::zrevrange(self::FOLLOWING_KEY.$id, $start, $stop);
}
/**
* Return the profile ids a profile follows, including the profile's own
* id, as an array. Cached under the 'profile:following:{pid}' key, which
* is invalidated by add()/remove().
*
* @return array<int, int>
*/
public static function getFollowingIds($pid)
{
return Cache::remember('profile:following:'.$pid, 1209600, function () use ($pid) {
return Follower::whereProfileId($pid)
->pluck('following_id')
->push($pid)
->toArray();
});
}
public static function followersPaginate($id, $page = 1, $limit = 10)
{
$start = $page == 1 ? 0 : $page * $limit - $limit;

@ -0,0 +1,55 @@
<?php
use App\Models\Follower;
use App\Models\User;
use App\Services\FollowerService;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Illuminate\Support\Facades\Cache;
uses(LazilyRefreshDatabase::class);
/*
|--------------------------------------------------------------------------
| FollowerService::getFollowingIds
|--------------------------------------------------------------------------
|
| Extracted from four inline copies of the same
| Cache::remember('profile:following:'.$pid, ...) pattern. Verifies the
| method returns the followed profile ids plus the caller's own id.
|
*/
beforeEach(function () {
Cache::flush();
});
it('returns followed ids plus the callers own id', function () {
$user = User::factory()->create();
$user->refresh();
$a = User::factory()->create();
$a->refresh();
$b = User::factory()->create();
$b->refresh();
foreach ([$a->profile_id, $b->profile_id] as $targetId) {
$f = new Follower;
$f->profile_id = $user->profile_id;
$f->following_id = $targetId;
$f->save();
}
$ids = FollowerService::getFollowingIds($user->profile_id);
expect($ids)->toContain($a->profile_id)
->toContain($b->profile_id)
->toContain($user->profile_id);
});
it('returns only the callers own id when following nobody', function () {
$user = User::factory()->create();
$user->refresh();
$ids = FollowerService::getFollowingIds($user->profile_id);
expect($ids)->toBe([$user->profile_id]);
});
Loading…
Cancel
Save