Yii中Model(模型)的创建及使用方法


Posted in PHP onDecember 28, 2015

本文实例分析了Yii中Model(模型)的创建及使用方法。分享给大家供大家参考,具体如下:

YII 实现了两种模型,表单模型(CFormModel类)和Active Record模型(CAtiveRecord类),它们都继承自CModel类。 CFormModel代表的数据模型是从HTML表单收集的输入,封装了所有逻辑(如表单的验证和其它业务逻辑,应用到表单的域上)。它能将数据存储在内 存中,或者在一个Active Record的帮助下,存入数据库里。

数据库连接操作

在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

Active Record(AR) 是一种设计模式,用面向对象的方式抽象的访问数据,Yii中,每一个AR对象的实例都可以是CActiveRecord类或者它的子类。它包装了数据库表 或视图中的一行记录,并封装了所有的逻辑和风闻数据库的细节,有大部分的业务逻辑,必须使用这种模型。数据库表中一行每列字段的值对应AR对象的一个属 性。它将表映射到类,行映射到对象,列则映射到对象的数据。也就是说每一个Active Record类的实例代表了数据库中表的一行。但一个 Active Record类不单单是数据库表中的字段跟类中属性的映射关系。它还需要在这些数据上处理一些业务逻辑,定义了所有对数据库的读写操作。

1) 声明一个基于CActiveRecord 类的Model

class Post extends CActiveRecord
{
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function tableName()
{
return '{{post}}';
}
public function primaryKey()
{
return 'id';
// return array('pk1', 'pk2');
}
}

2) 使用父类的方法完成数据库操作

(1) Insert:

$post=new Post;
$post->title='sample post';
$post->content='content for the sample post';
$post->create_time=time();
$post->save();

(2) Select: 常用几种方法

// find the first row satisfying the specified condition
$post=Post::model()->find($condition,$params);
// find the row with the specified primary key
$post=Post::model()->findByPk($postID,$condition,$params);
// find the row with the specified attribute values
$post=Post::model()->findByAttributes($attributes,$condition,$params);
// find the first row using the specified SQL statement
$post=Post::model()->findBySql($sql,$params);
$criteria=new CDbCriteria;
$criteria->select='title'; // only select the '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),
));
// find all rows satisfying the specified condition
$posts=Post::model()->findAll($condition,$params);
// find all rows with the specified primary keys
$posts=Post::model()->findAllByPk($postIDs,$condition,$params);
// find all rows with the specified attribute values
$posts=Post::model()->findAllByAttributes($attributes,$condition,$params);
// find all rows using the specified SQL statement
$posts=Post::model()->findAllBySql($sql,$params);
// get the number of rows satisfying the specified condition
$n=Post::model()->count($condition,$params);
// get the number of rows using the specified SQL statement
$n=Post::model()->countBySql($sql,$params);
// check if there is at least a row satisfying the specified condition
$exists=Post::model()->exists($condition,$params);

(3) Update

// update the rows matching the specified condition
Post::model()->updateAll($attributes,$condition,$params);
// update the rows matching the specified condition and primary key(s)
Post::model()->updateByPk($pk,$attributes,$condition,$params);
// update counter columns in the rows satisfying the specified conditions
Post::model()->updateCounters($counters,$condition,$params);

(4) Delete

$post=Post::model()->findByPk(10); // assuming there is a post whose ID is 10
$post->delete();
// delete the rows matching the specified condition
Post::model()->deleteAll($condition,$params);
// delete the rows matching the specified condition and primary key(s)
Post::model()->deleteByPk($pk,$condition,$params);

(5) 使用事务

$model=Post::model();
$transaction=$model->dbConnection->beginTransaction();
try
{
// find and save are two steps which may be intervened by another request
// we therefore use a transaction to ensure consistency and integrity
$post=$model->findByPk(10);
$post->title='new post title';
$post->save();
$transaction->commit();
}
catch(Exception $e)
{
$transaction->rollBack();
}

二. 基于CFormModel 的Model

