首页 文章

CakePHP 2.x成就

提问于
浏览
1

我'm attempting to build an achievements system in my CakePHP app using CakeEvents. I'一直在使用以下网站帮助我把事件放在一起:http://martinbean.co.uk/blog/2013/11/22/getting-to-grips-with-cakephps-events-system/

在我的应用程序中,成就称为徽章,可以授予用户 . 这些徽章是根据将徽章链接到Cake事件的规则授予的 .

因此,例如,如果用户创建帖子,则会触发 Model.Post.add 事件,该事件应检查该事件是否存在任何规则,如果是,则参数匹配,如果所有检出都匹配,则再次授予连接到该规则的徽章给用户 .

该模式包含以下表格:

用户

  • id

  • 用户名

  • 密码

帖子

  • id

  • Headers

  • 内容

  • 已创建

  • 已修改

  • user_id

徽章

  • id

  • Headers

  • 说明

事件

  • id

  • Headers

  • 名字

event_badges

  • id

  • event_id

  • badge_id

badge_users

  • id

  • badge_id

  • user_id

希望一切都有意义 . 以下是展示他们如何联系的模型 .

user.php的

class User extends AppModel
{
    public $name = 'User';

    public $hasMany = array(
        'Post', 'Badge'
    );

    public $belongsTo = array(
        'BadgeUser'
    );

}

Badge.php

class Badge extends AppModel {

    public $hasMany = array(
        'BadgeUser'
    );

    public $actsAs = array('Containable');

}

Event.php

class Event extends AppModel {

    public $hasMany = array(
        'EventBadge'
    );

    public $actsAs = array('Containable');

}

EventBadge.php

class ActionBadge extends AppModel {

    public $belongsTo = array(
        'Action', 'Badge'
    );

    public $actsAs = array('Containable');

}

BadgeUser.php

class BadgeUser extends AppModel {

    public $belongsTo = array(
        'Badge', 'User'
    );

    public $actsAs = array('Containable');

}

**如果您认为架构不正确以实现此问题中描述的内容,请随意发表评论 . **

所以示例徽章可能是:

  • Headers :第一篇文章,描述:因创建帖子而获奖

  • Headers :10篇帖子,描述:创建10个帖子获颁的奖项

  • Headers :编辑,描述:编辑帖子

  • Headers :删除,描述:删除帖子

以及Events表中的一些示例规则:

  • Headers :添加帖子,事件Model.Post.add

  • Headers :编辑帖子,事件:Model.Post.edit

  • Headers :删除帖子,事件:Model.Post.delete

  • Headers :查看帖子,事件:Model.Post.view

因此,您可以看到事件与上述徽章相关联,并且使用CakeEvents系统调用事件 .

好吧,当一个人做某事时,假设保存一个新帖子,我在Post模型中有以下内容:

public function afterSave($created, $options = array()) {
    if ($created) {
        $event = new CakeEvent('Model.Post.add', $this, array(
            'id' => $this->id,
            'data' => $this->data[$this->alias]
        ));
        $this->getEventManager()->dispatch($event);
    }
}

The first question is, how do I pass different events to the afterSave? As both Add and Edit methods in the controller would fire this...

然后我在 /app/Event 中有一个PostListener.php文件

class PostListener implements CakeEventListener {

    public function implementedEvents() {

        return array(
            'Model.Post.add' => 'postAdded',
            'Model.Post.edit' => 'postEdited',
            'Model.Post.view' => 'postViewed',
            'Model.Post.delete' => 'postDeleted',
        );

    }

    public function postAdded(CakeEvent $event) {

         $this->Badge->awardBadge($badgeId, $userId);  
    }

    public function postEdited(CakeEvent $event) {


    }

    public function postViewed(CakeEvent $event) {


    }

    public function postDeleted(CakeEvent $event) {


    }
}

So the next question is how do I link the event listener back up to my Events table?

And then award the badge connected to that action? Noting that some will need to do extra checks like a user must of created 10 posts to achieve the 10 Posts badged and not just because they have created a post.

在Badge.php模型中,我有以下功能来授予徽章:

