教程翻译:用 Yii Framework 编写博客 – 7
定制 Post Model
我们用 yiic 工具生成的 Post model 类需要在三处地方进行修改:
- rules() 方法:设定 model 属性的验证规则;
- relations() 方法:设定对象关系;
- safeAttributes() 方法:设定哪些属性是可以被快速赋值的(主要用在用户输入方面);
信息:一个 model 中包含了血多属性,每个属性对应数据表中的一个字段。我们可以选择在类中明确定义这些成员变量,也可以不定义他们。
定制 rules() 方法
我们首选对属性的验证规则进行设定,以保证用户数据输入的正确性。 比如,Post 中的 status 属性应该是值为 0,1或2的整数。其实 yiic 工具也已经为我们的 model 生成了验证规则。 但是这些规则都比较基础,不一定准确。
根据我们的需求分析, 我们可以对 rules() 方法做一下修改:
public function rules() { return array( array('title, content, status', 'required'), array('title', 'length', 'max'=>128), array('status', 'in', 'range'=>array(0, 1, 2)), array('tags', 'match', 'pattern'=>'/^[\w\s,]+$/', 'message'=>'Tags can only contain word characters.'), ); }
在上面的代码中,我们把 title,content 和 status 设置为必须的属性;title 的长度不能超过128; 在 status 的属性值中, 0 表示 drafted,1 表示 published,2 表示 archived;在 tags 属性中我们只能包含字符和逗号。 我们没有对其他的属性(比如: createTime )设置规则,因为他们不需要用户输入数据。
在对上面这行进行修改只有, 我们可以再次访问下 post 的创建页面来验证我们新的验证规则有没有生效。
信息:验证规则在 model 实例的 validate() 和 save() 方法中被使用。如果我们想的到更多关于验证规则设定的信息, 请参考手册。
定制 safeAttributes() 方法
我们可以通过修改 safeAttributes() 来设定哪些属性是可以被快速赋值的。当我们对 model 实例进行数据输入的时候, 我们可以通过下面的代码来实现快速赋值:
$post->attributes=$_POST['Post'];
如果没有使用快速赋值, 我们可以下面的代码代替:
$post->title=$_POST['Post']['title']; $post->content=$_POST['Post']['content']; ......
随便整体赋值很方便, 但是这也存在着隐患;有些带有恶意的用户试图对一些只读的属性或者应该只能被开发者在代码中修改属性进行修改。例如 当 post 在被更新的时候, id应该是不被修改的。
为了避免我们上述的隐患, 我们可以修改 safteAttributes() 方法, 设置只有 title,content,status 和 tags 属性可以被整体赋值:
public function safeAttributes() { return array('title', 'content', 'status', 'tags'); }
提示:我们通过观察 HTML 表单的用户输入信息来方便的判断哪些属性应该放在安全列表的。表单中需要接受用户输入的 Model 属性应该被设置为安全属性。由于属性需要接受用户的输入, 它们经常需要和验证规则关联在一起。
定制 relations() 方法
最后我们通过修改 relations() 方法来定制 post 的关联对象。 通过在 relations() 中关联对象, 我们可以使用强大的 Relational ActiveRecord (RAR) 特性来对post的关联对象比如 author 和 comments 进行访问,不用再去写那些复杂的 SQL join 语句了。
我们对 relations() 做下面的修改:
public function relations() { return array( 'author'=>array(self::BELONGS_TO, 'User', 'authorId'), 'comments'=>array(self::HAS_MANY, 'Comment', 'postId', 'order'=>'??.createTime'), 'tagFilter'=>array(self::MANY_MANY, 'Tag', 'PostTag(postId, tagId)', 'together'=>true, 'joinType'=>'INNER JOIN', 'condition'=>'??.name=:tag'), ); }
上面的修改表示:
- 一篇文章对应一个作者,post 通过 authorId 属性来关联 User 类;
- 一篇文章可以很多个评论,评论通过 postId 属性来和文章建立关系。评论应该按照创建时间来排列;
tagFilter 关系比较复杂。他用来关联 post 数据表 和 tag 数据表, 只选择那些特定的 tag 名字。 我们将在实施 post 显示功能的时候来展示如何使用这个关系。
通过上面的关系设定, 我们可以很简单来访问 post 的作者和评论:
$author=$post->author; echo $author->username; $comments=$post->comments; foreach($comments as $comment) echo $comment->content;
请根据手册来了解更多的关系设定。
用文字子描述 Status
由于 post 的 status 属性是用数字的形式存放在数据库的, 我们需要用文字的形式表示他才能更直观的现实给终端用户。为此,可以对 Post model 做这样的修改:
class Post extends CActiveRecord { const STATUS_DRAFT=0; const STATUS_PUBLISHED=1; const STATUS_ARCHIVED=2; ...... public function getStatusOptions() { return array( self::STATUS_DRAFT=>'Draft', self::STATUS_PUBLISHED=>'Published', self::STATUS_ARCHIVED=>'Archived', ); } public function getStatusText() { $options=$this->statusOptions; return isset($options[$this->status]) ? $options[$this->status] : "unknown ({$this->status})"; } }
在上面,我们用类的常量来表述 status的可能的值。 我们用这些常量来提高代码的可维护性。 同事我们定义了 getStatusOptions() 方法来翻译一个整数和文字对应的数组。 最后, 我们定义了 getStatusText() 方法来简单的返回当前文章的状态文字。
关联文章: