共计 7543 个字符,预计需要花费 19 分钟才能阅读完成。
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 只是代码返回。