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 相关文章推荐
oracle资料库函式库
Oct 09 PHP
php添加文章时生成静态HTML文章的实现代码
Feb 17 PHP
深入解析PHP的Yii框架中的event事件机制
Mar 17 PHP
PHP实现打包zip并下载功能
Jun 12 PHP
记录Yii2框架开发微信公众号遇到的问题及解决方法
Jul 20 PHP
php获取手机端的号码以及ip地址实例代码
Sep 12 PHP
PHP array_reduce()函数的应用解析
Oct 28 PHP
PHP PDOStatement::getAttribute讲解
Feb 01 PHP
php使用filter_var函数判断邮箱,url,ip格式示例
Jul 06 PHP
php传值和传引用的区别点总结
Nov 19 PHP
Laravel 自动转换长整型雪花 ID 为字符串的实现
Oct 27 PHP
php去除deprecated的实例方法
Nov 17 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执行速率优化技巧小结
2008/03/15 PHP
PHP实现图片上传并压缩
2015/12/22 PHP
PHP的Laravel框架结合MySQL与Redis数据库的使用部署
2016/03/21 PHP
PHP基于SMTP协议实现邮件发送实例代码
2017/04/27 PHP
PHP生成(支持多模板)二维码海报代码
2018/04/30 PHP
PHP addcslashes()函数讲解
2019/02/03 PHP
PHP封装请求类实例分析【基于Yii框架】
2019/10/17 PHP
Laravel框架基础语法与知识点整理【模板变量、输出、include引入子视图等】
2019/12/03 PHP
innertext , insertadjacentelement , insertadjacenthtml , insertadjacenttext 等区别
2007/06/29 Javascript
学习从实践开始之jQuery插件开发 对话框插件开发
2012/04/26 Javascript
javascript提取URL的搜索字符串中的参数(自定义函数实现)
2013/01/22 Javascript
js实现超简单的展开、折叠目录代码
2015/08/28 Javascript
JS获取元素多层嵌套思路详解
2016/05/16 Javascript
js实现百度地图定位于地址逆解析,显示自己当前的地理位置
2016/12/08 Javascript
vue-router 学习快速入门
2017/03/01 Javascript
NodeJs中express框架的send()方法简介
2017/06/20 NodeJs
Node.js利用console输出日志文件的方法示例
2018/04/27 Javascript
JS判断两个数组或对象是否相同的方法示例
2019/02/28 Javascript
JS实现根据详细地址获取经纬度功能示例
2019/04/16 Javascript
vue实现前台列表数据过滤搜索、分页效果
2019/05/28 Javascript
webpack4.0+vue2.0利用批处理生成前端单页或多页应用的方法
2019/06/28 Javascript
Python3中使用urllib的方法详解(header,代理,超时,认证,异常处理)
2016/09/21 Python
Python中字符串格式化str.format的详细介绍
2017/02/17 Python
Python实现的微信公众号群发图片与文本消息功能实例详解
2017/06/30 Python
Python复制Word内容并使用格式设字体与大小实例代码
2018/01/22 Python
Python 中Pickle库的使用详解
2018/02/24 Python
Python 类的特殊成员解析
2018/06/20 Python
Python中shapefile转换geojson的示例
2019/01/03 Python
python SQLAlchemy 中的Engine详解
2019/07/04 Python
CSS3制作圆形滚动进度条动画的示例
2020/11/05 HTML / CSS
英国奢侈品牌时尚购物平台:Farfetch(支持中文)
2020/02/18 全球购物
教师中国梦演讲稿
2014/04/23 职场文书
金融事务专业求职信
2014/04/25 职场文书
学习十八届四中全会依法治国心得体会
2014/11/03 职场文书
2015年统计员个人工作总结
2015/07/23 职场文书
使用Navicat Premium工具将oracle数据库迁移到MySQL
2021/05/27 Oracle