Yii中巧用

afterSave

使用 ar中的save方法后被调用,常用来做操作日志,或者其他状态变更后的后续处理

 

方法:afterSave($insert, $changedAttributes)

参数:bool $insert 是否是添加, 添加时为true,修改时为false
   array $changedAttributes 变更的字段,保存的时变更前的字段的值,获取当前变更后的值用$this->字段名,获取

下面的例子,就是通过字段的状态的变更,来判断用户进行的操作,添加对应的操作日志。如:



public function afterSave($insert, $changedAttributes)
    {
        $action = '';

        if($insert){
            if($this->getStatus() == 1)  $action = "添加意向单位/【待跟进】";
            if($this->getStatus() == 3)  $action = "添加协议单位/【已签约】";
        }elseif(
            key_exists('agreement_status', $changedAttributes)
            && $changedAttributes['agreement_status'] != $this->agreement_status
            && $changedAttributes['agreement_status'] != @static::$statusEnum[$this->agreement_status]
        ){
            if ($this->getStatus() == 1) $action = "转为后续跟进/【待跟进】";
            if ($this->getStatus() == 2) $action = "开始跟进单位/【跟进中】";
            if ($this->getStatus() == 3) $action = "签约合同/【已签约】";
            if ($this->getStatus() == 5) {
                if ($changedAttributes['agreement_status'] == 3 || $changedAttributes['agreement_status'] == '已签约') {
                    $action = "废弃合同/【已作废】";
                } else {
                    $action = "废弃意向单位/【已作废】";
                }
            }
        }
        if($action){
            //增加操作记录
            /** @var OperationLogService $operationLogService */
            $operationLogService = \Yii::createObject([
                'class' => OperationLogService::class
            ]);
            $operationLogService->add($this->agreement_id, $action, '无', true);
        }
        parent::afterSave($insert, $changedAttributes);
    }

  

 

afterFind


当创建AR对象并用查询结果填充时,将调用此方法。

 

有时候我们判断数据是否过期,由于定时脚本刚好未执行,导致读取出来的数据未及时更新,此时我们就可以通过此方法实时的判断,根据数据的实际情况,对数据实时进行处理。

 

下面的例子,就是读取数据的时候,如果数据过期了,则我们此时就把该数据的状态更改成过期状态,同时将读取的数据的模型的对应的字段也同步更改

