動態

詳情 返回 返回

YII2項目幾個常用技能知識總結 - 動態 詳情

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 yii\helpers\VarDumper;
//使用
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();

或者:

\yii\helpers\ArrayHelper::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' => \yii\helpers\ArrayHelper::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 = \yii\web\Response::FORMAT_JSON;
$items = ['some', 'array', 'of', 'data' => ['associative', 'array']];
return $items;

}

返回:

{

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

}

自定義響應格式

讓我們創建一個定製的響應格式。例子做點有趣和瘋狂的事我返回PHP 數組。 首先,我們需要格式化程序本身。創建 components/PhpArrayFormatter.php:

<?php
namespace app\components;
use yii\helpers\VarDumper;
use yii\web\ResponseFormatterInterface;
class PhpArrayFormatter implements ResponseFormatterInterface
{

public function format($response)
{
    $response->getHeaders()->set('Content-Type', 'text/php; charset=UTF-8');
    if ($response->data !== null) {
        $response->content = "<?php\nreturn " . VarDumper::export($response->data) . ";\n";
    }
}

}

組件配置:

return [

// ...
'components' => [
    // ...
    'response' => [
        'formatters' => [
            'php' => 'app\components\PhpArrayFormatter',
        ],
    ],
],

];

現在是準備使用。在 controllers/SiteController 創建一個新的方法 actionTest:

public function actionTest()
{

Yii::$app->response->format = 'php';
return [
    'hello' => 'world!',
];

}

返回如下:

<?php
return [

'hello' => '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 yii\log\Logger;
\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' => 'yii\web\ErrorAction',
        ],
        'captcha' => [
            'class' => 'yii\captcha\CaptchaAction',
            'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
        ],
    ];
}

actions繼承yii\base\Actions類,並重寫父類的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...

輸出: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' = [

 'class' => 'yii\gii\Module',
 'allowedIPs' => ['127.0.0.1', '::1','10.10.1.*'], 

];

$config'modules' = [

'class' => 'yii\debug\Module',
'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.33.1'],

];

16、防止 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>代碼

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表單中加入隱藏域

<input name="_csrf" type="hidden" id="_csrf" value="<?= Yii::$app->request->csrfToken ?>">

方法三: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 \yii\db\ActiveRecord
{

...

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的邏輯,並不完美。

解決辦法:

【本文由php_sir的博客 http://blog.sina.com.cn/phpsi...

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只是代碼返回。

Add a new 評論

Some HTML is okay.