简体   繁体   English

CakePHP 2.x的成就

[英]CakePHP 2.x Achievements

I'm attempting to build an achievements system in my CakePHP app using CakeEvents. 我正在尝试使用CakeEvents在CakePHP应用程序中构建成就系统。 I've been using the following website for helping me put the Events together: http://martinbean.co.uk/blog/2013/11/22/getting-to-grips-with-cakephps-events-system/ 我一直在使用以下网站来帮助我将活动汇总: http : //martinbean.co.uk/blog/2013/11/22/getting-to-grips-with-cakephps-events-system/

In my app, achievements are called badges and can be awarded to users. 在我的应用中,成就称为徽章,可以授予用户。 These badges are awarded based on rules that link the badge to a Cake event. 这些徽章是根据将徽章与Cake事件链接的规则授予的。

So for example if a user creates a post, that will fire the Model.Post.add event which should check if any rules exist for that event, and if so do the parameters match up, and again if all checks out then award a badge connected to that rule to the user. 因此,例如,如果用户创建了一个帖子,则将触发Model.Post.add事件,该事件应检查该事件是否存在任何规则,如果匹配,则参数匹配,如果所有签出都再次授予徽章与该规则相关联的用户。

The schema comprises of the following tables: 该架构包含以下表格:

users 用户

  • id ID
  • username 用户名
  • password 密码

posts 帖子

  • id ID
  • title 标题
  • content 内容
  • created 创建
  • modified 改性
  • user_id 用户身份

badges 徽章

  • id ID
  • title 标题
  • description 描述

events 事件

  • id ID
  • title 标题
  • name 名称

event_badges event_badges

  • id ID
  • event_id EVENT_ID
  • badge_id badge_id

badge_users badge_users

  • id ID
  • badge_id badge_id
  • user_id 用户身份

Hopefully that all makes sense. 希望一切都有意义。 And here are the Models to show how they connect. 这里是展示它们如何连接的模型。

User.php user.php的

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

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

    public $belongsTo = array(
        'BadgeUser'
    );

}

Badge.php Badge.php

class Badge extends AppModel {

    public $hasMany = array(
        'BadgeUser'
    );

    public $actsAs = array('Containable');

}

Event.php Event.php

class Event extends AppModel {

    public $hasMany = array(
        'EventBadge'
    );

    public $actsAs = array('Containable');

}

EventBadge.php EventBadge.php

class ActionBadge extends AppModel {

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

    public $actsAs = array('Containable');

}

BadgeUser.php BadgeUser.php

class BadgeUser extends AppModel {

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

    public $actsAs = array('Containable');

}

** Feel free to comment if you think the schema is incorrect to achieve what is being described in this question.** **如果您认为该模式不正确,无法发表评论,请随时发表评论。**

So example badges might be: 因此,示例徽章可能是:

  • Title: First Post, Description: Awarded for creating a post 标题:第一篇文章,描述:因创建新文章而获奖
  • Title: 10 Posts, Description: Awarded for creating 10 posts 职称:10个帖子,描述:因创建10个帖子而获奖
  • Title: Editor, Description: Editing a post 标题:编辑者,描述:编辑帖子
  • Title: Deleter, Description: Deleting a post 标题:Deleter,描述:删除帖子

And some example rules in the Events table: 还有“事件”表中的一些示例规则:

  • Title: Add Post, Event Model.Post.add 标题:添加帖子,事件模型.Post.add
  • Title: Edit Post, Event: Model.Post.edit 标题:编辑帖子,事件:Model.Post.edit
  • Title: Delete Post, Event: Model.Post.delete 标题:删除帖子,事件:Model.Post.delete
  • Title: View Post, Event: Model.Post.view 标题:查看帖子,事件:Model.Post.view

So as you can see the Events are linked to the above Badges and the Events are called using the CakeEvents system. 如您所见,事件链接到上述徽章,并且使用CakeEvents系统调用事件。

