guard($actor, $collection); $inserted = false; DB::transaction(function () use ($actor, $collection, &$inserted): void { $rows = DB::table('collection_follows')->insertOrIgnore([ 'collection_id' => $collection->id, 'user_id' => $actor->id, 'created_at' => now(), ]); if ($rows === 0) { return; } $inserted = true; DB::table('collections') ->where('id', $collection->id) ->update([ 'followers_count' => DB::raw('followers_count + 1'), 'last_activity_at' => now(), 'updated_at' => now(), ]); }); if ($inserted) { event(new CollectionFollowed($collection->fresh(), (int) $actor->id)); } return $inserted; } public function unfollow(User $actor, Collection $collection): bool { $deleted = false; DB::transaction(function () use ($actor, $collection, &$deleted): void { $rows = DB::table('collection_follows') ->where('collection_id', $collection->id) ->where('user_id', $actor->id) ->delete(); if ($rows === 0) { return; } $deleted = true; DB::table('collections') ->where('id', $collection->id) ->where('followers_count', '>', 0) ->update([ 'followers_count' => DB::raw('followers_count - 1'), 'updated_at' => now(), ]); }); if ($deleted) { event(new CollectionUnfollowed($collection->fresh(), (int) $actor->id)); } return $deleted; } public function isFollowing(?User $viewer, Collection $collection): bool { if (! $viewer) { return false; } return DB::table('collection_follows') ->where('collection_id', $collection->id) ->where('user_id', $viewer->id) ->exists(); } private function guard(User $actor, Collection $collection): void { if (! $collection->isPubliclyEngageable()) { throw ValidationException::withMessages([ 'collection' => 'Only public collections can be followed.', ]); } if ($collection->isOwnedBy($actor)) { throw ValidationException::withMessages([ 'collection' => 'You cannot follow your own collection.', ]); } } }