public function afterFind()
    {
        parent::afterFind();
        //检查合同过期时间
        if($this->is_auto_expire
            && date('Y-m-d',strtotime($this->contract_limited_end)) < date('Y-m-d')
            && in_array($this->agreement_status, [3,'已签约'])
        ){
            $this->agreement_status = '已过期';
      //1.修改已查询结果集中的返回值
   //我们在开始获取查询结果集时,状态还是未过期状态,读取出来的值为未过期的,但是实际是已过期的,我们要将已读取的模型的状态的设置为过期(返回给前端),这样就达到了实时变更字段的值 $this->setOldAttribute('agreement_status', '已过期'); // 2.同时更新数据库中字段的状态 self::updateAll(['agreement_status'=>'已过期'],['agreement_id'=>$this->agreement_id]); } }

 

 

表单验证,两个参数中至少需要一个


public function rules()
{
    return [
        [['card_id', 'card_code'], 
        function ($attribute, $param) {
            //两个参数中至少需要一个
            if (empty($this->card_code) && empty($this->card_id)) {
                $this->addError($attribute, 'card_id/card_code至少要填一个');
            }
        }, 
        'skipOnEmpty' => false],
    ];
}

  

 

表单验证,去除首尾空格:


public function rules()
{
    return [[title', 'content'],'trim']];
}

  

校验 user_id 在User表中是否存在,并自定义错误信息。


 

public function rules()
{
    return [
        ...
        [['user_id'], 'exist',
            'targetClass' => User::className(),
            'targetAttribute' => 'id',
            'message' => '此{attribute}不存在。'
        ],
        ...
    ];
}

  

Model 里面 rules 联合唯一规则


 

[['store_id', 'member_name'], 'unique', 'targetAttribute' => ['store_id', 'member_name'], 'message' => 'The combination of Store ID and Member Name has already been taken.']
!

  

嵌套查询,groupBy 分组之后排序功能


$subQuery = new Query();
$subQuery->from(PostComment::tableName())->where(['status' => PostComment::STATUS_ACTIVE])->orderBy(['created_at' => SORT_DESC]);

$comment = PostComment::find()->from(['tmpA' => $subQuery])
    ->groupBy('post_id')
    ->all();

  

生成的语句是

SELECT * FROM (SELECT * FROM `post_comment` WHERE `status`=1 ORDER BY `created_at` DESC) `tmpA` GROUP BY `post_id`

  

总结:这里是用到的子查询。Yii2中,from 子句中除了用表名外,还可以用AR对象作为子查询。

 

避免子句被识别成字段,或者字符串,而是要被识别成原生的SQL


 

使用 new Expression()

如:order by null 排序,如果我们YII2中使用子句->orderBy('null'), 这里的 null 就会别识别成字段,而非NULL,此时我们可以用 ->orderBy(new Expression('null')) 即可。

 

  • 加where条件:

$query->andWhere(new \yii\db\Expression('c.type = b.type'));

 

  • 如果要用 find_in_set 需要使用到 Expression 表达式:
User::find()
    ->where(new Expression('FIND_IN_SET(:status, status)'))
    ->addParams([':status' => 1])
    ->all();

  

LIKE 查询 单边加%


['like', 'name', 'tester'] 会生成 name LIKE '%tester%'。

['like', 'name', '%tester', false] => name LIKE '%tester'

$query = User::find()
    ->where(['LIKE', 'name', $id.'%', false]);

  

SQL 随机抽取十名幸运用户


$query = new Query;             
$query->select('ID, City,State,StudentName')
      ->from('student')                               
      ->where(['IsActive' => 1])
      ->andWhere(['not', ['State' => null]])
      ->orderBy(['rand()' => SORT_DESC])
      ->limit(10);

  

 

where条件中两字段相加或相减


$query->andWhere(['<', '`updated_at` + `duration`', time()])->all();

  

搜索的时候添加条件筛选


$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$dataProvider->query->andWhere(['pid' => 0]);

  

 

yii2 给mysql数据库表添加字段后,立即使用这个字段时会出现未定义的情况(Getting unknown property)


原因:yii 对数据表结构进行了缓存。

方法1. 清理掉runtime下的cache缓存之后也可以正常使用这个字段。

方法2. 修改完表字段后执行

# 清理指定表结构缓存数据
Yii::$app->db->getSchema()->refreshTableSchema($tableName);

或

# 清理所有表结构缓存数据
Yii::$app->db->getSchema()->refresh();

  建议将以上代码添加到修改数据表结构的migration中。

 

字段去重的三种方法


static::find()
->where([
    'user_id' => $user_id,
])
->groupBy('uuid')
->all();

--------------------------------

static::find()
->select(['uuid'])
->where([
    'user_id' => $user_id,
])
->distinct()
->count();

-----------------------------------

static::find()->where([
    'user_id' => $user_id,
])->count('distinct uuid');

  

事务


 

Yii::$app->db->transaction(function() {
    $order = new Order($customer);
    $order->save();
    $order->addItems($items);
});

// 这相当于下列冗长的代码:

$transaction = Yii::$app->db->beginTransaction();
try {
    $order = new Order($customer);
    $order->save();
    $order->addItems($items);
    $transaction->commit();
} catch (\Exception $e) {
    $transaction->rollBack();
    throw $e;
}

  

执行SQL查询并缓存结果


$styleId = Yii::$app->request->get('style');
$collection = Yii::$app->db->cache(function($db) use($styleId){
    return Collection::findOne(['style_id'=>$styleId]);
}, self::SECONDS_IN_MINITUE * 10);

  

批量插入数据 


第一种方法

$model = new User();
foreach($data as $attributes)
{
     $_model = clone $model;
     $_model->setAttributes($attributes);
     $_model->save();
}

 

第二种方法

$model = new User();
foreach($data as $attributes)
{
      $model->isNewRecord = true;
      $model->setAttributes($attributes);
      $model->save() && $model->id = 0;
}

  

URL


 

 

URL地址:在WWW上,每一信息资源都有统一的且在网上唯一的地址,该地址就叫URL(Uniform Resource Locator,统一资源定位符),它是WWW的统一资源定位标志,就是指网络地址。

URL由三部分组成:资源类型、存放资源的主机域名、资源文件名。格式:protocol(协议) :// hostname(主机地址,可以是域名)[:port](协议端口) / path(路径:目录+文件) / [?query](查询字符串或者说是参数)#fragment(锚点)

 

假设我们当前页面的访问地址是:http://localhost/public/index.php?r=news&id=1

  • 获取url中的host信息:http://localhost
Yii::$app->request->getHostInfo()
  • 获取url中的路径信息(不包含host和参数):
Yii::$app->request->getPathInfo()
  • 获取不包含host信息的url(含参数): /public/index.php?r=news&id=1
Yii::$app->request->url 
或者
Yii::$app->request->requestUri
  • 获取完整url(含host以及参数):
Yii::$app->request->getHostInfo() . Yii::app()->request->url
  • 只想获取url中的参数部分: r=news&id=1
Yii::$app->getRequest()->queryString
  • 获取某个参数的值,比如id
Yii::$app->getRequest()->getQuery('id'); //get parameter 'id'
  • 获取(除域名外的)首页地址 /public/index.php
Yii::$app->user->returnUrl;
  • 获取Referer
Yii::$app->request->headers['Referer']
或者
Yii::$app->getRequest()->getReferrer()

 

 写 log 日志


use yii\log\Logger;
\Yii::getLogger()->log('User has been created', Logger::LEVEL_INFO);

  

Yii2 获取接口传过来的 JSON 数据


 

 

\Yii::$app->request->rawBody;

 

 防止 SQL 和 Script 注入


use yii\helpers\Html;
use yii\helpers\HtmlPurifier;

echo Html::encode($view_hello_str) //可以原样显示<script></script>代码  
echo HtmlPurifier::process($view_hello_str)  //可以过滤掉<script></script>代码

 

restful 获取 GET 和 POST 过来的数据(得到结果是数组)


// post
Yii::$app->request->bodyParams

// get
Yii::$app->request->queryParams;

  

Yii2 生成url的两种方式实例


 

 

Html::a("链接1", \yii\helpers\Url::toRoute(['product/view', 'id' => 42]);
Html::a("链接2", Yii::$app->urlManager->createUrl(['mysql/chart', 'id' => 43,'time_interval' => '1800', 'end'=>'0']));

  

一个控制器调用其他控制器action的方法


 

 

Yii::$app->runAction('new_controller/view', $params);
// 或者
return (new SecondController('second', Yii::$app->module))->runAction('index', $data);

  

注意:runAction函数的第二个参数是绑定的是控制器的actionParams参数,可以通过 $this->actionParams (在控制器中时),或 Yii::$app->controller->actionParams 获取 。runAction 第二个参数如果传的时数组,那么第一个参数对应的控制器方法的参数一定要是数组,如

function actionView(array $params){//接受参数是数组类型}

  

 

点击下载文件 action


 

 

public function actionDownload($id)
{
    $model = $this->findModel($id);

    if ($model) {
        // do something
    }
    return \Yii::$app->response->setDownloadHeaders($model->downurl);

}

  

发送邮件


 注意,使用邮件发送前发送邮件的邮箱必须开启 POP3/SMTP/IMAP 服务,请在邮箱账号设置中自行开启

  •  config/config.php中的components配置  
'mailer' => [
    'class' => 'yii\swiftmailer\Mailer',
    //'viewPath' => '@common/mail',
    // 默认把所有邮件发送到一个文件里,若需要发送真邮件,你需要把userFileTransport设置为false,并且添加邮件的配置
    'useFileTransport' => false,
    'transport' => [
        'class' => 'Swift_SmtpTransport',
        'host' => 'smtp.gmail.com',
        'username' => 'admin@gmail.com',
        'password' => 'password12345678',
        'port' => 587,//or 25/587
        'encryption' => 'tls',//tls or ssl
    ],
    'messageConfig'=>[
        'charset' => 'UTF-8',
        'from'=>[ 'xxx@126.com' => '发件人名称']
    ],
],
  • 发送
$mail= Yii::$app->mailer->compose()
    ->setFrom(['admin@gmail.com' => Yii::$app->name])
    ->setTo('<target_email@qq.com>')
    ->setSubject('邮件标题')
    ->setHtmlBody('邮件内容'); //->setTextBody('test body') 文本发送

if($mail->send()) {
    echo '发送成功';
} else {
    echo '发送失败';
}

  

 

修改登陆状态超时时间(到期后自动退出登陆) config/web.php中的components


 

user’ => [ 
‘class’=>’yii\web\User’, 
‘identityClass’ => ‘common\models\User’, 
‘loginUrl’=>[‘/user/sign-in/login’], 
‘authTimeout’ => 1800,//登陆有效时间 
‘as afterLogin’ => ‘common\behaviors\LoginTimestampBehavior’ 
],

  

修改返回的数据格式(详见Response::FORMAT_XXXX)


 

$result = array('code' => $code, 'msg' => $msg, 'data' => $data);
$callback = Yii::$app->request->get('callback',null);

$format = $callback ? Response::FORMAT_JSONP : Response::FORMAT_JSON;
Yii::$app->response->format = $format;

if($callback){
    return array(
        'callback' => $callback,
        'data' => $result
    );
}
return $result;

  

 

# 获取字段列

modelAR::getTableSchema()->getColumn("字段名")

如:获取枚举值, static::getTableSchema()->getColumn("system_type")->enumValues;

  

posted on 2019-05-08 00:33  追风的浪子  阅读(639)  评论(0)    收藏  举报

导航