DARK MODE 

Posted on Monday, August 8, 2022 by

Create YouTube Clone with Yii (Part 12)

 1) Display channel username and description in video view

13
..
25
26
27
28
29
<div class="d-flex justify-content-between align-items-center">
            ..
        </div>
        <div>
            <p><?php echo $model->createdBy->username ?></p>
            <?php echo \yii\helpers\Html::encode($model->description) ?>
        </div>
frontend > views > video > view.php



2) Link username in video view to channel view

 1
 2
 3
 4
 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
<?php

namespace frontend\controllers;

use common\models\User;
use yii\web\Controller;
use yii\web\NotFoundHttpException;

class ChannelController extends Controller
{
    public function actionView($username)
    {
        $channel = $this->findChannel($username);

        return $this->render('view', [
            'channel' => $channel
        ]);
    }

    public function findChannel($username)
    {
        $channel = User::findByUsername($username);
        if (!$channel) {
            throw new NotFoundHttpException("Channel does not exist.");
        }

        return $channel;
    }
}
frontend > controllers > ChannelController.php (new file)

 1
 2
 3
 4
..
26
27
28
29
30
31
32
33
<?php

use yii\helpers\Html;
use yii\widgets\Pjax;
..
        <div>
            <p>
                <?php echo Html::a($model->createdBy->username, [
                    '/channel/view', 'username' => $model->createdBy->username
                ]) ?>
            </p>
            <?php echo Html::encode($model->description) ?>
        </div>
frontend > views > video > view.php

3) Create channel view

 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?php

?>

<div class="jumbotron">
    <h1 class="display-4"><?php echo $channel->username ?></h1>
    <hr class="my-4">
    <p>It uses utility classes for typography and spacing to space content out within the larger container.</p>
    <p class="lead">
        <a class="btn btn-danger mr-2" href="#" role="button">Subscribe</a><i class="far fa-bell"></i>
    </p>
</div>
frontend > views > channel (new folder) > view.php (new file)


4) Create channel short link


Right now, the channel link looks like this: /channel/view?username=aliya. We want to shorten it into /c/aliya just like YouTube.

40
41
42
43
44
45
46
        'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'rules' => [
                '/c/<username>' => '/channel/view'
            ],
        ],
frontend > config > main.php

5) Redirect unauthorized user to login page when clicking the Subscribe button

1
2
3
4
5
6
7
<?php

use yii\helpers\Url;

?>

<a class="btn btn-danger mr-2" href="<?php echo Url::to(['channel/subscribe', 'username' =>  $channel->username]) ?>" data-method="post" data-pjax="1">Subscribe</a><i class="far fa-bell"></i>
frontend > views > channel > _subscribe.php (new file)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?php

use yii\helpers\Url;
use yii\widgets\Pjax;

?>

<div class="jumbotron">
    <h1 class="display-4"><?php echo $channel->username ?></h1>
    <hr class="my-4">
    <?php Pjax::begin();

    echo $this->render('_subscribe', [
        'channel' => $channel
    ]);

    Pjax::end(); ?>
</div>
frontend > views > channel > view.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
..
37
38
39
40
..
51
<?php

namespace frontend\controllers;

use common\models\User;
use yii\web\Controller;
use yii\filters\AccessControl;
use yii\web\NotFoundHttpException;

class ChannelController extends Controller
{
    public function behaviors()
    {
        return [
            // If unathorized user clicked the Subscribe button, they will be redirected to login page
            'access' => [
                'class' => AccessControl::class,
                'only' => ['subscribe'],
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@']
                    ]
                ]
            ]
        ];
    }
    ..
    public function actionSubscribe($username)
    {
        $channel = $this->findChannel($username);
    }
    ..
}
frontend > controllers > ChannelController.php

6) Create Subscriber table, migration & model

Run these commands to create new table and migration:

php yii migrate/create create_subscriber_table --fields="channel_id:integer(11):foreignKey(user),user_id:integer(11):foreignKey(user),created_at:integer(11)"
php yii migrate

Then create new model through Gii as we already done before.

7) Working Subscribe button

 26
 27
 ..
215
216
217
218
219
220
221
222
class User extends ActiveRecord implements IdentityInterface
{
    ..
    public function isSubscribed($userId)
    {
        return Subscriber::find()->andWhere([
            'channel_id' => $this->id,
            'user_id' => $userId
        ])->one();
    }
}
common > models > User.php

 6
 7
 8