public function awardBadge($badgeId, $userId) {

    $controlFind = $this->BadgeUser->find(
        'first',
        array(
            'conditions' => array(
                'badge_id' => $badgeId,
                'user_id' => $userId,
            )
        )
    );

    if(!$controlFind) {

        $temp = array(
            'BadgeUser' => array(
                'badge_id' => $badgeId,
                'user_id' => $userId,
                'created' => date('Y-m-d H:i:s')
            )
        );

        $collection[] = $temp;

        return $this->BadgeUser->saveAll($collection, array('validate' => false));

    }

}

So I need to run the code above from the listener when things match up with the DB rules. Just struggling to make it all stick together.

2 回答

  • 1

    我认为你的数据库模式可能会因事件的概念而变得复杂 . 就个人而言,我有一个 badges 表存储徽章 Headers 和描述(如果需要,还有图像路径) . 然后,我会有一个与每个徽章相对应的事件监听器,因此会涉及一定程度的手工劳动 .

    让我们想一个示例场景 . 假设当用户发布100次时会颁发徽章 . 因此,当您保存帖子时,您的 Post 模型会触发事件:

    <?php
    App::uses('CakeEvent', 'Event');
    
    class Post extends AppModel {
    
        public function afterSave($created, $options = array()) {
            $event = new CakeEvent('Model.User.afterSave', $this);
            $this->getEventManager()->dispatch($event);
        }
    }
    

    然后,您可以创建相应的处理程序:

    <?php
    // Event/BadgeListener.php
    App::uses('CakeEventListener', 'Event');
    App::uses('ClassRegistry', 'Utility');
    
    class BadgeListener implements CakeEventListener {
    
        public function implementedEvents() {
            return array(
                'Model.Post.afterSave' => 'afterSaveListener'
            );
        }
    
        public function afterSaveListener(CakeEvent $event) {
            // check number of posts
            $this->Post = ClassRegistry::init('Post');
            $count = $this->Post->find('count', array(
                'Post.author_id' => $event->subject()->data[$event->subject()->alias]['author_id'];
            ));
            // award badge
            if ($count > 100) {
                // TODO: check user does not already have badge
                $this->BadgeUser = ClassRegistry::init('BadgeUser');
                $this->BadgeUser->create();
                $this->BadgeUser->set('badge_id', 'whatever_badge_id_actually_is');
                $this->BadgeUser->set('user_id', $this->Auth->user('id')); // logged in user ID
                $this->BadgeUser->save();
            }
        }
    }
    

    这是一个粗略的例子,但它希望能引导你朝着正确的方向前进 .

    如果有什么要让我清理的话,请告诉我,我会尽我所能 .

  • 0

    The first question - 区分新帖子和编辑

    要区分添加和编辑,您需要在创建CakeEvent时传递 $created 参数 . 像这样的东西:

    public function afterSave($created, $options = array()) {
            //NOTICE: it's afterSave now, since this will be called after edit or new
            $event = new CakeEvent('Model.Post.afterSave', $this, array(
                'created' => $created, //NOW you will know when you process the even if this was a new post or post edit
                'id' => $this->id,
                'data' => $this->data[$this->alias]
            ));
            $this->getEventManager()->dispatch($event);
    }
    

    您应该在事件数据中添加以后需要处理的所有数据并匹配您的规则 . 如果您认为需要对模型对象进行一些查询,您甚至可以添加模型对象本身 .

    Second Question - 如何将事件处理链接到Events表

    在Event侦听器中,您可以使用ClassRegistry来获取Event模型的实例(以及您需要的任何其他模型) . 您可以进行规则匹配,一旦获得所需的所有数据,就可以将徽章保存到数据库中 .

    由于您现在知道它是编辑还是新帖子(来自事件 - >数据),您可以采取适当的措施 .

    编辑ID我猜你可以把Auth组件作为登录用户 . 因此,当您拥有它时,您可以使用它从数据库中读取编辑器所需的内容 .

    总结:当您发送事件时,使用事件数据传递您在侦听器中需要的所有信息 . 事件可以携带更多信息,而不仅仅是它们的名称以及它们被触发的事实 . 您可以发送然后查看整个"context" .

    在侦听器中,充分利用从事件和当前登录的用户ID或帖子作者获得的数据,执行您需要执行的匹配,然后为相应的用户保存徽章 .

    希望这是你在找什么:)

相关问题