Skip to content

Commit acfba12

Browse files
committed
Implement like/dislike tweet api
1 parent f0c3c1c commit acfba12

File tree

6 files changed

+151
-0
lines changed

6 files changed

+151
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Action\Tweet;
6+
7+
use App\Entity\Like;
8+
use App\Repository\LikeRepository;
9+
use App\Repository\TweetRepository;
10+
use Illuminate\Support\Facades\Auth;
11+
12+
final class LikeTweetAction
13+
{
14+
private $tweetRepository;
15+
private $likeRepository;
16+
17+
public function __construct(TweetRepository $tweetRepository, LikeRepository $likeRepository)
18+
{
19+
$this->tweetRepository = $tweetRepository;
20+
$this->likeRepository = $likeRepository;
21+
}
22+
23+
public function execute(LikeTweetRequest $request): void
24+
{
25+
$tweet = $this->tweetRepository->getById($request->getTweetId());
26+
27+
$userId = Auth::id();
28+
29+
// if user already liked tweet, we remove previous like
30+
if ($this->likeRepository->existsForTweetByUser($tweet->id, $userId)) {
31+
$this->likeRepository->deleteForTweetByUser($tweet->id, $userId);
32+
33+
return;
34+
}
35+
36+
$like = new Like();
37+
$like->forTweet(Auth::id(), $tweet->id);
38+
39+
$this->likeRepository->save($like);
40+
}
41+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Action\Tweet;
6+
7+
final class LikeTweetRequest
8+
{
9+
private $tweetId;
10+
11+
public function __construct(int $tweetId)
12+
{
13+
$this->tweetId = $tweetId;
14+
}
15+
16+
public function getTweetId(): int
17+
{
18+
return $this->tweetId;
19+
}
20+
}

backend/app/Entity/Like.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Illuminate\Database\Eloquent\Model;
99
use Illuminate\Database\Eloquent\Relations\BelongsTo;
1010
use Illuminate\Database\Eloquent\Relations\MorphTo;
11+
use InvalidArgumentException;
1112

1213
/**
1314
* Class Like
@@ -27,6 +28,9 @@ final class Like extends Model
2728
{
2829
protected $table = 'likes';
2930

31+
// no timestamps for likes migration
32+
public $timestamps = false;
33+
3034
protected $fillable = [
3135
'user_id',
3236
'likeable_id',
@@ -64,4 +68,26 @@ public function getUser(): User
6468
{
6569
return $this->user;
6670
}
71+
72+
public function forTweet(int $userId, int $tweetId): void
73+
{
74+
$this->assertIdIsValid($userId);
75+
$this->assertIdIsValid($tweetId);
76+
77+
$this->user_id = $userId;
78+
$this->likeable_id = $tweetId;
79+
$this->likeable_type = Tweet::class;
80+
$this->created_at = Carbon::now();
81+
}
82+
83+
/**
84+
* @param int $id
85+
* @throws InvalidArgumentException
86+
*/
87+
private function assertIdIsValid(int $id): void
88+
{
89+
if ($id < 1) {
90+
throw new InvalidArgumentException('Id cannot be less than 1.');
91+
}
92+
}
6793
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Http\Controllers\Api;
6+
7+
use App\Action\Tweet\LikeTweetAction;
8+
use App\Action\Tweet\LikeTweetRequest;
9+
use App\Http\Controllers\ApiController;
10+
use App\Http\Response\ApiResponse;
11+
12+
final class LikeController extends ApiController
13+
{
14+
private $likeTweetAction;
15+
16+
public function __construct(LikeTweetAction $likeTweetAction)
17+
{
18+
$this->likeTweetAction = $likeTweetAction;
19+
}
20+
21+
public function likeOrDislikeTweet(string $id): ApiResponse
22+
{
23+
$this->likeTweetAction->execute(new LikeTweetRequest((int)$id));
24+
25+
return $this->createEmptyResponse();
26+
}
27+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Repository;
6+
7+
use App\Entity\Like;
8+
use App\Entity\Tweet;
9+
10+
final class LikeRepository
11+
{
12+
public function save(Like $like): Like
13+
{
14+
$like->save();
15+
16+
return $like;
17+
}
18+
19+
public function existsForTweetByUser(int $tweetId, int $userId): bool
20+
{
21+
return Like::where([
22+
'likeable_id' => $tweetId,
23+
'likeable_type' => Tweet::class,
24+
'user_id' => $userId
25+
])->exists();
26+
}
27+
28+
public function deleteForTweetByUser(int $tweetId, int $userId): void
29+
{
30+
Like::where([
31+
'likeable_id' => $tweetId,
32+
'likeable_type' => Tweet::class,
33+
'user_id' => $userId
34+
])->delete();
35+
}
36+
}

backend/routes/api.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
Route::post('/{id}/image', 'TweetController@uploadTweetImage');
4646
Route::put('/{id}', 'TweetController@updateTweetById');
4747
Route::delete('/{id}', 'TweetController@deleteTweetById');
48+
Route::put('/{id}/like', 'LikeController@likeOrDislikeTweet');
4849
});
4950

5051
Route::group([

0 commit comments

Comments
 (0)