编写表单需要的HTML之前,我们需要决定我们希望用户输入哪些数据,以及应该符合什么规则。一个模型类可以用来记录这些信息,模型是保持用户输入并进行验证的核心

根据我们如何使用用户的输入,我们可以创建两种类型的模型。如果用户输入的数据被收集,使用,然后丢弃,我们将创建一个表单模型(form model); 如果用户输入的数据被保存到数据库中,我们则会使用 active record 。这两种模型都继承了他们相同的基类CModel中定义的表单的通用接 口。

1) 模型类的定义

下面的例子中,我们创建了一个LoginForm模型,用来收集用户在登陆页面的输入。由于登陆信息仅仅用于用户验证,并不需要保存,因此我们用form model创建

class LoginForm extends CFormModel
{
public $username;
public $password;
public $rememberMe=false;
}

LoginForm一共声明了三个属性(attributes),$username、$password、$rememberMe

用来记录用户输入的用户名、密码、以及是否记住登陆的选项。因为$rememberMe有了默认值false,所以显示表单时对应的选框是没有勾选的。

提示:我们使用名"attributes",而不是"properties",来把他们和正常的属性(properties)进行区分。

2) 声明验证规则

一旦把用户提交的数据填充到模型,在使用之前,我们要检查他们是否合法。这是通过对输入进行一组规则验证实现的。我们在rulers()方法中通过配置一个数组来定义验证规则

class LoginForm extends CFormModel
{
public $username;
public $password;
public $rememberMe=false;
private $_identity;
public function rules()
{
return array(
array('username, password','required'),
array('rememberMe', 'boolean'),
array('password', 'authenticate'),
);
}
public function authenticate($attribute,$params)
{
if(!$this->hasErrors()) // we only want to authenticate when no input errors
{
$this->_identity=new UserIdentity($this->username,$this->password);
if(!$this->_identity->authenticate())
$this->addError('password','Incorrect password.');
}
}
}

上面的代码指明了用户名和密码是必须得,密码需要被验证,rememberMe必须是布尔型

rules()中返回的每条规则,必须按照如下格式

array('AttributeList', 'Validator', 'on'=>'ScenarioList', ...附加选项(additional options))

AttributeList 是一个被逗号分隔的需要验证的属性名列表。Validator 指出了需要做怎样的验证。可选的on 参数指出了该规则应用的场景列表,(additional options)是对应的name-value,用于初始对应验证器的相关属性

在一个规则中指定Validator有三种方法,首先Validator可以使该类的一个方法,比如上面例子中的authenticate。该Validator方法必须按照如下的格式声明

public function ValidatorName($attribute,$params) { ... }

其次 Validator 可以使验证器的类名,当规则适用时,一个验证器类的实例会被创建并进行实际的验证。规则里的附加属性,用于初始实例的相关属性。验证器类必须继承于CValidator

提示:当对active record模型指定规则的时候,我们可以使用特殊的参数‘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路径.

下面我们给出一些使用预定义验证器的例子。

// username is required
array('username', 'required'),
// username must be between 3 and 12 characters
array('username', 'length', 'min'=>3, 'max'=>12),
// when in register scenario, password must match password2
array('password', 'compare', 'compareAttribute'=>'password2',
'on'=>'register'),
// when in login scenario, password must be authenticated
array('password', 'authenticate', 'on'=>'login'),

3) 安全属性的设置

当一个模型创建之后,我们往往需要根据用户的输入,为它填充属性。这可以方便的通过下面批量赋值的方式来实现

$model=new LoginForm;
if(isset($_POST['LoginForm']))
$model->attributes=$_POST['LoginForm'];

最后那条语句便是批量赋值,把$_POST['LoginForm']中每个属性都赋值到对应的模型属性中,它等价于下面的语句

