资讯专栏INFORMATION COLUMN

YII2项目常用技能知识总结

W_BinaryTree / 3349人阅读

摘要:不通过日志获取执行的原生语句和打印变量数据打印变量数据可以这样写引用命名空间使用使用第二个参数是数组的深度第三个参数是是否显示代码高亮默认不显示从数据库二维数组中返回一维数组并配合验证规则实现分类数据过滤。

1、不通过日志获取AR执行的原生SQL语句和打印变量数据

$query = User::find() ->select(["username"])->where(["id"=>[1,2,3,4])
// get the AR raw sql in YII2
$commandQuery = clone $query;
echo $commandQuery->createCommand()->getRawSql();$users = $query->all();

打印变量数据可以这样写:

//引用命名空间
use yiihelpersVarDumper;
//使用
VarDumper::dump($var);
//使用2  第二个参数是数组的深度  第三个参数是是否显示代码高亮(默认不显示)
VarDumper::dump($var, 10 ,true);

2、从数据库二维数组中返回一维数组并配合rules验证规则实现分类数据过滤。

普通返回表记录的二维数组

Member::find()->select("userid")->asArray()->all();
Array
(
    [0] => Array
        (
            [userid] => 1
        )

    [1] => Array
        (
            [userid] => 2
        )

    [2] => Array
        (
            [userid] => 3
        )

)

返回字段的一维数组

Member::find()->select("userid")->asArray()->column();

或者:

yiihelpersArrayHelper::getColumn(Member::find()->all(), "userid")
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
)

返回一维数组配合验证规则验证数据正确性,如分类catid正确分为只有1-4,但是在devTools打开修改catid为5,提交同样会到数据库,此时rules验证规则如下:

["catid", "in", "range" => category::find()->select("id")->asArray()->column()],

当然,这个也可以通过下面这样子写,一样的:

["catid", "in", "range" => yiihelpersArrayHelper::getColumn(category::find()->all(), "catid")],

这样就可以过滤不正确的分类数据了!

3、友好时间表示方法

之前一直使用自定义的友好时间函数。几天前发现万能的YII已经提供了友好时间访问,代码如下:

Yii::$app->formatter->asRelativeTime("1447565922"); //2小时前

4、使用不同的响应类型或者自定义响应类型

有效的格式:

    FORMAT_RAW
    
    FORMAT_HTML
    
    FORMAT_JSON
    
    FORMAT_JSONP
    
    FORMAT_XML
    
    JSON响应
    
    public function actionIndex()
    {
        Yii::$app->response->format = yiiwebResponse::FORMAT_JSON;
        $items = ["some", "array", "of", "data" => ["associative", "array"]];
        return $items;
    }

返回:

    {
        "0": "some",
        "1": "array",
        "2": "of",
        "data": ["associative", "array"]
    }

自定义响应格式

让我们创建一个定制的响应格式。例子做点有趣和疯狂的事我返回PHP 数组。 首先,我们需要格式化程序本身。创建 components/PhpArrayFormatter.php:

    getHeaders()->set("Content-Type", "text/php; charset=UTF-8");
            if ($response->data !== null) {
                $response->content = "data) . ";
";
            }
        }
    }

组件配置:

return [
        // ...
        "components" => [
            // ...
            "response" => [
                "formatters" => [
                    "php" => "appcomponentsPhpArrayFormatter",
                ],
            ],
        ],
    ];

现在是准备使用。在 controllers/SiteController 创建一个新的方法 actionTest:

public function actionTest()
    {
        Yii::$app->response->format = "php";
        return [
            "hello" => "world!",
        ];
    }

返回如下:

     "world!",
    ];

5、AR入库前时间通过在模型重写behaviors方法实现优雅入库方式。

如下:

