输出sql语句
$query = self::findOne(1);
echo $query->createCommand()->getRawSql();
复杂的sql语句拼接
在model中使用复杂的sql时,Yii会出现解析错误的情况。例如
$query = User::find()->all();
$query->select("*,FROM_UNIXTIME('create_time','%Y-%m-%d') as date");
以上生成的sql语句中,yii会把````FROM_UNIXTIME(‘create_time’,‘%Y-%m-%d’)` ```当做是一个字段,以至报错。
此时我们在头部引入 use yii\db\Expression;使用方法如下
use yii\db\Expression;
$query = User::find()->all();
$query->select(new Expression("*,FROM_UNIXTIME('create_time','%Y-%m-%d') as date"));
YII框架自带的JSON方法
使用AR获取的数据列表,不能直接使用json_encode进行序列化,会丢失数据。使用yii\helpers\Json::encode($data);进行序列化,可以保证数据的完整性,要注意命名空间的大小写。mmp,这个问题耽误老子俩小时
使用自定义的model
即不指定表名,主要用于验证用户提交的数据,自己新建的继承AR的model,需要注意:
①不能使用$model->attributes = $param赋值,只能使用$model->load($param,'')
②不能使用场景,会提示表不存在
修改数据提供器数据
场景1
通过数据提供器获取数据列表后,某些字段我们可能想要单独赋值,比如当username为空时,我们想要给username赋值为“游客”。
$list = $dataProvider->getModels();
foreahc($list as $val){
//usernam必须是主表中的字段
if(!$val->username) $val->username = '游客';
}
$dataProvider->setModels($list);
但是上面的赋值方式中,当username不是主表字段时,会报错。比如数据提供器查询中,使用了with关联users,users作为一个关联值,修改时会提示不能修改只读属性。
这种情况下,我们需要在数据提供器model中添加如下代码
//model中加入如下代码
public function __set($attributes,$val){
if($attributes == 'users') $this->$attributes = $val;
}
//赋值代码
$list = $dataProvider->getModels();
foreahc($list as $val){
if(!$val->users) $val->users= object(['username'=>'游客']);
}
$dataProvider->setModels($list);
数据模型中,会追加一个可读的users对象属性。
当我们再次通过getModels获取models数组,遍历models数组,使用其成员model调用users时,就会获取到users属性的值了
场景2
但是上面的方法存在局限性。当我们使用\yii\rest\Serialize 的serialize()方法序列化数据提供器时,通过上述方法新增的属性并没返回。这是因为serialize()方法只把主表的字段进行了返回,如果想返回新增的字段,就需要修改model的attribute值,代码如下
public function attributes()
{
$attribute = parent::attributes();
$attribute[] = 'users';
return $attribute;
}
注意: 在使用该方法添加新的字段,并在实例化对象中给该字段赋值后,不能使用model对象的save()方法进行数据的添加和修改,这会把新增的字段添加到sql操作中,而数据表中根本不存在该字段,导致不错。
yii框架接口分页
Yii框架的数据提供及ActiveDataProvider 配合页面小部件可以实现内容分页。当我们使用yii写前台接口时,也可以使用数据提供器来实现数据的分页,步骤如下
//首先,获取数据提供器
$data = new ActiveDataProvider([
'query' => $query
]};
//然后使用yii/rest/serializer类中的serializer方法序列化数据提供器的数据
$serializer = new yii/rest/serializer();
return $serializer->serialize($data);
执行serialize() 方法后,会在返回的hearder信息中添加分页相关的信息。方法说明如下图
数据验证
可查看官方文档:核心验证器
这里是提示下,文件验证的时候,设置
[‘primaryImage’, ‘file’, ‘extensions’ =>[‘png’,‘jpg’,‘gif’],‘maxSize’=>102410241024],‘checkExtensionByMimeType’=>false]
checkExtensionByMimeType默认为true,需要设置为false。
是否通过文件的 MIME 类型来判断其文件扩展。 若由 MIME 判定的文件扩展与给定文件的扩展不一样,则文件会被认为无效
with的使用
1、语法
yii2联表查询除了可以使用join,还可以使用with进行联表查询。有with和joinWith两个方法可使用。
差异:
with:以主表内容为主,关联表的筛选条件对主表无效
joinWith:以主表内容为主,关联表查询条件会影响主表的查询内容
//多个关联多个表时,joinWith内以数组方式设置参数
$query = CpOrderFission::find()->joinWith([
//自2.0.7开始,可直接在关联表后加字符串,作为关联别名
//不需要再使用$q->from(['su' => User::tableName()])或$q->alias('su')来设置别名
'shareUsers su' => function($query)use($where){
$query
//追加当前关联表的查询条件
->andFilterWhere($where)
//追加当前关联和主表的关联条件
->onCondition($where2)
//嵌套关联,即主表A关联b,b关联c;需要在shareUsers的主表model中,添加getRegister方法
->joinWith('register');
},
'orders o',
])
//当需要查询额外的字段时,需要设置select
->select([
CpOrderFission::tableName().'.*',
//新增的set_num字段需要在主表model中声明后才能使用
'count(case when is_set=1 then id end) as set_num',
]);
2、关联子查询
//建立子查询sql
$sub_query = (new \yii\db\Query())->from('table_name')->where('')->groupBy('order_id');
//关联
$query->leftJoin(['fx'=>$sub_query],'fx.id=table_name.id');
命令行执行yii控制器方法
可以通过yii框架中,项目根目录中的yii文件访问
yii代码如下
<?php
/**
* Yii console bootstrap file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
require(__DIR__ . '/vendor/autoload.php');
require(__DIR__ . '/vendor/yiisoft/yii2/Yii.php');
require __DIR__ . '/common/config/bootstrap.php';
//cli运行模式配置文件
$config = require(__DIR__ . '/common/config/console.php');
$application = new yii\console\Application($config);
//需要访问的应用主体的别名配置文件
require __DIR__ . '/appapi/common/config/bootstrap.php';
$exitCode = $application->run();
exit($exitCode);
yii文件配置好后,配置console.php配置文件,如下
<?php
$params = require(__DIR__ . '/params.php');
$db = require(__DIR__ . '/database.php');
$config = [
'id' => 'basic-console',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
//当应用不分模块时,需配置控制器的命名空间
//'controllerNamespace' => 'app\commands',
//当应用分多模块时,需配置模块的命名空间
'modules' => [
'v1' => 'app\modules\v1\Module',
],
//方法中用到的组件也要在这里配置
'components' => [
'cache' => [
'class' => 'yii\caching\FileCache',
],
'db' => $db,
],
'params' => $params,
/*
'controllerMap' => [
'fixture' => [ // Fixture generation command line.
'class' => 'yii\faker\FixtureController',
],
],
*/
];
if (YII_ENV_DEV) {
// configuration adjustments for 'dev' environment
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
'class' => 'yii\gii\Module',
];
}
return $config;
控制器文件,如下
<?php
namespace app\modules\v1\controllers;
use yii\console\Controller;
//此处继承console下的controller,专门用于cli执行
class Message2Controller extends Controller
{
public function actionWork(){
echo 'Hello World';
}
}
在cmd下,先cd到yii文件目录下,然后执行
//多模块执行
php yii v1/message2/work
//单模块执行
php yii message2/work