CakePHP 2.x成就

时间:2014-01-18 16:07:11

标签: php cakephp

我正在尝试使用CakeEvents在我的CakePHP应用程序中构建成就系统。我一直在使用以下网站帮助我将事件放在一起:http://martinbean.co.uk/blog/2013/11/22/getting-to-grips-with-cakephps-events-system/

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

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

架构由以下表格组成:

用户

  • ID
  • 用户名
  • 密码

帖子

  • ID
  • 标题
  • 含量
  • 创建
  • 修饰
  • USER_ID

徽章

  • ID
  • 标题
  • 描述

事件

  • ID
  • 标题
  • 名称

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');

}

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

示例徽章可能是:

  • 标题:第一篇文章,描述:因创建帖子而获颁奖项
  • 标题:10个帖子,描述:创建10个帖子获奖
  • 标题:编辑,描述:编辑帖子
  • 标题:删除,说明:删除帖子

事件表中的一些示例规则:

  • 标题:添加帖子,事件Model.Post.add
  • 标题:编辑帖子,事件:Model.Post.edit
  • 标题:删除帖子,事件:Model.Post.delete
  • 标题:View Post,事件: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);
    }
}

第一个问题是,如何将不同的事件传递给afterSave?由于控制器中的添加和编辑方法都会触发此...

然后我在/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) {


    }
}

所以下一个问题是如何将事件监听器链接回我的事件表?

然后奖励与该操作相关的徽章?注意到有些人需要做额外的检查,比如用户必须创建10个帖子来实现10个帖子的标记,而不仅仅是因为他们创建了帖子。

在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));

    }

}

所以当事情与数据库规则匹配时,我需要从侦听器运行上面的代码。只是努力使它们全部结合在一起。

2 个答案:

答案 0 :(得分:1)

我认为您的数据库架构可能会因事件概念而变得复杂。就个人而言,我有一个badges表,用于存储徽章标题和描述(如果需要,还有图像路径)。然后,我会有一个与每个徽章相对应的事件监听器,因此会涉及一定程度的体力劳动。

让我们想一个示例场景。假设当用户发布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();
        }
    }
}

这是一个粗略的例子,但它希望能引导你走向正确的方向。

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

答案 1 :(得分:0)

第一个问题 - 区分新帖子和编辑

要区分添加和编辑,您需要在创建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);
}

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

第二个问题 - 如何将事件处理链接到事件表

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

由于您现在知道它是编辑还是新帖子(来自event-&gt;数据),您可以采取适当的措施。

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

总结:发送事件时,使用事件数据传递侦听器中需要的所有信息。 事件可以传递更多信息,而不仅仅是它们的名称以及它们被触发的事实。您可以发送然后查看整个“上下文”。

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

希望这就是你要找的东西:)。