乐趣区

关于yii:Yii2学习笔记

控制器

控制器周期

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. 格局
['操作符', 操作数 1, 操作数 2, ...];
  1. 演示
// 简略单个查问 对应的 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()]]
    ]
]);
  1. 操作符阐明

    • 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 须要一个操作数,该操作数必须是代表子查问 yiidbQuery 的一个实例
    // 生成的 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

字段名 字段阐明
id 文章 ID
user_id 文章作者 ID
title 文章题目

用户表 user

字段名 字段阐明
id 用户 ID
name 用户姓名
  • 计划一 应用表关联
// 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'];
        }
    }
}

批处理查问

当须要解决大数据的时候,像 yiidbQuery::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 one
foreach ($query->each() as $user) {// $user 指代的是用户表当中的其中一行数据}

yiidbQuery::batch() 和 yiidbQuery::each() 办法将会返回一个实现了 Iterator 接口 yiidbBatchQueryResult 的对象,能够用在 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());

块赋值留神

  1. 须要定义为平安的字段才能够赋值胜利
  2. 在没有定义场景的状况下, 定义了规定的字段、便会认为是平安的,能够块赋值胜利
  3. 定义了验证场景, 只有场景定义的字段能够批量赋值

新增数据

$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
yiidbActiveRecord::init(): 会触发一个 yiidbActiveRecord::EVENT_INIT 事件

  • 当你通过 find() 办法查问数据时,每个 AR 实例都将有以下生命周期:

constructor

  1. yiidbActiveRecord::init(): 会触发一个 yiidbActiveRecord::EVENT_INIT 事件
  2. yiidbActiveRecord::afterFind(): 会触发一个 yiidbActiveRecord::EVENT_AFTER_FIND 事件
  • 当通过 yiidbActiveRecord::save() 办法写入或者更新数据时, 咱们将取得如下生命周期:
  1. yiidbActiveRecord::beforeValidate(): 会触发一个 yiidbActiveRecord::EVENT_BEFORE_VALIDATE 事件
  2. yiidbActiveRecord::afterValidate(): 会触发一个 yiidbActiveRecord::EVENT_AFTER_VALIDATE 事件
  3. yiidbActiveRecord::beforeSave(): 会触发一个 yiidbActiveRecord::EVENT_BEFORE_INSERT 或 yiidbActiveRecord::EVENT_BEFORE_UPDATE 事件
  4. yiidbActiveRecord::afterSave(): 会触发一个 yiidbActiveRecord::EVENT_AFTER_INSERT 或 yiidbActiveRecord::EVENT_AFTER_UPDATE 事件
  • 最初,当调用 delete() 删除数据时, 咱们将取得如下生命周期:
  1. yiidbActiveRecord::beforeDelete(): 会触发一个 yiidbActiveRecord::EVENT_BEFORE_DELETE 事件

执行理论的数据删除

  1. yiidbActiveRecord::afterDelete(): 会触发一个 yiidbActiveRecord::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
退出移动版