Yii2学习-关于Model总结
来源:互联网 发布:java学多久可以上岗 编辑:程序博客网 时间:2024/06/07 14:23
控制器
控制器周期
beforeAction
/** * action 运行的前置操作 * * 比较适合统一化的数据验证,请求数据的接受等 * @param \yii\base\Action $action action 类 * @return bool 返回ture 控制器周期才会走下去 */public function beforeAction($action){ var_dump($action->id, $action->controller->id); return parent::beforeAction($action); // TODO: Change the autogenerated stub}
afterAction
/** * action 后置操作 * * 比较适合返回最后的日志搜集 * @param \yii\base\Action $action action 类 * @param mixed $result * @return mixed */public function afterAction($action, $result){ return parent::afterAction($action, $result); // TODO: Change the autogenerated stub}
模型
AR 模型 常用方法
查询数据
// 查询单条$one = Post::find()->where(['id' => 1])->one();// 或者$one = Post::finOne(1);// 查询多条$posts = Post::find()->where(['status' => 1])->all();// 或者$posts = Post::findAll(['status' => 1]);// 通过sql查询$posts = Post::findBySql('SELECT * FROM `posts` WHERE `status` = :status', [':status' => 1])->all();
查询条件的设定
where 查询支持的参数
- 字符串格式 例如: ‘status=1’
// 对应的SQL: WHERE status = 1$query->where('status = 1');// 使用字符串方式,可以绑定参数$query->where('status = :status', [':status' => 1])
- 哈希格式 例如: [‘status’ => 1, ‘type’ => 1]
哈希格式最适合用来指定多个 AND 串联起来的简单的”等于断言”子条件。
// 对应的SQL: WHERE (`status`=1) AND (`type`=1)$query->where(['status' => 1, 'type' => 1])// 如果值为一个数组会转为IN 对应SQL: WHERE (`status`=1) AND (`type` IN (1, 2, 3))$query->where(['status' => 1, 'type' => [1, 2, 3]])
- 操作符格式 例如: [‘=’, ‘status’, 1]
可以实现比较复杂的查询条件
- 格式
['操作符', 操作数1, 操作数2, ...];
- 演示
// 简单单个查询 对应的SQL: WHERE `status` >= 1$query->where(['>=', 'status', 1])// 多个条件 AND 连接 对应的SQL: WHERE (`status` >= 1) AND (`type` <= 3)$query->where(['and', ['>=', 'status', 1], ['<=', 'type', 3]])// 多个条件 OR 连接 对应SQL: WHERE (`status` IN (1, 3)) OR (`type` >= 2)$query->where('or', ['in', 'status', [1, 3], ['>=', 'type', 2]])// 比较复杂组合的SQL 对应SQL: WHERE (`create_type` = 6) AND (`status` = 0) AND (`is_fail` = 0) AND (((`last_view_time` = 0) AND (`create_time` <= 1503562511)) OR ((`last_view_time` > 0) AND (`last_view_time` <= 1503562511)))$query->where([ 'and', ['=', 'create_type', 6], ['=', 'status', 0], ['=', 'is_fail', 0], ['or', ['and', ['=', 'last_view_time', 0], ['<=', 'create_time', time()]], ['and', ['>', 'last_view_time', 0], ['<=', 'last_view_time', time()]] ]]);
操作符说明
- and 和 or 确定多个条件通过什么方式连接
between 和 not between
// 数组需要四个元素 对应SQL: WHERE `id` BETWEEN 1 AND 10['between', 'id', 1, 10]
in 和 not in
// 对应SQL: WHERE `status` IN (1, 3)['in', 'status', [1, 3]]
like
// 默认 对应SQL: WHERE `name` LIKE '%username%'['like', 'name', 'username'] /** * 第二个范围值是一个数组,那么将会生成用 AND 串联起来的 多个 like 语句 * 对应SQL: WHERE `name` LIKE '%user%' AND `name` LIKE '%name%' */['like', 'name', ['user', 'name']]// 使用前缀查询 对应SQL: WHERE `name` LIKE 'user%'['like', 'name', 'user%', false]
or like 与like 相同,只是第二个范围值是一个数组,那么将会生成用 OR 串联起来的 多个 like 语句
// 对应的SQL: WHERE `name` LIKE '%user%' OR `name` LIKE '%name%'['or like', 'name', ['user', 'name']]// 自己定义前缀查询还是后缀查询 对应SQL: WHERE `name` LIKE 'user%' OR `name` LIKE '%name'['or like', 'name', ['user%', '%name'], false]
not like 和 or not like 和 like 与 or like 用法相同
exists 和 not exists 需要一个操作数,该操作数必须是代表子查询 yii\db\Query 的一个实例
// 生成的SQL: WHERE EXISTS (SELECT * FROM `user` WHERE `status` = 1)$queryOne = new Query();$queryOne->from('user')->where(['=', 'status', 1])->one();$query->where(['exists', $queryOne])
>, >=, =, <, <=
- andWhere 和 orWhere 在原有条件的基础上 附加额外的条件。你可以多次调用这些方法来分别追加不同的条件
// 对应SQL: WHERE (`status` = 1) AND (`type` >= 1)$query->where(['=', 'status', 1]);$query->andWhere(['>=', 'type', 1]);// 对应的SQL: WHERE ((`status`=1) AND (`type`=1)) OR (`name`='username')$query->where(['status' => 1, 'type' => 1]);$query->orWhere(['name' => 'username']);
- filterWhere 过滤查询(在用户输入查询的时候比较好用) 会忽略空值(null, ”, ’ ‘, [])
// 不会添加查询条件$status = ''; // null, ' ', [] 都不会添加查询条件$query->filterWhere(['status' => $status]);// 添加查询条件: WHERE `status` = 0$status = 0;$query->filterWhere(['status' => $status]);
建议查询时候直接使用where() 方法中传递数组的方式定义where条件; andWhere() 和 orWhere() 会增加判断
查询对象转数组
asArray() 方法
在对查询数据没有其他操作的情况下,建议都转为数组(能够节省内存)
// 查询出来是一个数组$posts = Post::find()->where(['status' => 1])->asArray()->all();
指定数组的键
indexBy() 方法
$users = User::find()->where(['status' => 1])->asArray()->indexBy('id')->all();// 查询出来的数组[ '1' => [ 'id' => 1, 'status' => 1, 'username' => 'username' ], '3' => [ 'id' => 3, 'status' => 1, 'username' => 'my name' ],];// 这样查询出来的数组,判断指定ID的用户是否存在比较方法(特别是循环中)if (isset($user[1])) { ....}
使用场景
现在后台程序需要显示文章信息,并且需要显示文章的作者信息
两个表的结构
文章表 article
用户表 user
- 方案一 使用表关联
// Article 模型类中定义关联关系class Article extends ActiveRecord{ public function getUser() { return $this->hasOne(User::className(), ['id' => 'user_id']); }}/** * 使用 * * 说明这里也是只使用了两次查询 * 第一次: SELECT * FROM `article` LIMIT 10 * 第二次: SELECT * FROM `user` WHERE `id` IN (1, 2, ...) */$arrArticles = Article::find()->with('user')->limit(10)->asArray()->all();if ($arrArticles) { foreach ($arrArticles as $article) { if (isset($article['user'])) { // 使用作者名称 $article['user']['name']; } }}
- 方案二 使用indexBy()
// 第一步查询出文章信息$arrArticles = Article::find()->limit(10)->asArray()->all();// 第二步获取到用户信息if ($arrArticles) { // 获取到用户ID $arrUserIds = array_column($arrArticles, 'user_id'); // 查询到客户信息 $arrUsers = User::find()->where(['id' => $arrUserIds])->indexBy('id')->asArray()->all(); // 三 将用户名称追加到文章信息中 foreach ($arrArticles as &$value) { $value['user_name'] = ''; if (isset($arrUsers[$value['user_id']])) { $value['user_name'] = $arrUsers[$value['user_id']]['name']; } }}
批处理查询
当需要处理大数据的时候,像 yii\db\Query::all() 这样的方法就不太合适了, 因为它们会把所有数据都读取到内存上。为了保持较低的内存需求, Yii 提供了一个 所谓的批处理查询的支持。批处理查询会利用数据游标 将数据以批为单位取出来。
use yii\db\Query;$query = (new Query()) ->from('user') ->orderBy('id');foreach ($query->batch() as $users) { // $users 是一个包含100条或小于100条用户表数据的数组}// or if you want to iterate the row one by oneforeach ($query->each() as $user) { // $user 指代的是用户表当中的其中一行数据}
yii\db\Query::batch() 和 yii\db\Query::each() 方法将会返回一个实现了Iterator 接口 yii\db\BatchQueryResult 的对象,可以用在 foreach 结构当中使用。在第一次迭代取数据的时候, 数据库会执行一次 SQL 查询,然后在剩下的迭代中,将直接从结果集中批量获取数据。默认情况下, 一批的大小为 100,也就意味着一批获取的数据是 100 行。你可以通过给 batch() 或者 each() 方法的第一个参数传值来改变每批行数的大小。
查看执行语句
// 可以通过yii 自带的 debug 工具查看// 通过model 类// 查看执行SQL: SELECT * FROM `user` WHERE `status` IN (1, 2)var_dump(User::find()->where(['status' => [1, 2, 3]])->createCommand()->getRawSql());// 查看预处理的SQL: SELECT * FROM `user` WHERE `status` IN (:qp0, :qp1)var_dump(User::find()->where(['status' => [1, 2, 3]])->createCommand()->getSql());
验证
验证规则定义
定义格式
// 第一个字段可以为字符串,也可以是数组[[验证字段], 验证规则, 其他配置项...]// 为字符串的时候必须为单个字段['username', 'required', 'message' => '用户名不能为空']// 多个字段验证[['username', 'password'], 'required']
例子:
// 在模型的 rules 方法中定义public function rules(){ return [ // 不能为空 [['username', 'passwrod'], 'required'], // 必须唯一 [['username'], 'unique'], ];}
验证规则类型
说明
一般提示信息可以不用填写,会自动匹配 attributeLabels() 方法返回的字段说明信息
- required: 必须值验证
// requiredValue, message 可以不用填写[['字段名'], 'required', 'requiredValue' => '必填值', 'message' => '提示信息']
- email 邮箱格式验证
['email', 'email']
- match 正则表达事验证
[['字段名'], 'match', 'pattern' => '正则表达式']// 正则取反[['字段名'], 'match', 'pattern' => '正则表达式', 'not' => true]
- url 网址信息验证
// 验证https 或者 http 的网址['字段名', 'url']/** * 输入字段可以不带 http 前缀,默认帮你添加 * 输入的值可以是 www.baidu.com 也可以是 http://www.baidu.com * 输入 www.baidu.com 会帮你加上 http:// 最终为 http://www.baidu.com */[['字段名'], 'url', 'defaultScheme' => 'http']
- captcha 验证码
['验证码字段', 'captcha']
- compare 比较
// compareValue 比较值 operator 比较类型['字段', 'compare', 'compareValue' => 30, 'operator' => '>=']// 比较两个字段的值(确认密码需要与密码一致)[['confirm_password'], 'compare', 'compareAttribute' => 'password']
- default 默认值 当字段为空那么赋默认值
// value 定义默认值['字段', 'default', 'value' => 30]
- exist 验证存在
// 验证数据username 在表中必须存在['username', 'exist']// 定义查询的model, 用户名在admin 表中是否存在['username', 'exist', 'targetClass' => Admin::className()]// 定义数据的字段['username', 'exist', 'targetAttribute' => 'name']
- unique 唯一性验证
/** * targetClass 可以配置查询那个表 * targetAttribute 可以定义对应的字段信息 */['username', 'unique']
- file 文件验证
/** * extension 允许上传的文件类型 * 其他配置项 * checkExtensionByMimeType 是否使用mime类型检查文件类型(扩展名) * mimeTypes 允许的mimeTypes 类型 * minSize 文件最小大小 * maxSize 文件最大大小 * 其他配置... */[['file'], 'file', 'extensions' => ['png', 'jpg', 'gif', 'jpeg']]
- image 图片验证 继承于 File
/** * image 验证继承于 file 验证 * file 定义的验证配置都可以使用 * 其他配置 * minWidth, minHeight, maxWidth, maxLength, ... */['image', 'image', 'minWidth' => 100]
- filter 滤镜[trim]
/** * filter 制定过滤的函数 可以使用匿名函数 * skipOnArray 是否跳过数组过滤 */['username', 'filter', 'filter' => 'trim', 'skipOnArray' => true]
- trim 处理
[['username', 'password'], 'trim']
- in 范围值验证
// range 定义范围值['status', 'in', 'range' => [1, 2]]
- integer 整数
['age', 'integer']
- number 数字
['money', 'number']
- double 浮点数
['money', 'double']
- string 字符串验证
/** * length 定义字符串最小长度和最大长度 * min, max 单独定义指定最小,最大长度 */['title', 'string', 'length' => [1, 2]]
- boolean 布尔值验证
/** * strict 定义是否严格验证 */['字段名', 'boolean', 'trueValue' => true, 'falseValue' => false, 'strict' => true]
- date 日期验证[data, time, datetime]
['start_time', 'date']
- ip 验证
[['user_ip'], 'ip']
自定义验证规则
class User extends Model{ public function rules() { return [ ['username', 'validateUser', 'params' => [1, 2, 3]] ]; } /** * 自定义验证处理 * * @desc 函数写的时候可以不接受参数 * @param string $attribute 字段名称 * @param mixed $params rules 中定义的params 参数信息 * @param \yii\validators\InlineValidator $validator 验证类 */ public function validateUser($attribute, $params, $validator) { if ($this->user == 2) { $this->addError($attribute, '不能等于二'); } }}
验证规则生效条件
// 可以定义指定验证的生效条件[ ['passowrd'], 'required', // 指定服务器验证什么时候生效(当状态为1的时候密码不能为空) 'when' => function ($model) { return $model->status == 1; }, // 前端js 验证什么时候生效 'whenClient' => "function(attribute, value) { return $('#status').val() == 1; }",],
验证场景
model 可能在不同的场景下使用,不同场景对应不同的业务逻辑,需要验证的字段和方式也就不一样,这个时候就需要用到验证场景
定义验证场景
model 中定义验证场景
class User extends Model{ public function scenarios() { // 默认验证场景 default 的验证字段 $scenarios = parent::scenarios(); // 登录时候,验证用户名和密码 $scenarios['login'] = ['username', 'password']; // 注册的时候要验证用户名、密码、确认密码 $scenarios['register'] = ['username', 'password', 'confirm_password']; return $scenarios; }}
为规则指定验证场景
还是上面那个model
/** * 定义验证规则 */public function rules{ return [ // 一样定义通用验证 [['username', 'password'], 'trim'], // on 定义使用的验证场景 可以是字符串,也可以是数组 [['username', 'password'], 'required', 'on' => ['login', 'register']], ['confirm_password', 'required', 'on' => 'register'], ['confirm_password', 'compare', 'compareAttribute' => 'password', 'on' => 'register'], ]; }
使用验证场景
一般在控制器中
public function actionLogin(){ // 使用验证场景 $user = new User(); $user->scenario = 'login'; // 或者在实例化指定验证场景 $user = new User(['scenario' => 'login']); // 对model的属性进行赋值 $user->username = '123'; ... // 显示的调用验证 if ($user->validate()) { // 通过验证 } else { // 获取到错误信息 var_dump($user->getErrors()); } /** * 执行save()的时候会调用validate() 方法 * 除非save() 调用时指定不走验证 * $user->save(false) */ if ($user->save()) { ... } else { var_dump($user->getErrors()); }}
验证规则使用注意
执行验证是通过rules 中的规则,从上往下验证的,一旦验证不通过,不会向下验证, 建议关于数据库的验证,尽量放到最后
数据的操作
块赋值
块赋值只用一行代码将用户所有输入填充到一个模型
$user = new User();$user->attributes = Yii::$app->request->post('User', []);// 等同于$user = new User();$data = Yii::$app->request->post('User', []);$user->username = isset($data['username']) ? $data['username'] : null;$user->password = isset($data['password']) ? $data['password'] : null;
- 使用load() 方法
$user = new User();/** * 默认使用Yii 表单 * 提交的表单数组应该为 * 表单元素 <input type="text" name="User[username]" /> * [ * 'User' => ['username' => 'username', 'password' => 'password'] * ] */ $user->load(Yii::$app->request->post());/** * 没有使用yii表单 * <input type="text" name="username" > * 对应提交的值 * ['username' => 'username', 'password' => ''] */$user->load(Yii::$app->request->post(), '');
- 使用属性 attributes
/** * attributes 需要接收一个数组 * [属性字段 => 对应值] */$user->attributes = Yii::$app->request->post('User', []);
- 使用 setAttributes() 方法(前面两种最终都是调用的 setAttributes() 方法)
$user = new User();/** * 需要接收一个数组 * [属性字段 => 对应值] */$user->setAttributes(Yii::$app->request->post());
块赋值注意
- 需要定义为安全的字段才可以赋值成功
- 在没有定义场景的情况下,定义了规则的字段、便会认为是安全的,可以块赋值成功
- 定义了验证场景,只有场景定义的字段可以批量赋值
新增数据
$user = new User();$user->username = 'username';$user->password = 'password';$user->insert();// 或者使用$user->save();
修改数据
- 查询对象修改
$user = User::findOne(1);$user->username = 'username';$user->password = 'password';$user->update();// 或者使用$user->save();
- 修改指定数据
// 将ID 等于 2的用户的状态改为 1, 第二个参数同 where() 方法中的参数$intNumber = User::updateAll(['status' => 1], ['id' => 2]]);// 使用字符的绑定参数查询修改User::updateAll(['status' => 2], 'id=:id', [':id' => 1]);
- 属性值实现累加
/** * updateAllCounters * 第一个参数: 字段对应累加 正数值、累减的值 负数值 * 第二个参数: 查询条件 同where() 方法,可以字符串,数组 * 第三个参数: 查询绑定的参数 */User::updateAllCounters(['status' => -2], 'id=:id', [':id' => 1]);
删除数据
- 使用查询对象删除
$user = User::findOne(1);$user->delete()
- 删除指定数据
User::deleteAll(['status' => 0]);
AR的生命周期
AR的生命周期
理解AR的生命周期对于你操作数据库非常重要。生命周期通常都会有些典型的事件存在。对于开发AR的behaviors来说非常有用。
- 当你实例化一个新的AR对象时,我们将获得如下的生命周期:
constructor
yii\db\ActiveRecord::init(): 会触发一个 yii\db\ActiveRecord::EVENT_INIT 事件
- 当你通过 find() 方法查询数据时,每个AR实例都将有以下生命周期:
constructor
- yii\db\ActiveRecord::init(): 会触发一个 yii\db\ActiveRecord::EVENT_INIT 事件
yii\db\ActiveRecord::afterFind(): 会触发一个 yii\db\ActiveRecord::EVENT_AFTER_FIND 事件
- 当通过 yii\db\ActiveRecord::save() 方法写入或者更新数据时, 我们将获得如下生命周期:
yii\db\ActiveRecord::beforeValidate(): 会触发一个 yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE 事件
- yii\db\ActiveRecord::afterValidate(): 会触发一个 yii\db\ActiveRecord::EVENT_AFTER_VALIDATE 事件
- yii\db\ActiveRecord::beforeSave(): 会触发一个 yii\db\ActiveRecord::EVENT_BEFORE_INSERT 或 yii\db\ActiveRecord::EVENT_BEFORE_UPDATE 事件
yii\db\ActiveRecord::afterSave(): 会触发一个 yii\db\ActiveRecord::EVENT_AFTER_INSERT 或 yii\db\ActiveRecord::EVENT_AFTER_UPDATE 事件
- 最后,当调用 delete() 删除数据时, 我们将获得如下生命周期:
yii\db\ActiveRecord::beforeDelete(): 会触发一个 yii\db\ActiveRecord::EVENT_BEFORE_DELETE 事件
执行实际的数据删除- yii\db\ActiveRecord::afterDelete(): 会触发一个 yii\db\ActiveRecord::EVENT_AFTER_DELETE 事件
参考文档
- Yii2中文社区 http://www.yiichina.com/
- 深入理解Yii2.0 http://www.digpage.com/index.html
- 看云Yii学习https://www.kancloud.cn/curder/yii/247740
- 文档 http://www.awaimai.com/patterns
- Yii2学习-关于Model总结
- yii2 urlManager学习总结
- [源码学习] -- yii2源码学习笔记(七) -- model类
- Yii2详解Model类
- Yii2—模型(Model)
- yii2 model validate
- yii2 model fields使用说明
- yii2 model 输出sql
- Yii2 - 06模型(Model)
- yii2 常见model操作方法
- Yii2—模型(Model)
- yii2关于HTTP请求处理的总结
- Yii2学习笔记:关于params['breadcrumbs'][]
- yii2学习笔记,错误总结,持续更新
- yii2总结
- Yii2 自动分表 model
- [源码学习] -- yii2源码学习笔记(六) -- Behavior和model类
- yii2 学习
- 【DP】回文的最小分割数2
- java编程:输入int数组的方法一(不知道长度)
- SpringBoot 配置分析(二)
- FreeRTOS任务基础
- NTT(模板)
- Yii2学习-关于Model总结
- ART深度探索开篇:从Method Hook谈起
- [置顶] Android自定义控件 温度旋转按钮
- 找回path变量值
- apt命令
- c语言变长结构体
- Android图表 MPAndroidChart折线图
- 机器学习笔记5:TensorFlow的了解与运行
- C/C++ for VS Code