0 follower

Customizing Comment Model

Like the Post model, we need to customize the rules(), relations() and safeAttributes() methods of the Comment model. In addition, we also need to modify the attributeLabels() to declare the customized labels for some attributes.

1. Customizing rules() Method

We first customize the validation rules generated by the yiic tool. The following rules are used for comments:

public function rules()
{
    return array(
        array('author,email,content', 'required'),
        array('author,email,url','length','max'=>128),
        array('email','email'),
        array('url','url'),
        array('verifyCode', 'captcha', 'on'=>'insert',
            'allowEmpty'=>!Yii::app()->user->isGuest),
    );
}

In the above, we specify that the author, email and content attributes are required; the length of author, email and url cannot exceed 128; the email attribute must be a valid email address; the url attribute must be a valid URL; and the verifyCode attribute should be validated as a CAPTCHA code.

The verifyCode attribute in the above is mainly used to store the verification code that a user enters in order to leave a comment. Because it is not present in the Comment table, we need to explicitly declare it as a public member variable. Its validation is using a special validator named captcha which refers to the CCaptchaValidator class. Moreover, the validation will only be performed when a new comment is being inserted (see the on option). And for authenticated users, this is not needed (see the allowEmpty option).

2. Customizing safeAttributes() Method

We then customize the safeAttributes() method to specify which attributes can be massively assigned.

public function safeAttributes()
{
    return array('author', 'email', 'url', 'content', 'verifyCode');
}

This also indicates that the comment form would consist of fields to collect the information about author, email, URL, content and verification code.

3. Customizing relations() Method

When we develop the "recent comments" portlet, we need to list the most recent comments together with their corresponding post information. Therefore, we need to customize the relations() method to declare the relation about post.

public function relations()
{
    return array(
        'post'=>array(self::BELONGS_TO, 'Post', 'postId',
            'joinType'=>'INNER JOIN'),
    );
}

Notice that the join type for the post relation is INNER JOIN. This is because a comment has to belong to a post.

4. Customizing attributeLabels() Method

Finally, we need to customize the attributeLabels() method to declare the customized labels for the attributes. The method returns an array consisting of name-label pairs. When we call CHtml::activeLabel() to display an attribute label, it will first check if a customized label is declared. If not, it will use an algorithm to generate the default label.

public function attributeLabels()
{
    return array(
        'author'=>'Name',
        'url'=>'Website',
        'content'=>'Comment',
        'verifyCode'=>'Verification Code',
    );
}

Tip: The algorithm for generating the default label is based on the attribute name. It first breaks the name into words according to capitalization. It then changes the first character in each word into upper case. For example, the name verifyCode would have the default label Verify Code.

5. Customizing Saving Process

Because we want to keep the comment count in each post, when we add or delete a comment, we need to adjust the corresponding comment count for the post. We achieve this by overriding the afterSave() method and the afterDelete() method of the Comment model. We also override its beforeValidate() method so that we can convert the content from the Markdown format to HTML format and record the creation time.

protected function beforeValidate($on)
{
    $parser=new CMarkdownParser;
    $this->contentDisplay=$parser->safeTransform($this->content);
    if($this->isNewRecord)
        $this->createTime=time();
    return true;
}
 
protected function afterSave()
{
    if($this->isNewRecord && $this->status==Comment::STATUS_APPROVED)
        Post::model()->updateCounters(array('commentCount'=>1), "id={$this->postId}");
}
 
protected function afterDelete()
{
    if($this->status==Comment::STATUS_APPROVED)
        Post::model()->updateCounters(array('commentCount'=>-1), "id={$this->postId}");
}