messages implemented
This commit is contained in:
144
app/Services/FollowService.php
Normal file
144
app/Services/FollowService.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* FollowService
|
||||
*
|
||||
* Manages follow / unfollow operations on the user_followers table.
|
||||
* Convention:
|
||||
* follower_id = the user doing the following
|
||||
* user_id = the user being followed
|
||||
*
|
||||
* Counters in user_statistics are kept in sync atomically inside a transaction.
|
||||
*/
|
||||
final class FollowService
|
||||
{
|
||||
/**
|
||||
* Follow $targetId on behalf of $actorId.
|
||||
*
|
||||
* @return bool true if a new follow was created, false if already following
|
||||
*
|
||||
* @throws \InvalidArgumentException if self-follow attempted
|
||||
*/
|
||||
public function follow(int $actorId, int $targetId): bool
|
||||
{
|
||||
if ($actorId === $targetId) {
|
||||
throw new \InvalidArgumentException('Cannot follow yourself.');
|
||||
}
|
||||
|
||||
$inserted = false;
|
||||
|
||||
DB::transaction(function () use ($actorId, $targetId, &$inserted) {
|
||||
$rows = DB::table('user_followers')->insertOrIgnore([
|
||||
'user_id' => $targetId,
|
||||
'follower_id' => $actorId,
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
if ($rows === 0) {
|
||||
// Already following – nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
$inserted = true;
|
||||
|
||||
// Increment following_count for actor, followers_count for target
|
||||
$this->incrementCounter($actorId, 'following_count');
|
||||
$this->incrementCounter($targetId, 'followers_count');
|
||||
});
|
||||
|
||||
return $inserted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unfollow $targetId on behalf of $actorId.
|
||||
*
|
||||
* @return bool true if a follow row was removed, false if wasn't following
|
||||
*/
|
||||
public function unfollow(int $actorId, int $targetId): bool
|
||||
{
|
||||
if ($actorId === $targetId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$deleted = false;
|
||||
|
||||
DB::transaction(function () use ($actorId, $targetId, &$deleted) {
|
||||
$rows = DB::table('user_followers')
|
||||
->where('user_id', $targetId)
|
||||
->where('follower_id', $actorId)
|
||||
->delete();
|
||||
|
||||
if ($rows === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$deleted = true;
|
||||
|
||||
$this->decrementCounter($actorId, 'following_count');
|
||||
$this->decrementCounter($targetId, 'followers_count');
|
||||
});
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle follow state. Returns the new following state.
|
||||
*/
|
||||
public function toggle(int $actorId, int $targetId): bool
|
||||
{
|
||||
if ($this->isFollowing($actorId, $targetId)) {
|
||||
$this->unfollow($actorId, $targetId);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->follow($actorId, $targetId);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isFollowing(int $actorId, int $targetId): bool
|
||||
{
|
||||
return DB::table('user_followers')
|
||||
->where('user_id', $targetId)
|
||||
->where('follower_id', $actorId)
|
||||
->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Current followers_count for a user (from cached column, not live count).
|
||||
*/
|
||||
public function followersCount(int $userId): int
|
||||
{
|
||||
return (int) DB::table('user_statistics')
|
||||
->where('user_id', $userId)
|
||||
->value('followers_count');
|
||||
}
|
||||
|
||||
// ─── Private helpers ─────────────────────────────────────────────────────
|
||||
|
||||
private function incrementCounter(int $userId, string $column): void
|
||||
{
|
||||
DB::table('user_statistics')->updateOrInsert(
|
||||
['user_id' => $userId],
|
||||
[
|
||||
$column => DB::raw("COALESCE({$column}, 0) + 1"),
|
||||
'updated_at' => now(),
|
||||
'created_at' => now(), // ignored on update
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
private function decrementCounter(int $userId, string $column): void
|
||||
{
|
||||
DB::table('user_statistics')
|
||||
->where('user_id', $userId)
|
||||
->where($column, '>', 0)
|
||||
->update([
|
||||
$column => DB::raw("{$column} - 1"),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user