CodeIgniter 4:喜欢和不喜欢的功能

CodeIgniter 4: Like and Dislike Functionality

我实现了以下 like/dislike 受 Code with AWA 启发的代码。

编辑 如果有任何改变,我现在正在使用 CodeIgniter。我已经用 MVC 风格的代码更新了我的问题。我还启用了 CSRF 令牌,这可能是我的问题?

post 请求似乎在工作(当我点击喜欢或不喜欢按钮时,正确的值会在检查模式下显示。但除此之外,没有其他工作(即更新数据库,显示 like/dislike 计数等)。

这是我的 Ajax 脚本 view_image.js:

$(document).ready(function() {

        // if the user clicks the subscribe button
        $(".subscibe-button").on("click", function() {
            var user = $(this).data("user");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-rss")) {
                action = "subscribe";
            } else if ($clicked_btn.hasClass("fa-user-check")) {
                action = "unsubscribe";
            }

            $.ajax ({
                url: "<?= site_url('images/view_image/index') ?>",
                type: "post",
                dataType: 'json',
                data: {
                    "action": action,
                    "user": user
                },
                success: function(data) {
                    var res = JSON.parse(data);
                    $("input[name='csrf_test_name']").val(result['csrf']);
                }

            });
        });

        // if the user clicks on the like button
        $(".like-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-thumbs-o-up")) {
                action = "like";
            } else if ($clicked_btn.hasClass("fa-thumbs-up")) {
                action = "unlike";
            }

            $.ajax({
                url: "<?= site_url('images/view_image/index') ?>",
                type: "post",
                dataType: "json",
                data: {
                    "action": action,
                    "viewkey": viewkey
                },
                success: function(data) {
                    var res = JSON.parse(data);

                    if (action == "like") {
                        $clicked_btn.removeClass("fa-thumbs-o-up");
                        $clicked_btn.addClass("fa-thumbs-up");
                    } else if (action == "unlike") {
                        $clicked_btn.removeClass("fa-thumbs-up");
                        $clicked_btn.addClass("fa-thumbs-o-up");
                    }

                    // display number of likes and dislikes
                    $clicked_btn.siblings('span.likes').text(res.likes);
                    $clicked_btn.siblings('span.dislikes').text(res.dislikes);

                    // Change button styling of the other button if user is reacting the second time to image
                    $clicked_btn.siblings("i.fa-thumbs-down").removeClass("fa-thumbs-down").addClass("fa-thumbs-o-down");
                }
            });
        });
        // If the user clicks on the dislike button
        $(".dislike-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-thumbs-o-down")) {
                action = "dislike";
            } else if ($clicked_btn.hasClass("fa-thumbs-down")) {
                action = "undislike";
            }

            $.ajax({
                url: "<?= site_url('images/view_image/index') ?>",
                type: "post",
                dataType: "json",
                data: {
                    "action": action,
                    "viewkey": viewkey
                },
                success: function(data) {
                    var res = JSON.parse(data);

                    if (action == "dislike") {
                        $clicked_btn.removeClass("fa-thumbs-o-down");
                        $clicked_btn.addClass("fa-thumbs-down");
                    } else if (action == "undislike") {
                        $clicked_btn.removeClass("fa-thumbs-down");
                        $clicked_btn.addClass("fa-thumbs-o-down");
                    }

                    // display number of likes and dislikes
                    $clicked_btn.siblings('span.likes').text(res.likes);
                    $clicked_btn.siblings('span.dislikes').text(res.dislikes);

                    // Change button styling of the other button if user is reacting the second time to image
                    $clicked_btn.siblings("i.fa-thumbs-up").removeClass("fa-thumbs-up").addClass("fa-thumbs-o-up");
                }
            });
        });

这是我的视图 view_image.php 文件的摘录,显示了 Ajax 请求所指的位置。

<div class='view-image-info-r'>
                        <i <?php if ($userLiked): ?>
                            class='fa fa-thumbs-up like-button'  
                        <?php else: ?>
                            class='fa fa-thumbs-o-up like-button' 
                        <?php endif ?>
                            data-viewkey="<?= $image['viewkey']; ?>"></i>

                        <span class='likes'><?= esc($likes); ?></span>
                    </div>
                    
                    <div class='view-image-info-r'>
                        <i <?php if ($userDisliked): ?>
                            class='fa fa-thumbs-down dislike-button' 
                        <?php else: ?>
                            class='fa fa-thumbs-o-down dislike-button' 
                        <?php endif ?>
                            data-viewkey="<?= esc($image['viewkey']); ?>"></i>

                        <span class='dislikes'><?= esc($dislikes); ?></span>
                    </div>

这是我的模型 ActionModel.php,包含 insert/update 哪个动作的功能,喜欢/不喜欢like/dislike/不喜欢。