..
11
12
..
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
use yii\web\Controller;
use common\models\Subscriber;
use yii\filters\AccessControl;
..
class ChannelController extends Controller
{
    ..
    public function actionSubscribe($username)
    {
        $channel = $this->findChannel($username);

        // Check if user already subscribed
        $userId = \Yii::$app->user->id;
        $subscriber = $channel->isSubscribed($userId);

        // If user haven't subscribed, then create new Susbcribe
        if (!$subscriber) {
            $subscriber = new Subscriber();
            $subscriber->channel_id = $channel->id;
            $subscriber->user_id = $userId;
            $subscriber->created_at = time();
            $subscriber->save();
        }
        // If user already subscribed, then unsubscribed
        else {
            $subscriber->delete();
        }

        return $this->renderAjax('_subscribe', [
            'channel' => $channel
        ]);
    }
frontend > controllers > ChannelController.php

To change the state of the button:
7
8
9
<a class="btn <?php echo $channel->isSubscribed(Yii::$app->user->id) ? 'btn-secondary' : 'btn-danger' ?> mr-2"
    href="<?php echo Url::to(['channel/subscribe', 'username' =>  $channel->username]) ?>" data-method="post"
    data-pjax="1"><?php echo $channel->isSubscribed(Yii::$app->user->id) ? 'Subscribed' : 'Subscribe' ?></a><i class="far fa-bell"></i>
frontend > views > channel > _subscribe.php




8) Display Subscriber count


54
55
56
57
58
59
60
61
62
63
64
65
66
    public function rules()
    {
        return [
            ['status', 'default', 'value' => self::STATUS_INACTIVE],
            ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_INACTIVE, self::STATUS_DELETED]],
        ];
    }

    public function getSubscribers()
    {
        return $this->hasMany(User::class, ['id' => 'user_id'])
            ->viaTable('subscriber', ['channel_id' => 'id']);
    }
common > models > User.php

 6
 7
 8
 9
10
11
12
13
<div class="d-flex align-items-center">

    <a class="btn <?php echo $channel->isSubscribed(Yii::$app->user->id) ? 'btn-secondary' : 'btn-danger' ?> mr-2"
        href="<?php echo Url::to(['channel/subscribe', 'username' =>  $channel->username]) ?>" data-method="post"
        data-pjax="1"><?php echo $channel->isSubscribed(Yii::$app->user->id) ? 'Subscribed' : 'Subscribe' ?><span
            class="ml-2"><?php echo $channel->getSubscribers()->count() ?></span></a><i class="far fa-bell"></i>

</div>
frontend > views > channel _subscribe.php



9) Refasctor channel link display


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?php

namespace common\helpers;

class Html
{
    public static function channelLink($user)
    {
        return \yii\helpers\Html::a(
            $user->username,
            [
                '/channel/view', 'username' => $user->username
            ],
            ['class' => 'text-dark']
        );
    }
}
common > helpers (new folder)Html.php (new file)

27
28
29
30
31
32
        <div>
            <p>
                <?php echo \common\helpers\Html::channelLink($model->createdBy) ?>
            </p>
            <?php echo Html::encode($model->description) ?>
        </div>
frontend > views > video view.php


10) Display video upload in channel page


 7
 8
 9
10
11
12
13
14
..
31
32
33
34
35
36
37
38
39
40
41
42
43
use common\models\Video;
use common\models\Subscriber;
use yii\filters\AccessControl;
use yii\data\ActiveDataProvider;
use yii\web\NotFoundHttpException;

class ChannelController extends Controller
{
    ..
    public function actionView($username)
    {
        $channel = $this->findChannel($username);

        $dataProvider = new ActiveDataProvider([
            'query' => Video::find()->creator($channel->id)->published()
        ]);

        return $this->render('view', [
            'channel' => $channel,
            'dataProvider' => $dataProvider
        ]);
    }
frontend > controllers > ChannelController.php

20
21
22
23
24
25
26
27
28
29
<?php
echo \yii\widgets\ListView::widget([
    'dataProvider' => $dataProvider, // Display video id
    'itemView' => '../video/_video_item', // Display video in Bootstrap Card from _video_item.php
    'layout' => '<div class="d-flex flex-wrap">{items}</div>{pager}', // Wrap item in _video_item.php in new div
    'itemOptions' => [
        'tag' => false // Remove data-key in div
    ]
]);
?>
frontend > views > channel > view.php

15
16
17
18
<h6 class="card-title m-0"><?php echo $model->title ?></h6>
        <p class="text-muted card-text m-0">
            <?php echo \common\helpers\Html::channelLink($model->createdBy) ?>
        </p>
frontend > views > video > _video_item.php











No comments:

Post a Comment