이 글에서는 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', ),
댓글 켜기
1. Model
CAActiveRecord를 기반으로 하는 Active Record(AR)는 객체를 사용하는 디자인 패턴입니다. Yii에서는 AR 개체의 각 인스턴스가 CActiveRecord 클래스 또는 해당 하위 클래스일 수 있습니다. 이는 데이터베이스 테이블이나 뷰의 레코드 행을 래핑하고 이 모델을 사용하여 사용해야 하는 대부분의 비즈니스 논리를 포함하는 데이터베이스의 모든 논리와 세부 정보를 캡슐화합니다. 데이터베이스 테이블 행의 각 열 필드 값은 AR 개체의 속성에 해당합니다. 테이블을 클래스에, 행을 개체에, 열을 개체의 데이터에 매핑합니다. 즉, Active Record 클래스의 각 인스턴스는 데이터베이스의 테이블 행을 나타냅니다. 그러나 Active Record 클래스는 데이터베이스 테이블의 필드와 클래스의 속성 간의 매핑 관계만은 아닙니다. 또한 이 데이터에 대한 일부 비즈니스 논리를 처리하고 데이터베이스에 대한 모든 읽기 및 쓰기 작업을 정의해야 합니다.
1) 모델 선언
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) 삽입:
$post=new Post; $post->title='sample post'; $post->content='content for the sample post'; $post->create_time=time(); $post->save();
(2) 선택: 일반적으로 사용되는 몇 가지 방법
// 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 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) 삭제
$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(); }
사용 2. 모델
을 기준으로 양식을 작성합니다. CFormModel HTML을 요구하기 전에 사용자가 입력할 데이터와 이를 준수해야 하는 규칙을 결정해야 합니다. 모델 클래스를 사용하면 이 정보를 기록할 수 있습니다. 모델은 사용자 입력을 유지하고 유효성을 검사하는 핵심입니다.
사용자 입력을 어떻게 사용하느냐에 따라 두 가지 유형의 모델을 만들 수 있습니다. 사용자가 입력한 데이터를 수집하고 사용하고 폐기하는 경우 양식 모델을 생성하고, 사용자가 입력한 데이터를 데이터베이스에 저장하는 경우 활성 레코드를 사용합니다. 두 모델 모두 기본 클래스 CModel에 정의된 양식의 공통 인터페이스를 상속합니다.
1) 모델 클래스 정의
다음 예에서는 로그인 페이지에서 사용자 입력을 수집하는 LoginForm 모델을 생성합니다. 로그인 정보는 사용자 확인에만 사용되며 저장할 필요가 없으므로 양식 모델을 사용하여 총 3가지 속성인 $username, $password, $rememberMe
는 사용자 이름, 사용자가 입력한 비밀번호, 로그인을 기억하는 옵션을 기록하는 데 사용됩니다. $rememberMe의 기본값은 false이므로 양식이 표시될 때 해당 확인란이 선택되어 있지 않습니다.
팁: 일반 속성과 구별하기 위해 "속성" 대신 "속성"이라는 이름을 사용합니다.
2) 유효성 검사 규칙 선언
사용자가 제출한 데이터가 모델에 입력되면 사용하기 전에 해당 데이터가 합법적인지 확인해야 합니다. 이는 일련의 규칙을 사용하여 입력을 검증함으로써 달성됩니다. ruleers() 메소드
class LoginForm extends CFormModel { public $username; public $password; public $rememberMe=false; }
에서 배열을 구성하여 유효성 검사 규칙을 정의합니다. 위 코드는 사용자 이름과 비밀번호가 필요하고, 비밀번호를 확인해야 하며, RememberMe가 필수임을 나타냅니다. 부울
rules()에서 반환된 각 규칙은
array('AttributeList', 'Validator', 'on'=>'ScenarioList', .. 형식으로 추가되어야 합니다. . 옵션(추가 옵션)
AttributeList는 확인해야 하는 속성 이름을 쉼표로 구분한 목록입니다. 유효성 검사기는 수행해야 할 유효성 검사를 나타냅니다. 선택적 on 매개변수는 규칙이 적용되는 시나리오 목록을 나타내며, (추가 옵션)은 해당 이름-값으로 초기에 유효성 검사기의 관련 속성에 대응하는 데 사용됩니다
세 가지 방법이 있습니다. 규칙에 유효성 검사기를 지정합니다. 먼저 유효성 검사기는 위 예의 authenticate와 같은 이 클래스의 메서드를 사용할 수 있습니다. Validator 메서드는
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.'); } } }
형식으로 선언해야 합니다. 둘째, Validator는 규칙이 적용되면 유효성 검사기 클래스의 인스턴스가 생성되고 실제 유효성 검사를 수행합니다. 초기 인스턴스의 관련 속성에 사용되는 규칙의 추가 속성입니다. 유효성 검사기 클래스는 CValidator
에서 상속해야 합니다. 팁: 활성 레코드 모델에 대한 규칙을 지정할 때 특수 매개변수 'on'을 사용할 수 있습니다.
이는 매개변수는 '삽입' 또는 '업데이트'일 수 있으며, 이를 통해 각각 삽입하거나 업데이트할 때 규칙을 적용할 수 있습니다. 생명이 없다면 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程序设计有所帮助。
更多Yii中Model(模型)的创建及使用方法相关文章请关注PHP中文网!