public function insertAction($input, $where)
    {
        $this->$db = \Config\Database::connect();
        $this->$builder = $db->table('actions');

        $data = [];

        $viewkey = $input['viewkey'];

        switch($input['action']) {

            case 'dislike':

                $input['action'] = 0;

                if (userLiked($viewkey) == false) {
                    
                    $this->builder->insert($input);
                
                } else {

                    $this->builder->where($where);
                    $this->builder->update($input);
                }

                break;

            case 'undislike':

                $where = [
                    'action' => 0,
                ];

                $this->builder->where($where)->delete();

                break;

            case 'like':

                $data = [
                    'action' => 1,
                ];

                if (userDisliked($viewkey) == false) {
                    
                    $this->builder->insert($input);
                
                } else {

                    $this->builder->where($where);
                    $this->builder->update($input);
                }

                break;

            case 'unlike':

                $where = [
                    'action' => 1,
                ];

                $this->builder->where($where)->delete();

                break;

            case 'view':
                                    
                $data = [
                    'action' => 2,
                ];

                if (userViewed($viewkey) == false) {
                    
                    $this->builder->insert($input);
                
                } else {

                    $this->builder->where($where);
                    $this->builder->update($input);
                }

                break;

            default:

                break;
        }

        return getActions($viewkey);
        exit(0);
    }

public function getActions($viewkey)
    {
        $actionModel = new ActionModel();

        $data = [];

        $data['dislikes'] = $actionModel->getDislikes($viewkey);
        $data['likes'] = $actionModel->getLikes($viewkey);
        $data['views'] = $actionModel->getViews($viewkey);
        $data['favorites'] = $actionModel->getFavorites($viewkey);

        return json_encode(['data' => $data, 'csrf' => csrf_hash()]);
    }

public function userDisliked($viewkey) 
    {
        $actionModel = new ActionModel();
        
        $where = [];

        $where = [
            'viewkey'   => $viewkey,
            'username'  => session()->get('username'),
            'action'    => 0,
        ];

        if ($actionModel->where($where)->first()) {

            return true;
        
        } else {

            return false;
        } 
    }

    public function userLiked($viewkey) 
    {
        $actionModel = new ActionModel();

        $where = [];

        $where = [
            'viewkey'   => $viewkey,
            'username'  => session()->get('username'),
            'action'    => 1,
        ];

        if ($actionModel->where($where)->first()) {

            return true;
        
        } else {

            return false;
        } 
    }

这是我的控制器View_Image.php:

public function index() 
    {
        $viewkey = $this->request->uri->getSegment(4);

        if ($this->request->isAJAX()) {

            $request = service('request')->getPost('data');
            $postData = $request->getPost();

            $data = [];

            $data['token'] = csrf_hash();

            $validation = \Config\Services::validation();

            if ($validation->withRequest($this->request)->run() == FALSE) {

                if (! empty($this->request->getVar('action')) && ! empty($this->request->getVar('user')) && ! empty(session()->get('username'))) {

                    $data = $input = [];

                    $input = [
                        'subscriber'    => $session()->get('username'),
                        'user_profile'  => $this->request->getVar('user'), 
                        'action'        => $this->request->getVar('action'),
                    ];

                    $this->subscribeModel->insertSubscriber($input);
                }

                if (! empty($this->request->getVar('action')) && ! empty($viewkey) && ! empty(session()->get('username'))) {

                    $data = $where = [];

                    $input = [
                        'viewkey'   => $viewkey,
                        'username'  => session()->get('username'),
                        'action'    => $this->request->getVar('action'),
                        'modified'  => date('Y-m-d H:i:s'),
                    ];

                    $where = [
                        'viewkey'   => $viewkey,
                        'username' => session()->get('username'),
                    ];

                    $actionCount = $this->actionModel->insertAction($input, $where);

                    return $actionCount;
                
                } 
            
            } 
        } 

我已尝试限制在此处粘贴我的代码,以便删除所有回显视图和 namespace/class 声明。

这是我的UI:

我解决了我自己的问题。这是一个安全问题。这就是如何在 AJAX 请求中重新生成 CSRF 令牌。请务必在视图中的某处添加 <?= csrf_field() ?> 行。并在你的 controller/model 中传递 csrf_token()csrf_hash()(无论你在哪里返回 JSON 响应。我在我的模型中这样做。

<script>
    $(document).ready(function() {  
        var csrfName = "<?= csrf_token(); ?>";
        var csrfHash = "<?= csrf_hash(); ?>"; 

        // if the user clicks on the like button
        $(".like-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-thumbs-o-up")) {
                action = "like";
            } else if ($clicked_btn.hasClass("fa-thumbs-up")) {
                action = "unlike";
            }

            $.ajax({
                url: "<?= base_url('/images/view_image/index'); ?>",
                type: "post",
                dataType: "json",
                data: {
                    [csrfName]: csrfHash,
                    "action": action,
                    "viewkey": viewkey,
                },
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                },
                success: function(data) {
                    var res = data;
                    csrfName = data.csrfName;
                    csrfHash = data.csrfHash;

                    if (action == "like") {
                        $clicked_btn.removeClass("fa-thumbs-o-up");
                        $clicked_btn.addClass("fa-thumbs-up");
                    } else if (action == "unlike") {
                        $clicked_btn.removeClass("fa-thumbs-up");
                        $clicked_btn.addClass("fa-thumbs-o-up");
                    }

                    // display number of likes and dislikes
                    $clicked_btn.siblings('span.likes').text(res.likes);
                    $clicked_btn.siblings('span.dislikes').text(res.dislikes);

                    // Change button styling of the other button if user is reacting the second time to image
                    $clicked_btn.siblings("i.fa-thumbs-down").removeClass("fa-thumbs-down").addClass("fa-thumbs-o-down");
                }
            });
        });
        // If the user clicks on the dislike button
        $(".dislike-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-thumbs-o-down")) {
                action = "dislike";
            } else if ($clicked_btn.hasClass("fa-thumbs-down")) {
                action = "undislike";
            }

            $.ajax({
                url: "<?= base_url('/images/view_image/index'); ?>",
                type: "post",
                dataType: "json",
                data: {
                    [csrfName]: csrfHash,
                    "action": action,
                    "viewkey": viewkey
                },
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                },
                success: function(data) {
                    var res = data;
                    csrfName = data.csrfName;
                    csrfHash = data.csrfHash;

                    if (action == "dislike") {
                        $clicked_btn.removeClass("fa-thumbs-o-down");
                        $clicked_btn.addClass("fa-thumbs-down");
                    } else if (action == "undislike") {
                        $clicked_btn.removeClass("fa-thumbs-down");
                        $clicked_btn.addClass("fa-thumbs-o-down");
                    }

                    // display number of likes and dislikes
                    $clicked_btn.siblings('span.likes').text(res.likes);
                    $clicked_btn.siblings('span.dislikes').text(res.dislikes);

                    // Change button styling of the other button if user is reacting the second time to image
                    $clicked_btn.siblings("i.fa-thumbs-up").removeClass("fa-thumbs-up").addClass("fa-thumbs-o-up");
                }
            });
        });
   });