public function behaviors()
{
    return [
        "timestamp" => [
            "class" => TimestampBehavior::className(),
            "attributes" => [
                ActiveRecord::EVENT_BEFORE_INSERT => "creation_time",
                ActiveRecord::EVENT_BEFORE_UPDATE => "update_time",
            ],
            "value" => function() { return date("U"); // unix timestamp },
        ],
    ];
}

6、除配置组件记录不同级别日志外,也可以自定义在某个地方记录LOG日志

use yiilogLogger;
Yii::getLogger()->log("User has been created", Logger::LEVEL_INFO);

7、 ActiveForm类不让生成label标签

//方法一,通过ActiveForm类
$form->field($model, "字段名")->passwordInput(["maxlength" => true])->label(false) ?>
//方法二,通过 HTML类
Html::activeInput($type,$model,"字段名")
Yii2给必填项加星,样式如下:

div.required label:after {
    content: " *";
    color: red;
}

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

接收get和post的数据很容易,那么接收json数据呢?!没关系,看这里:

Yii::$app->request->rawBody;
9、座机和手机号码必须填写一个:

public function rules()
{
    return [
        [["telephone", "mobile"], function ($attribute, $param) {//至少要一个
            if (empty($this->telephone) && empty($this->mobile)) {
                $this->addError($attribute, "telephone/mobile至少要填一个");
            }
        }, "skipOnEmpty" => false],
    ];
}

10、where多条件查询示例:

//and复杂示例:
$time = time();
Member::find()->where(["and", ["userid" => 1, "company" =>"测试公司"], [">", "addtime", $time]]);
//SELECT * FROM `member` WHERE ((`userid`=1) AND (`company`="测试公司")) AND (`addtime` > 1447587486)
//and和or组合示例:
$query = Member::find()->where(["and", [">","userid",2], ["or", ["company" => "深圳市新民家具有限公司"], ["address" => "深圳"]]]);
//SELECT * FROM `member` WHERE (`userid` > 2) AND ((`company`="深圳市新民家具有限公司") OR (`address`="深圳"))

11、关于事务:

优雅的写法

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

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

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

12、rest风格API获取客户端提交的get和post的数组

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

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

方法一:

是经典的重写actions方法

public function actions()
    {
        return [
            "error" => [
                "class" => "yiiwebErrorAction",
            ],
            "captcha" => [
                "class" => "yiicaptchaCaptchaAction",
                "fixedVerifyCode" => YII_ENV_TEST ? "testme" : null,
            ],
        ];
    }

actions继承yiibaseActions类,并重写父类的run方法。

方法二:

site控制器如下,访问MemberController控制器下面的index方法。

class SiteController extends Controller
{
    public function actionIndex(){
     Yii::$app->runAction("member/index", ["param"=>"123"]);
    }
}
MemberController控制器如下:

class MemberController extends Controller
{
    public function actionIndex($param = "456"){
     echo "second Controller".$param;
    }
}
访问:http://www.yii.dev/site/index.html 

输出:second Controller123

14、点击下载,如下载安卓APK文件。

public function actionDownload(){
    return Yii::$app->response->setDownloadHeaders("http://xxx.com/apk/com.trade.activity.3.0.8.apk");
    //return Yii::$app->response->sendFile("./com.trade.activity.3.0.8.apk");
}

15、YII模块IP白名单设置,增加安全性

$config["modules"]["gii"] = [
     "class" => "yiigiiModule",
     "allowedIPs" => ["127.0.0.1", "::1","10.10.1.*"], 
];
$config["modules"]["debug"] = [
    "class" => "yiidebugModule",
    "allowedIPs" => ["127.0.0.1", "::1", "192.168.0.*", "192.168.33.1"],
];

16、防止 SQL 和 Script 注入

use yiihelpersHtml;
use yiihelpersHtmlPurifier;
echo Html::encode($view_hello_str) //可以原样显示代码  
echo HtmlPurifier::process($view_hello_str)  //可以过滤掉代码

17、验证某个ID值是否存在

//之前一直用$model->findOne($id);exists()方法,资源节约,有没有?!

public function validateAttribute($model, $attribute)
{
   $value = $model->$attribute;
   if (!Status::find()->where(["id" => $value])->exists()) {
       $model->addError($attribute, $this->message);
   }
}

18、批量查询

如查询并循环10000条数据。一次性拿1万条内存会有压力,通过批量查询,每次拿1000条,那么内存始终只有1000条的占有量。

foreach(Member::find()->batch(1000) as $value){
    //do something
    //print_r(count($value));
}

19、关于CSRF验证

方法一:关闭Csrf,除非必要,否则不推荐

public function init(){
    $this->enableCsrfValidation = false;
}

方法二:普通提交,form表单中加入隐藏域

方法三:ajax异步提交,加入_csrf字段

var csrfToken = $("meta[name="csrf-token"]").attr("content");
$.ajax({
  type: "POST",
  url: url,
  data: {_csrf:csrfToken},
  success: success,
  dataType: dataType
});

20、YII命令行生成数据库文件

自动列出可用的migrate文件

php yii migrate

从vendor/callmez/wechat/migrations目录下生成数据表

php yii migrate --migrationPath=@callmez/wechat/migrations

从当前应用/migrations/db1下初始化数据到db1表

php yii migrate --migrationPath=@app/migrations/db1 --db=db1

21.关联查询

//客户表Model:CustomerModel 
//订单表Model:OrdersModel
//国家表Model:CountrysModel
//首先要建立表与表之间的关系 
//在CustomerModel中添加与订单的关系
      
Class CustomerModel extends yiidbActiveRecord
{
    ...
    
    public function getOrders()
    {
        //客户和订单是一对多的关系所以用hasMany
        //此处OrdersModel在CustomerModel顶部别忘了加对应的命名空间
        //id对应的是OrdersModel的id字段,order_id对应CustomerModel的order_id字段
        return $this->hasMany(OrdersModel::className(), ["id"=>"order_id"]);
    }
     
    public function getCountry()
    {
        //客户和国家是一对一的关系所以用hasOne
        return $this->hasOne(CountrysModel::className(), ["id"=>"Country_id"]);
    }
    ....
}
      
// 查询客户与他们的订单和国家
CustomerModel::find()->with("orders", "country")->all();

// 查询客户与他们的订单和订单的发货地址
CustomerModel::find()->with("orders.address")->all();

// 查询客户与他们的国家和状态为1的订单
CustomerModel::find()->with([
    "orders" => function ($query) {
        $query->andWhere("status = 1");
        },
        "country",
])->all();

22、yii2中关闭debug后return $this->redirect($url);不能跳转,服务器报500错误。

问题分析:

1.必须 return 才能让$this->redirect($url);立马跳转, 而不执行后续代码;

2.redirect() 中指定了响应的 http status code,默认是302;

3.当执行$this->redirect($url)时,不管是否在后面加return false 、return true都没有用,还是继续执行完代码。使用header("Location:$url");exit;可以解决此问题,但是,这不是yii2的逻辑,并不完美。

解决办法:

1.在正常情况下,使用

return $this->redirect($url);

2.在解决方案1不生效时,用

$this->redirect($url);Yii::$app->response->send();

3.在解决方案2不生效时,用

$this->redirect($url);Yii::$app->end();

总结:

用Yii::$app->end();、Yii::$app->response->send();
不管在actionXXX还是init方法都能终止代码,而return只能在action终止代码,是因为在init()里仅仅是代码的执行,return只是代码返回。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/31372.html

相关文章

  • 基于Yii2的应用开发引擎RageFrame

    摘要:多入口模式,多入口分为后台前端,微信,其他或接口对接,不同的业务不同的设备进入不同的入口。对接微信公众号,使用了一款优秀的微信非官方,系统内已集成了该,调用方式会在文档说明,也可直接看其文档进入深入开发。 RageFrame 为二次开发而生,让开发变得更简单。 前言 RageFrame项目创建于2016年4月16日,基于Yii2框架开发的应用开发引擎,目前正在成长中,目的是为了集成更多...

    enda 评论0 收藏0
  • RageFrame 一个 Yii2 + AdminLET 免费开源多商户通用后台管理系统

    摘要:极致的插件机制,系统内的系统,安装和卸载不会对原来的系统产生影响强大的功能完全满足各阶段的需求,支持用户多端访问后台微信前台等,系统中的系统。多入口模式,多入口分为后台前端,微信,对内接口,对外接口,不同的业务,不同的设备,进入不同的入口。 RageFrame 2.0 为二次开发而生,让开发变得更简单 项目地址:https://github.com/jianyan74/... 前言 这...

    lordharrd 评论0 收藏0
  • RageFrame 一个 Yii2 + AdminLET 免费开源多商户通用后台管理系统

    摘要:极致的插件机制,系统内的系统,安装和卸载不会对原来的系统产生影响强大的功能完全满足各阶段的需求,支持用户多端访问后台微信前台等,系统中的系统。多入口模式,多入口分为后台前端,微信,对内接口,对外接口,不同的业务,不同的设备,进入不同的入口。 RageFrame 2.0 为二次开发而生,让开发变得更简单 项目地址:https://github.com/jianyan74/... 前言 这...

    sunny5541 评论0 收藏0
  • RageFrame 一个 Yii2 + AdminLET 免费开源多商户通用后台管理系统

    摘要:极致的插件机制,系统内的系统,安装和卸载不会对原来的系统产生影响强大的功能完全满足各阶段的需求,支持用户多端访问后台微信前台等,系统中的系统。多入口模式,多入口分为后台前端,微信,对内接口,对外接口,不同的业务,不同的设备,进入不同的入口。 RageFrame 2.0 为二次开发而生,让开发变得更简单 项目地址:https://github.com/jianyan74/... 前言 这...

    Ali_ 评论0 收藏0
  • PHP回顾之Composer

    摘要:本文简要回顾相关概念和用法。相比之下已是明日黄花。分别对应的命令是根据关键字查找依赖包,例如查找本人发布的包。作为目前包依赖管理的最佳工具,值得每一位开发人员掌握。 转载请注明文章出处:https://tlanyan.me/php-review... PHP回顾系列目录 PHP基础 web请求 cookie web响应 session 数据库操作 加解密 Composer是PHP...

    Ocean 评论0 收藏0

发表评论

0条评论

W_BinaryTree

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<