foreach($_POST['LoginForm'] as $name=>$value)
{
if($name is a safe attribute)
$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场景下,那么这三个属性都 会被 赋值。

// in login scenario
$model=new User('login');
if(isset($_POST['User']))
$model->attributes=$_POST['User'];
// in register scenario
$model=new User('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程序设计有所帮助。

PHP 相关文章推荐
谈谈新手如何学习PHP 默默经典版本
Aug 04 PHP
php csv操作类代码
Dec 14 PHP
PHP版国家代码、缩写查询函数代码
Aug 14 PHP
使用CodeIgniter的类库做图片上传
Jun 12 PHP
php使用str_replace实现输入框回车替换br的方法
Nov 24 PHP
PHP实现格式化文件数据大小显示的方法
Jan 03 PHP
Yii2如何批量添加数据
May 17 PHP
PHP简单实现二维数组的矩阵转置操作示例
Nov 24 PHP
php+croppic.js实现剪切上传图片功能
Aug 14 PHP
php无限极分类实现方法分析
Jul 04 PHP
PHP的静态方法与普通方法用法实例分析
Sep 26 PHP
PHP字符串与数组处理函数用法小结
Jan 07 PHP
yii数据库的查询方法
Dec 28 #PHP
yii分页组件用法实例分析
Dec 28 #PHP
PHP读取文件内容的五种方式
Dec 28 #PHP
yii用户注册表单验证实例
Dec 26 #PHP
PHP7之Mongodb API使用详解
Dec 26 #PHP
thinkPHP下的widget扩展用法实例分析
Dec 26 #PHP
thinkPHP下ueditor的使用方法详解
Dec 26 #PHP
You might like
PHP错误WARNING: SESSION_START() [FUNCTION.SESSION-START]解决方法
2014/05/04 PHP
浅析PHP的静态成员函数效率更高的原因
2014/06/13 PHP
php修改指定文件后缀的方法
2014/09/11 PHP
php+mysqli批量查询多张表数据的方法
2015/01/29 PHP
讲解WordPress中用于获取评论模板和搜索表单的PHP函数
2015/12/28 PHP
重定向实现代码
2006/11/20 Javascript
jQuery 如何先创建、再修改、后添加DOM元素
2014/05/20 Javascript
JS实现控制表格行内容垂直对齐的方法
2015/03/30 Javascript
基于JS2Image实现圣诞树代码
2015/12/24 Javascript
three.js实现围绕某物体旋转
2017/01/25 Javascript
vue动态生成dom并且自动绑定事件
2017/04/19 Javascript
js canvas实现QQ拨打电话特效
2017/05/10 Javascript
微信小程序实现下拉刷新和轮播图效果
2017/11/21 Javascript
jQuery实现经典的网页3D轮播图封装功能【附源码下载】
2019/02/15 jQuery
解决vue页面渲染但dom没渲染的操作
2020/07/27 Javascript
js实现全选和全不选功能
2020/07/28 Javascript
[01:00:10]完美世界DOTA2联赛PWL S2 FTD vs Inki 第二场 11.21
2020/11/24 DOTA
[01:03:41]完美世界DOTA2联赛PWL S3 DLG vs Phoenix 第一场 12.17
2020/12/19 DOTA
python实现通过shelve修改对象实例
2014/09/26 Python
初步介绍Python中的pydoc模块和distutils模块
2015/04/13 Python
Python中__new__与__init__方法的区别详解
2015/05/04 Python
Python字典循环添加一键多值的用法实例
2019/01/20 Python
Python K最近邻从原理到实现的方法
2019/08/15 Python
python web框架中实现原生分页
2019/09/08 Python
pygame实现非图片按钮效果
2019/10/29 Python
Django模型中字段属性choice使用说明
2020/03/30 Python
学习Python需要哪些工具
2020/09/04 Python
.TTL是什么?有什么用处,通常那些工具会用到它?(ping? traceroute? ifconfig? netstat?)
2016/05/09 面试题
程序员跳槽必看面试题总结
2013/06/28 面试题
普通员工辞职信
2014/01/17 职场文书
上课迟到检讨书
2014/01/19 职场文书
雷人标语集锦
2014/06/19 职场文书
教育实践活动对照检查材料
2014/09/23 职场文书
走群众路线学习笔记
2014/11/06 职场文书
SQL Server表分区降低运维和维护成本
2022/04/08 SQL Server
Windows server 2012 NTP时间同步的实现
2022/06/25 Servers