</script>

这是我的控制器View_Image.php索引函数:

$viewkey = $this->request->uri->getSegment(4);

        if ($this->request->IsAjax()) {

            if (! empty($this->request->getPost('action')) && ! empty($this->request->getPost('viewkey')) && ! empty(session()->get('username'))) {

                $input = $where = [];

                $input = [
                    'action'    => $this->request->getPost('action'),
                    'username' => session()->get('username'),
                    'viewkey'   => $this->request->getPost('viewkey'),
                    'modified'  => date('Y-m-d H:i:s'),
                ];

                $actionCount = $this->actionModel->insertAction($input);

                return $actionCount;
            
            } 
        } 

ActionModel.php

public function insertAction($input)
    {
        $db = \Config\Database::connect();
        $builder = $db->table('actions');

        $data = $where = [];

        $viewkey = $input['viewkey'];

        switch($input['action']) {

            case 'dislike':

                $data = [
                    'username'  => $input['username'],
                    'action'    => 0,
                    'viewkey'   => $input['viewkey'],
                    'modified'  => $input['modified'],
                ];

                if ($this->userLiked($viewkey) == false) {
                    
                    $builder->insert($data);
                
                } else {

                    $where = [
                        'username'  => $input['username'],
                        'viewkey'   => $input['viewkey'],
                        'action'    => 1,
                    ];

                    $builder->where($where)->delete();
                    $builder->insert($data);
                }

                break;

            case 'undislike':

                $where = [
                    'action' => 0,
                ];

                $builder->where($where)->delete();

                break;

            case 'like':

               $data = [
                    'username'  => $input['username'],
                    'action'    => 1,
                    'viewkey'   => $input['viewkey'],
                    'modified'  => $input['modified'],
                ];

                if ($this->userDisliked($viewkey) == false) {
                    
                    $builder->insert($data);
                
                } else {

                    $where = [
                        'username'  => $input['username'],
                        'viewkey'   => $input['viewkey'],
                        'action'    => 0,
                    ];

                    $builder->where($where)->delete();
                    $builder->insert($data);
                }

                break;

            case 'unlike':

                $where = [
                    'action' => 1,
                ];

                $builder->where($where)->delete();

                break;
    return $this->getActions($viewkey);
        exit(0);
    }

public function userDisliked($viewkey) 
    {
        $actionModel = new ActionModel();
        
        $where = [];

        $where = [
            'viewkey'   => $viewkey,
            'username'  => session()->get('username'),
            'action'    => 0,
        ];

        if ($actionModel->where($where)->first()) {

            return true;
        
        } else {

            return false;
        } 
    }

    public function userLiked($viewkey) 
    {
        $actionModel = new ActionModel();

        $where = [];

        $where = [
            'viewkey'   => $viewkey,
            'username'  => session()->get('username'),
            'action'    => 1,
        ];

        if ($actionModel->where($where)->first()) {

            return true;
        
        } else {

            return false;
        } 
    }

 public function getActions($viewkey)
    {
        $data = [];

        $data = [
            'csrfName'  => csrf_token(),
            'csrfHash'  => csrf_hash(),
            'dislikes'  => $this->getDislikes($viewkey),
            'likes'     => $this->getLikes($viewkey),
            'views'     => $this->getViews($viewkey),
            'favorites' => $this->getFavorites($viewkey),
        ];

        return json_encode($data);
    }