1. 程式人生 > >Yii2 常用操作總結

Yii2 常用操作總結

時區配置

#common\config\main.php
return [
'timeZone' => 'Asia/Shanghai',
]

a標籤

<?= Html::a('Delete', 
['delete', 'id' =>$model->id], 
['class' => 'btn btn-danger',
'data' => ['confirm' => 'Are you sure you want to delete this item?','method' => 'post',
  ],
]) ?>
#第一個引數是超連結的標題。它不會被轉碼,所以如果是使用者輸入資料, 你需要使用 Html::encode() 方法進行轉碼。第二個引數是 <a 標籤的 href 屬性的值。 關於該引數能夠接受的更詳細的資料值,請參閱 Url::to()。 第三個引數是標籤的屬性陣列。

#這個和上面比較看可能更好理解
<?= Html::a('已授權列表', ['cancel-grant', 'id' => yii::$app->request->get('id'),'rType'=>yii::$app->request->get('rType')], [
          'class' => 'btn btn-success','style' => 'margin-bottom:10px;'
      ]) ?>

展示圖片

 [
     'attribute' => 'cover',
    'format' => 'raw',
    'value' => function($model){
         return Html::img("{$model->cover}",['alt' => '縮圖', 'width' => 80]);
      }
],

獲取最後一次插入的id

Yii::app()->db->getLastInsertId();

返回欄位的一位陣列

Member::find()->select('userid')->asArray()->column();
# 或者:
\yii\helpers\ArrayHelper::getColumn(Member::find()->all(), 'userid')

rules驗證

['catid', 'in', 'range' => category::find()->select('id')->asArray()->column()],
#當然,這個也可以通過下面這樣子寫,一樣的:
['catid', 'in', 'range' => \yii\helpers\ArrayHelper::getColumn(category::find()->all(), 'catid')],

友好時間訪問

Yii::$app->formatter->asRelativeTime($value, $referenceTime = null)  

使用不同的響應型別或者自定義響應型別

#有效的格式:
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"]
}

元件配置

return [
    'components' => [
        'cache' => [
            'class' => 'yii\caching\FileCache',
        ],
        'redis' => [
            'class' => 'yii\redis\Connection',
            'hostname' => '127.0.0.1',
            'port' => 6379,
            'database' => 0,
            'password' => '!chxlqqx!',
        ],
    ],
];
#在專案中通過yii::$app->redis呼叫

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 },
        ],
    ];
}

除配置元件記錄不同級別日誌外,也可以自定義在某個地方記錄LOG日誌

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

Yii2 獲取介面傳過來的 JSON 資料:

接收get和post的資料很容易,那麼接收json資料呢?!沒關係,看這裡:
Yii::$app->request->rawBody;

座機和手機號碼必須填寫一個:

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

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`='深圳'))

關於事務:

優雅的寫法
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;
}

rest風格API獲取客戶端提交的get和post的陣列

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

一個控制器呼叫其他控制器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.html 

輸出:second Controller123

點選下載,如下載安卓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");
}

YII模組IP白名單設定,增加安全性

$config['modules']['gii'] = [
     'class' => 'yii\gii\Module',
     'allowedIPs' => ['127.0.0.1', '::1','10.10.1.*'], 
];
$config['modules']['debug'] = [
    'class' => 'yii\debug\Module',
    'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.33.1'],
];

防止 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>程式碼

驗證某個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);
   }
}

批量查詢

#如查詢並迴圈10000條資料。一次性拿1萬條記憶體會有壓力,通過批量查詢,每次拿1000條,那麼記憶體始終只有1000條的佔有量。

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

關於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
});

YII命令列生成資料庫檔案

自動列出可用的migrate檔案

php yii migrate
 從vendor/callmez/wechat/migrations目錄下生成資料表

php yii migrate [email protected]/wechat/migrations
從當前應用/migrations/db1下初始化資料到db1表

php yii migrate [email protected]/migrations/db1 --db=db1

關聯查詢

//客戶表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();

yii2中關閉debug後return t h i s &gt; r e d i r e c t ( this-&gt;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/phpsir原創,未經授權禁止轉載】

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

Yii2 修改導航欄

#後臺 
#views/layouts/main.php
<?php
    NavBar::begin([
        'brandLabel' => Yii::$app->name,
        'brandUrl' => Yii::$app->homeUrl,
        'options' => [
            'class' => 'navbar-inverse navbar-fixed-top',
        ],
    ]);
    $menuItems = [
        ['label' => '小說', 'url' => ['/book/index']],
        ['label' => '漫畫', 'url' => ['/comic/index']],
        ['label' => '渠道商', 'url' => ['/channel/index']],
        [
            'label' => '佇列',
            'items' => [
                ['label' => '狀態', 'url' => '/queue/index'],
                ['label' => '任務新增', 'url' => '/queue/add'],
            ],
        ],
    ];

修改專案名稱,以及修改專案為中文

return [
    'id' => 'app-backend',
    'name' => '棉花糖',#此處修改專案名稱
    'language' => 'zh-CN',#修改專案為中文
    ...
    ]

修改searchModel 新增查詢條件

 public function search($params)
    {
        $query = Book::find();

        // add conditions that should always apply here

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
        ]);

        $this->load($params);

        if (!$this->validate()) {
            // uncomment the following line if you do not want to return any records when validation fails
            // $query->where('0=1');
            return $dataProvider;
        }
        // grid filtering conditions
        $query->andFilterWhere([
            'id' => $this->id,
            'sourceId' => $this->sourceId,
            'status' => $this->status,
            'finished' => $this->finished,
            'chapterCount' => $this->chapterCount,
            'lastCid' => $this->lastCid,
            'gender' => $this->gender,
            'mainCate' => $this->mainCate,
            'subCate' => $this->subCate,
            'score' => $this->score,
            'words' => $this->words,
            'orgCreated' => $this->orgCreated,
            'orgUpdate' => $this->orgUpdate,
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at,
        ]);

        $query->andFilterWhere(['like', 'orgId', $this->orgId])
            ->andFilterWhere(['like', 'title', $this->title])
            ->andFilterWhere(['like', 'author', $this->author])
            ->andFilterWhere(['like', 'cover', $this->cover])
            ->andFilterWhere(['like', 'tags', $this->tags])
            ->andFilterWhere(['like', 'intro', $this->intro])
            ->andFilterWhere(['like', 'copyright', $this->copyright]);
        if($this->cancelId){
            $query->andFilterWhere(['in','id',$this->cancelId]);
        }
        if($this->grantedId){
            $query->andFilterWhere(['not in', 'id', $this->grantedId]);
        }
        return $dataProvider;
    }

控制器向公共模板傳送資料

#方法一:
#控制器中:
Yii::$app->view->params['name'] = $name;
#檢視中
$this->params['name']
#方法二
#控制器
$this->name = $name;
#檢視中
$this->context->name;

獲取yii版本

Yii::getVersion()