Okay so when a person does something, let's say saves a new post, I have the following in the Post model: 好的,所以当一个人做某事时,比如说保存了一个新帖子,我在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? 第一个问题是,如何将不同的事件传递给afterSave? As both Add and Edit methods in the controller would fire this... 由于控制器中的Add和Edit方法都会触发此操作...

And then I have a PostListener.php file in /app/Event 然后我在/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. 请注意,有些用户将需要做额外的检查,例如用户必须创建10个帖子才能获得标记的10个帖子,而不仅仅是因为他们已经创建了一个帖子。

In the Badge.php model I have the following function to award badges: 在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. 只是努力使所有东西粘在一起。

I think your database schema may be complicating things by having a notion of events. 我认为您的数据库架构可能由于具有事件概念而使事情复杂化。 Personally, I'd have a badges table that stores badge title and description (and also image path if it's needed). 就个人而言,我会有一个badges表,用于存储徽章标题和描述(如果需要,还可以包含图像路径)。 I'd then have an event listener that corresponds to each badge, so there will be some degree of manual labour involved. 然后,我将有一个与每个徽章相对应的事件侦听器,因此将涉及一定程度的体力劳动。

So let's think of a sample scenario. 因此,让我们考虑一个示例方案。 Let's say a badge is awarded when a user posts a 100 times. 假设用户发布100次,便会授予徽章。 So you'd have your Post model that fires an event when a post is saved: 因此,您将拥有一个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);
    }
}

You can then create a corresponding handler: 然后,您可以创建一个相应的处理程序:

<?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();
        }
    }
}

This is a rough example written off-the-cuff, but hopefully it should steer you in the right direction. 这是一个粗略的示例,但希望它能引导您朝着正确的方向发展。

If there's anything you want me to clear up, let me know and I'll do my best. 如果有什么要我清理的,请告诉我,我会尽力而为。

The first question - differentiate between new post and edit 第一个问题 -区分新帖和编辑

To differentiate between add and edit you need to pass along the $created parameter when you create your CakeEvent. 要区分添加和编辑,您需要在创建CakeEvent时传递$created参数。 Something like this: 像这样:

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

You should add to the data of your event all the data that you will need later on to process it and to match your rules. 您应该将事件以后处理和匹配规则所需的所有数据添加到事件数据中 You can even add the model object itself, if you think you will need that to do some queries with it. 如果您认为需要使用它来进行一些查询,甚至可以添加模型对象本身。

Second Question - how to link event processing to the Events table 第二个问题 -如何将事件处理链接到事件表

In the Event listener you can use the ClassRegistry to get an instance of the Event model (and any other models you require). 在事件侦听器中,您可以使用ClassRegistry获取事件模型(以及您需要的任何其他模型)的实例。 You can do your rules matching and once you have all the data you need you save the badge to the database. 您可以进行规则匹配,一旦拥有了所有需要的数据,便将徽章保存到数据库中。

Since you now know if it's an edit or a new post (from the event->data) you can take appropriate action. 由于您现在知道是编辑还是新帖子(来自event-> data),因此可以采取适当的措施。

The editor id I guess you can take it with the Auth component as being the logged in user. 编辑器ID我想您可以将它作为登录用户与Auth组件一起使用。 So when you have that you can use it to read what you need about the editor from the database. 因此,您可以使用它从数据库中读取有关编辑器的需求。

To conclude: when you send your events, use the event data to pass all the information that you will need in the listener. 总结一下:发送事件时,请使用事件数据在侦听器中传递所需的所有信息。 Event can carry so much more information, not just their names and the fact that they were triggered . 事件可以携带更多信息,而不仅仅是它们的名称和它们被触发的事实 You can send and then look at the entire "context". 您可以发送,然后查看整个“上下文”。

In the listener, make good use of the data you get from the event and of the currently logged in user ID or the post author, do the matching that you need to do and then save the badge for the appropriate user. 在侦听器中,充分利用从事件中获取的数据以及当前登录的用户ID或帖子作者,进行所需的匹配,然后为适当的用户保存徽章。

Hopefully this is what you were looking for :). 希望这是您正在寻找的:)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM