1) Create video_like table, migration and model
php yii migrate/create create_video_like_table
--fields="video_id:string(16):notNull:foreignKey(video),user_id:integer(11):notNull:foreignKey(user),type:integer(1),created_at:integer(11)"
php yii migrate
2) Save like counts
5
6
7
..
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
use yii\web\Controller;
use common\models\Video;
use common\models\VideoLike;
..
public function actionView($id)
{
$this->layout = 'blank';
$video = $this->findVideo($id);
// Save video views
$videoView = new VideoView();
$videoView->video_id = $id;
$videoView->user_id = \Yii::$app->user->id;
$videoView->created_at = time();
$videoView->save();
// Display video/view.php
return $this->render('view', [
'model' => $video
]);
}
public function actionLike($id)
{
$video = $this->findVideo($id);
$userId = \Yii::$app->user->id;
$videoLike = new VideoLike();
$videoLike->video_id = $id;
$videoLike->user_id = $userId;
$videoLike->created_at = time();
$videoLike->save();
}
public function findVideo($id)
{
$video = Video::findOne($id);
// Display error if video id does not exist.
if (!$video) {
throw new NotFoundHttpException("Video does not exist.");
}
return $video;
}
|
frontend > controllers > VideoController.php
3
4
..
19
20
21
22
23
24
25
26
27
28
29
|
use yii\helpers\Url;
use yii\widgets\Pjax;
...
<div>
<?php Pjax::begin() ?>
<a href="<?php echo Url::to(['/video/like', 'id' => $model->video_id]) ?>"
class="btn btn-sm btn-outline-primary" data-method="post" data-pjax="1">
<i class="fa-solid fa-thumbs-up"></i> 9
</a>
<button class="btn btn-sm btn-outline-secondary">
<i class="fa-regular fa-thumbs-down"></i> 3
</button>
<?php Pjax::end() ?>
</div>
|
frontend > views > video > view.php
When the like button is clicked, there should be a new data in the table
video_like.
3) Redirect unauthorized user and accept button click as POST method
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
..
93
|
use yii\web\Controller;
use common\models\Video;
use common\models\VideoLike;
use common\models\VideoView;
use yii\data\ActiveDataProvider;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;
use yii\web\NotFoundHttpException;
class VideoController extends Controller
{
public function behaviors()
{
return [
// If unathorized user clicked the Like button, they will be redirected to login page
'access' => [
'class' => AccessControl::class,
'only' => ['like', 'dislike'],
'rules' => [
[
'allow' => true,
'roles' => ['@']
]
]
],
// Only POST method is allowed for Like & Dislike button
'verb' => [
'class' => VerbFilter::class,
'actions' => [
'like' => ['post'],
'dislike' => ['post'],
]
]
];
}
..
}
|
frontend > controllers > VideoController.php
4) Use Pjax for the buttons
Pjax is a widget integrating the pjax jQuery plugin. We use it so that when
user click on the button, the page won't get reloaded. Instead, it only change
the state of the button.
19
20
21
22
|
class VideoLike extends \yii\db\ActiveRecord
{
const TYPE_LIKE = 1;
const TYPE_DISLIKE = 2;
|
common > models > VideoLike.php
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
public function actionLike($id)
{
$video = $this->findVideo($id);
$userId = \Yii::$app->user->id;
$videoLike = new VideoLike();
$videoLike->video_id = $id;
$videoLike->user_id = $userId;
$videoLike->type = VideoLike::TYPE_LIKE;
$videoLike->created_at = time();
$videoLike->save();
return $this->renderAjax('_buttons', [
'model' => $video
]);
}
|
frontend > controllers > VideoController.php
19
20
21
22
23
24
25
|
<div>
<?php Pjax::begin() ?>
<?php echo $this->render('_buttons', [
'model' => $model
]) ?>
<?php Pjax::end() ?>
</div>
|
frontend > views > video > view.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<?php
/** @var $model \common\models\Video */
use yii\helpers\Url;
?>
<a href="<?php echo Url::to(['/video/like', 'id' => $model->video_id]) ?>" class="btn btn-sm btn-outline-primary"
data-method="post" data-pjax="1">
<i class="fa-solid fa-thumbs-up"></i> 9
</a>
<button class="btn btn-sm btn-outline-secondary">
<i class="fa-regular fa-thumbs-down"></i> 3
</button>
|
frontend > views > video > _buttons.php (new file)
When you clicked on the like button, you can see there's a new request under
the Network tab. There's also a new data with a type of 1 in database.
5) Avoid multiple likes from 1 user
28
29
..
207
208
209
210
211
212
213
214
|
class Video extends \yii\db\ActiveRecord
{
..
public function isLikedBy($userId)
{
return VideoLike::find()
->userIdVideoId($userId, $this->video_id)
->liked()
->one();
}
}
|
common > models > Video.php
3
4
5
..
37
38
39
40
41
42
43
44
45
46
47
48
49
|
namespace common\models\query;
use common\models\VideoLike;
..
public function userIdVideoId($userId, $videoId)
{
return $this->andWhere([
'video_id' => $videoId,
'user_id' => $userId
]);
}
public function liked()
{
return $this->andWhere(['type' => VideoLike::TYPE_LIKE]);
}
}
|
common > models > query > VideoLikeQuery.php
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
public function actionLike($id)
{
$video = $this->findVideo($id);
$userId = \Yii::$app->user->id;
$videoLikeDislike = VideoLike::find()
->userIdVideoId($userId, $id)
->one();
// If user clicked the buttons for the first time, save the LIKE
if (!$videoLikeDislike) {
$this->saveLikeDislike($id, $userId, VideoLike::TYPE_LIKE);
}
// If user already clicked the LIKE button, delete the LIKE
else if ($videoLikeDislike->type == VideoLike::TYPE_LIKE) {
$videoLikeDislike->delete();
}
// If user already clicked the DISLIKE button and then click LIKE, delete the DISLIKE and save new LIKE
else {
$videoLikeDislike->delete();
$this->saveLikeDislike($id, $userId, VideoLike::TYPE_LIKE);
}
return $this->renderAjax('_buttons', [
'model' => $video
]);
}
public function findVideo($id)
{
$video = Video::findOne($id);
// Display error if video id does not exist.
if (!$video) {
throw new NotFoundHttpException("Video does not exist.");
}
return $video;
}
protected function saveLikeDislike($videoId, $userId, $type)
{
$videoLikeDislike = new VideoLike();
$videoLikeDislike->video_id = $videoId;
$videoLikeDislike->user_id = $userId;
$videoLikeDislike->type = $type;
$videoLikeDislike->created_at = time();
$videoLikeDislike->save();
}
|
frontend > controllers > VideoController.php
11
12
13
14
15
|
<a href="<?php echo Url::to(['/video/like', 'id' => $model->video_id]) ?>"
class="btn btn-sm <?php echo $model->isLikedBy(Yii::$app->user->id) ? 'btn-outline-primary' : 'btn-outline-secondary' ?>"
data-method="post" data-pjax="1">
<i class="fa-solid fa-thumbs-up"></i> 9
</a>
|
frontend > views > video > _buttons.php
6) Count and display number of likes
124
125
126
127
128
129
130
131
132
133
134
135
|
public function getViews()
{
return $this->hasMany(VideoView::class, ['video_id' => 'video_id']);
}
/** @return \yii\db\ActiveQuery */
public function getLikes()
{
return $this->hasMany(VideoLike::class, ['video_id' => 'video_id'])
->liked();
}
|
common > models > Video.php
11
12
13
14
15
|
<a href="<?php echo Url::to(['/video/like', 'id' => $model->video_id]) ?>"
class="btn btn-sm <?php echo $model->isLikedBy(Yii::$app->user->id) ? 'btn-outline-primary' : 'btn-outline-secondary' ?>"
data-method="post" data-pjax="1">
<i class="fa-solid fa-thumbs-up"></i> <?php echo $model->getLikes()->count() ?>
</a>
|
frontend > views > video > _buttons.php
7) Count and display number of dislikes
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
..
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
|
/** @return \yii\db\ActiveQuery */
public function getLikes()
{
return $this->hasMany(VideoLike::class, ['video_id' => 'video_id'])
->liked();
}
/** @return \yii\db\ActiveQuery */
public function getDislikes()
{
return $this->hasMany(VideoLike::class, ['video_id' => 'video_id'])
->disliked();
}
..
public function isLikedBy($userId)
{
return VideoLike::find()
->userIdVideoId($userId, $this->video_id)
->liked()
->one();
}
public function isDislikedBy($userId)
{
return VideoLike::find()
->userIdVideoId($userId, $this->video_id)
->disliked()
->one();
}
|
common > models > Video.php
45
46
47
48
49
50
51
52
53 | public function liked()
{
return $this->andWhere(['type' => VideoLike::TYPE_LIKE]);
}
public function disliked()
{
return $this->andWhere(['type' => VideoLike::TYPE_DISLIKE]);
}
|
common > models > query > VideoLikeQuery.php
70
71
..
97
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 | public function actionLike($id)
{
...
}
public function actionDislike($id)
{
$video = $this->findVideo($id);
$userId = \Yii::$app->user->id;
$videoLikeDislike = VideoLike::find()
->userIdVideoId($userId, $id)
->one();
// If user clicked the buttons for the first time, save the DISLIKE
if (!$videoLikeDislike) {
$this->saveLikeDislike($id, $userId, VideoLike::TYPE_DISLIKE);
}
// If user already clicked the DISLIKE button, delete the DISLIKE
else if ($videoLikeDislike->type == VideoLike::TYPE_DISLIKE) {
$videoLikeDislike->delete();
}
// If user already clicked the LIKE button and then click DISLIKE, delete the LIKE and save new DISLIKE
else {
$videoLikeDislike->delete();
$this->saveLikeDislike($id, $userId, VideoLike::TYPE_DISLIKE);
}
return $this->renderAjax('_buttons', [
'model' => $video
]);
}
|
frontend > controllers > VideoController.php
11
12
13
14
15
16
17 | <a href="<?php echo Url::to(['/video/like', 'id' => $model->video_id]) ?>" class="btn btn-sm <?php echo $model->isLikedBy(Yii::$app->user->id) ? 'btn-outline-primary' : 'btn-outline-secondary' ?>" data-method="post" data-pjax="1">
<i class="fa-solid fa-thumbs-up"></i> <?php echo $model->getLikes()->count() ?>
</a>
<a href="<?php echo Url::to(['/video/dislike', 'id' => $model->video_id]) ?>" class="btn btn-sm <?php echo $model->isDislikedBy(Yii::$app->user->id) ? 'btn-outline-primary' : 'btn-outline-secondary' ?>" data-method="post" data-pjax="1">
<i class="fa-solid fa-thumbs-down"></i> <?php echo $model->getDislikes()->count() ?>
</a>
|
frontend > views > video > _buttons.php
No comments:
Post a Comment