Yii中Model(模型)的创建及使用方法
本文实例分析了Yii中Model(模型)的创建及使用方法。分享给大家供大家参考,具体如下:
YII实现了两种模型,表单模型(CFormModel类)和ActiveRecord模型(CAtiveRecord类),它们都继承自CModel类。CFormModel代表的数据模型是从HTML表单收集的输入,封装了所有逻辑(如表单的验证和其它业务逻辑,应用到表单的域上)。它能将数据存储在内存中,或者在一个ActiveRecord的帮助下,存入数据库里。
数据库连接操作
在config/main.php中
'db'=>array( 'connectionString'=>'mysql:host=localhost;dbname=oss', 'emulatePrepare'=>true, 'username'=>'root', 'password'=>'hahaha', 'charset'=>'utf8', //表前缀 'tablePrefix'=>"oss_" ),
打开注释,php要支持pdo
查看操作日志
//显示日志信息,包括sql的查询信息 array( 'class'=>'CWebLogRoute', ),
将注释打开
一.基于CActiveRecord的Model
ActiveRecord(AR)是一种设计模式,用面向对象的方式抽象的访问数据,Yii中,每一个AR对象的实例都可以是CActiveRecord类或者它的子类。它包装了数据库表或视图中的一行记录,并封装了所有的逻辑和风闻数据库的细节,有大部分的业务逻辑,必须使用这种模型。数据库表中一行每列字段的值对应AR对象的一个属性。它将表映射到类,行映射到对象,列则映射到对象的数据。也就是说每一个ActiveRecord类的实例代表了数据库中表的一行。但一个ActiveRecord类不单单是数据库表中的字段跟类中属性的映射关系。它还需要在这些数据上处理一些业务逻辑,定义了所有对数据库的读写操作。
1)声明一个基于CActiveRecord类的Model
classPostextendsCActiveRecord { publicstaticfunctionmodel($className=__CLASS__) { returnparent::model($className); } publicfunctiontableName() { return'{{post}}'; } publicfunctionprimaryKey() { return'id'; //returnarray('pk1','pk2'); } }
2)使用父类的方法完成数据库操作
(1)Insert:
$post=newPost; $post->title='samplepost'; $post->content='contentforthesamplepost'; $post->create_time=time(); $post->save();
(2)Select:常用几种方法
//findthefirstrowsatisfyingthespecifiedcondition $post=Post::model()->find($condition,$params); //findtherowwiththespecifiedprimarykey $post=Post::model()->findByPk($postID,$condition,$params); //findtherowwiththespecifiedattributevalues $post=Post::model()->findByAttributes($attributes,$condition,$params); //findthefirstrowusingthespecifiedSQLstatement $post=Post::model()->findBySql($sql,$params); $criteria=newCDbCriteria; $criteria->select='title';//onlyselectthe'title'column $criteria->condition='postID=:postID'; $criteria->params=array(':postID'=>10); $post=Post::model()->find($criteria); $post=Post::model()->find(array( 'select'=>'title', 'condition'=>'postID=:postID', 'params'=>array(':postID'=>10), )); //findallrowssatisfyingthespecifiedcondition $posts=Post::model()->findAll($condition,$params); //findallrowswiththespecifiedprimarykeys $posts=Post::model()->findAllByPk($postIDs,$condition,$params); //findallrowswiththespecifiedattributevalues $posts=Post::model()->findAllByAttributes($attributes,$condition,$params); //findallrowsusingthespecifiedSQLstatement $posts=Post::model()->findAllBySql($sql,$params); //getthenumberofrowssatisfyingthespecifiedcondition $n=Post::model()->count($condition,$params); //getthenumberofrowsusingthespecifiedSQLstatement $n=Post::model()->countBySql($sql,$params); //checkifthereisatleastarowsatisfyingthespecifiedcondition $exists=Post::model()->exists($condition,$params);
(3)Update
//updatetherowsmatchingthespecifiedcondition Post::model()->updateAll($attributes,$condition,$params); //updatetherowsmatchingthespecifiedconditionandprimarykey(s) Post::model()->updateByPk($pk,$attributes,$condition,$params); //updatecountercolumnsintherowssatisfyingthespecifiedconditions Post::model()->updateCounters($counters,$condition,$params);
(4)Delete
$post=Post::model()->findByPk(10);//assumingthereisapostwhoseIDis10 $post->delete(); //deletetherowsmatchingthespecifiedcondition Post::model()->deleteAll($condition,$params); //deletetherowsmatchingthespecifiedconditionandprimarykey(s) Post::model()->deleteByPk($pk,$condition,$params);
(5)使用事务
$model=Post::model(); $transaction=$model->dbConnection->beginTransaction(); try { //findandsavearetwostepswhichmaybeintervenedbyanotherrequest //wethereforeuseatransactiontoensureconsistencyandintegrity $post=$model->findByPk(10); $post->title='newposttitle'; $post->save(); $transaction->commit(); } catch(Exception$e) { $transaction->rollBack(); }
二.基于CFormModel的Model
编写表单需要的HTML之前,我们需要决定我们希望用户输入哪些数据,以及应该符合什么规则。一个模型类可以用来记录这些信息,模型是保持用户输入并进行验证的核心
根据我们如何使用用户的输入,我们可以创建两种类型的模型。如果用户输入的数据被收集,使用,然后丢弃,我们将创建一个表单模型(formmodel);如果用户输入的数据被保存到数据库中,我们则会使用activerecord。这两种模型都继承了他们相同的基类CModel中定义的表单的通用接口。
1)模型类的定义
下面的例子中,我们创建了一个LoginForm模型,用来收集用户在登陆页面的输入。由于登陆信息仅仅用于用户验证,并不需要保存,因此我们用formmodel创建
classLoginFormextendsCFormModel { public$username; public$password; public$rememberMe=false; }
LoginForm一共声明了三个属性(attributes),$username、$password、$rememberMe
用来记录用户输入的用户名、密码、以及是否记住登陆的选项。因为$rememberMe有了默认值false,所以显示表单时对应的选框是没有勾选的。
提示:我们使用名"attributes",而不是"properties",来把他们和正常的属性(properties)进行区分。
2)声明验证规则
一旦把用户提交的数据填充到模型,在使用之前,我们要检查他们是否合法。这是通过对输入进行一组规则验证实现的。我们在rulers()方法中通过配置一个数组来定义验证规则
classLoginFormextendsCFormModel { public$username; public$password; public$rememberMe=false; private$_identity; publicfunctionrules() { returnarray( array('username,password','required'), array('rememberMe','boolean'), array('password','authenticate'), ); } publicfunctionauthenticate($attribute,$params) { if(!$this->hasErrors())//weonlywanttoauthenticatewhennoinputerrors { $this->_identity=newUserIdentity($this->username,$this->password); if(!$this->_identity->authenticate()) $this->addError('password','Incorrectpassword.'); } } }
上面的代码指明了用户名和密码是必须得,密码需要被验证,rememberMe必须是布尔型
rules()中返回的每条规则,必须按照如下格式
array('AttributeList','Validator','on'=>'ScenarioList',...附加选项(additionaloptions))
AttributeList是一个被逗号分隔的需要验证的属性名列表。Validator指出了需要做怎样的验证。可选的on参数指出了该规则应用的场景列表,(additionaloptions)是对应的name-value,用于初始对应验证器的相关属性
在一个规则中指定Validator有三种方法,首先Validator可以使该类的一个方法,比如上面例子中的authenticate。该Validator方法必须按照如下的格式声明
publicfunctionValidatorName($attribute,$params){...}
其次Validator可以使验证器的类名,当规则适用时,一个验证器类的实例会被创建并进行实际的验证。规则里的附加属性,用于初始实例的相关属性。验证器类必须继承于CValidator
提示:当对activerecord模型指定规则的时候,我们可以使用特殊的参数‘on',
该参数可以使'insert'或者'update',可以让规则分别在插入或者更新的时候适用。如果没有生命,该规则会在任何调用save()的时候适用。
第三、Validator可以使验证器类预先定义的别名。在上面的例子中,“required”便是CRequiredValidator的别名,用来验证属性不能为空。下面是预定义的验证器类别名的列表
?boolean:CBooleanValidator的别名,验证属性的值是否是CBooleanValidator::trueValue或者CBooleanValidator::falseValue
?captcha:CCaptchaValidator的别名,验证属性的值是否和CAPTCHA中显示的验证码的值相等
?compare:CCompareValidator的别名,验证属性的值是否等于另一个属性或者一个常量
?email:CEmailValidator的别名,验证属性的值是否是个合法的email地址
?default:CDefaultValueValidator的别名,为属性指派一个默认值
?exist:CExistValidator的别名,验证属性的值是否能在表的列里面找到
?file:CFileValidator的别名,验证属性是否包含上传文件的名字
?filter:CFilterValidator的别名,使用一个过滤器转换属性的形式
?in:CRangeValidator的别名,验证属性值是否在一个预订的值列表里面
?length:CStringValidator的别名,确保了属性值的长度在指定的范围内.
?match:CRegularExpressionValidator的别名,验证属性是否匹配一个正则表达式.
?numerical:CNumberValidator的别名,验证属性是否是一个有效的数字.
?required:CRequiredValidator的别名,验证属性的值是否为空.
?type:CTypeValidator的别名,验证属性是否是指定的数据类型.
?unique:CUniqueValidator的别名,验证属性在数据表字段中是否是唯一的.
?url:CUrlValidator的别名,验证属性是否是一个有效的URL路径.
下面我们给出一些使用预定义验证器的例子。
//usernameisrequired array('username','required'), //usernamemustbebetween3and12characters array('username','length','min'=>3,'max'=>12), //wheninregisterscenario,passwordmustmatchpassword2 array('password','compare','compareAttribute'=>'password2', 'on'=>'register'), //wheninloginscenario,passwordmustbeauthenticated array('password','authenticate','on'=>'login'),
3)安全属性的设置
当一个模型创建之后,我们往往需要根据用户的输入,为它填充属性。这可以方便的通过下面批量赋值的方式来实现
$model=newLoginForm; if(isset($_POST['LoginForm'])) $model->attributes=$_POST['LoginForm'];
最后那条语句便是批量赋值,把$_POST['LoginForm']中每个属性都赋值到对应的模型属性中,它等价于下面的语句
foreach($_POST['LoginForm']as$name=>$value) { if($nameisasafeattribute) $model->$name=$value; }
声明属性是否是安全属性是个至关重要的工作。例如,如果我把把数据表的主键暴露为安全属性,那么便可以通过修改主键的值,来管理本没有权限管理的数据,进行攻击。
4)1.1版中的安全属性
在1.1版中,如果属性在适用的规则中指定了验证器,则认为是安全的。例如
array('username,password','required','on'=>'login,register'), array('email','required','on'=>'register'),
上面的代码中用户名和密码属性在login的场景下不允许为空。用户名、密码邮箱在register的场景下不允许为空。因此如果在login的场景下进行批量赋值,仅仅用户名和密码会被赋值,因为login场景下验证规则里仅出现了这两个属性,但是如果是在register场景下,那么这三个属性都会被赋值。
//inloginscenario $model=newUser('login'); if(isset($_POST['User'])) $model->attributes=$_POST['User']; //inregisterscenario $model=newUser('register'); if(isset($_POST['User'])) $model->attributes=$_POST['User'];
那么为什么我们使用如此的策略来决定一个属性是否是安全属性呢?因为一个属性,已经有了一个或者多个对个进行校验的规则,那么我还需要担心吗?
需要记住的是,验证器是用来检测用户输入的数据,而不是我们用代码产生的数据(例如时间戳,自增的主键等)。因此不要给那些不需要用户输入的属性添加验证器。
有时候我们想声明一些属性为安全属性,但是又不必给指定一个验证规则。例如文章的正文属性,我们可以允许用户的任何输入。为了实现这个目标,我们可以用safe规则。
array('content','safe')
对应的也有一个unsafe规则,来指定哪些属性是不安全的
array('permission','unsafe')
unsafe并不常用,对你以前定义的安全属性来说,这是个例外
5)获取验证错误
当验证结束后,任何可能的错误都存储在模型的实例中。我们可以通过调用CModel::getErrors()和CModel::getError()重新获取到。这两个方法的区别在于,第一个可以返回指定模型属性的所有错误,而第二个方法只返回了第一条错误。
6)属性标签
设计表单的时候,我们需要为用户的输入框显示一个标签,来提示用户输入。尽管我们可以再form中写死,但是如果我们在相应的模型中指定的话会更加方便和灵活
默认情况下,CModel会简单的返回属性的名字作为标签。这可以通过重写attributeLabels()方法来自定义。在接下来章节中我们将看到,在模型中指定标签可以让我们更快更强大的创建一个form表单
希望本文所述对大家基于yii框架的php程序设计有所帮助。