YII2 where查询条件整理

本文转自:https://www.yiichina.com/tutorial/1405

官方文档:http://www.yiichina.com/doc/guide/2.0/db-query-builder

文章涉及where、 addParams 、filterWhere 、andWhere、orWhere、 andFilterWhere()、 orFilterWhere()、andFilterCompare()
但是格式是一样的

字符串格式,例如:'status=1'
哈希格式,例如: ['status' => 1, 'type' => 2]
操作符格式,例如:['like', 'name', 'test']

字符串和哈希格式很好理解,我们来看看操作符格式,因为操作符格式可以组成相对复杂的查询语句
最简单的就是官方给的例子

$status = 10;
$search = 'yii';

$query->where(['status' => $status]);

if (!empty($search)) {
    $query->andWhere(['like', 'title', $search]);
}
生成的语句就是
... WHERE (`status` = 10) AND (`title` LIKE '%yii%')

操作符格式

[操作符, 操作数1, 操作数2, ...]
0cb4d39e-418f-4183-a900-8a4ab5b1aadf.png

第一个参数是操作符
操作符包括and、or、 like、in、 between等
第二个第三个都是操作数

第一种最简单的就是上面提到的例子
 andWhere(['like', 'title','搜索的标题']);
生成的语句
... WHERE (`status` = 10) AND (`title` LIKE '%yii%')
第二种
addWhere(['and', 'id=1', 'name=2']);
生成的语句
... WHERE id=1 AND name=2
第三种
addWhere(['and', 'type=1', ['or', 'id=1', 'id=2']]);
生成的语句
... WHERE type=1 AND (id=1 OR id=2);
第四种
->andWhere(['or like','name',['哈哈','苦苦']]);
生成的语句
 WHERE `name` LIKE '%哈哈%' OR `name` LIKE '%苦苦%';
 第五种
 addWhere(['or',['like','name','哈哈'],['like','title','苦苦']]);//操作符格式的嵌套
 生成的语句
... WHERE (`status`=1) AND ((`name` LIKE '%哈哈%') OR (`title` LIKE '%苦苦%'))

$query->andWhere(new Expression(‘FIND_IN_SET(‘1,size’)’));+
生成的语句
… WHERE id=1 AND FIND_IN_SET(1, size)
//size的值:1,2,3,4,5

yii2记数,自动累加

文章一般都有统计浏览次数的需求,一般小型项目的做法就是直接 update 数据库中的某个字段。在 Yii 中怎么实现呢?请往下看:

实现

方式一

Yii2 中有这个 updateAllCounters 静态方法,这种方式是最快并且最省事的实现方式,代码示例如下:

Topic::updateAllCounters(['view_count' => 1], ['id' => $id]);// 实现的效果就是 view_count + 1,1根据你的需求可以是正数也可以是负数。

如果你的条件比较复杂你可以这样写:

Topic::updateAllCounters(['view_count' => 1], ['and', ['xxx' => 0, 'yyy' => 2], ['>', 'zzz', $time]);

如果你现在的需求是:更新一个字段的值,一个字段的值 +1,你可以试着用这种方式去实现:

 Topic::updateAll(    ['view_count' => new Expression('`view_count` + 1'), 'updated_at' => time()],    ['id' => $id]);

PS:此处的 view_count 字段默认值切记不能设置为 null

Expression 是表达式的意思,可以实现更多特殊 SQL,想了解更多,可以去搜索一下文档。

方式二

当然你还可以这样去实现:

$model = Post::findOne($id);$model->updateCounters(['view_count' => 1]);

yii2 swift mailer 发送邮件不成功的问题

今天调试yii2自带的swift mailer发邮件,开始调试时,发送用的send()方法始终返回true,但是就是没有收到邮件,很是纳闷,于是开始了半个晚上的调试之旅,我把调试过程发出来,希望后面的小伙伴能少走一些弯路。
首先,根据热心网友的文章,配置邮箱的基础信息,我用的base项目,所以我的配置文件是web.php,配置内容为:
        ‘mailer’ => [
            ‘class’ => ‘yii\swiftmailer\Mailer’,
            ‘transport’ => [
                ‘class’ => ‘Swift_SmtpTransport’,
                ‘host’ => ‘smtp.163.com’,
                ‘username’ => ‘xxx@163.com’,
                ‘password’ => ‘xxx’,
                ‘port’ => ’25’,
                ‘encryption’ => ‘tls’,//    tls | ssl

            ],
            ‘messageConfig’=>[
                ‘charset’=>’UTF-8’,
                ‘from’=>[‘xxx@163.com’=>’admin’]
            ],
            ‘useFileTransport’ => false,
        ],
然后开始写了一个测试用的控制器,内容如下:
    public function actionMailer()
    {
        $mail= Yii::$app->mailer->compose();
        $mail->setTo(‘10000@qq.com’);
        $mail->setSubject(“Test title”);
        $mail->setTextBody(‘Test content’);
        //$mail->setHtmlBody(“Test HTML”);
        var_dump($mail->send());
    }
好了,信心满满的开始测试了,执行链接,满心欢喜的去查看QQ邮箱了,但是左等右等,前等后等,丫的就是没有,重新发送,还是没有,但是send()的返回值明明就是true!
 于是开始排错,总结了一下,出错的可能位置在以下几点:
 不同邮箱的host是不同的
如果是163邮箱,password是授权码
userFileTransport要设置成false,否则只会在runtime下生成缓存文件,不会真正发送
一一排查,确信没有错误,太奇怪了,于是我决定直接调用swiftmailer试一下,于是新建了下面的控制器:
    public function actionMailer2()
    {
        $mailer = new \yii\swiftmailer\Mailer();
        $mailer->transport=[
            ‘class’ => ‘Swift_SmtpTransport’,
            ‘host’ => ‘smtp.163.com’,
            ‘username’ => ‘xxxx@163.com’,
            ‘password’ => ‘xxxx’,
            ‘port’ => ’25’,
            ‘encryption’ => ‘tls’,//    tls | ssl
        ];
        $mailer->messageConfig=[
            ‘charset’=>’UTF-8’,
            ‘from’=>[‘xxxx@163.com’=>’admin’]
        ];
        $mailer->useFileTransport = false;
        $mail= $mailer->compose();
        $mail->setTo(‘10000@qq.com’);
        $mail->setSubject(“Test title”);
        $mail->setTextBody(‘Test content’);
        var_dump($mail->send());
    }

哎哟我去!发送成功了!这是为啥呢?首先证明这个类确是是可以发送邮件的了,那么下一步要细细的分析这两段代码区别在何处了。
我分别打印了两个类构造完成后的结果:
    public function actionMailer()
    {
        echo ‘<pre>’;
        var_dump(Yii::$app->mailer);
    }

    public function actionMailer2()
    {
        $mailer = new \yii\swiftmailer\Mailer();
        $mailer->transport=[
            ‘class’ => ‘Swift_SmtpTransport’,
            ‘host’ => ‘smtp.163.com’,
            ‘username’ => ‘xxxx@163.com’,
            ‘password’ => ‘xxxx’,
            ‘port’ => ’25’,
            ‘encryption’ => ‘tls’,//    tls | ssl
        ];
        $mailer->messageConfig=[
            ‘charset’=>’UTF-8’,
            ‘from’=>[‘xxxx@163.com’=>’admin’]
        ];
        $mailer->useFileTransport = false;
        echo ‘<pre>’;
        var_dump($mailer);
    }

在长长的内容中慢慢的对比,终于发现了端倪,
第一个方法中:[“useFileTransport”]=>bool(true)
第二个方法中:[“useFileTransport”]=>bool(false)
上面也说过了,useFileTransport必须设置成false才能发送成功,那问题总算是找到了,那为什么会出现这样的问题呢?我上面明明是设置过的,为什么没生效?难道是测试环境的原因吗?
我测试使用的url是http://goonwin.com/index-test.php?r=liyang/mailer,注意那个index-test.php,就是他的原因了,于是我把index-test.php改成index.php立马发送成功了,丫的,这么隐蔽一个坑啊!!!
但是我还是希望测试环境可以发送邮件的,于是,稍微改动了一下调用的方法:
    public function actionMailer()
    {
        $mail = Yii::$app->mailer;
        $mail->useFileTransport = false;
        $mail= $mail->compose();
        $mail->setTo(‘10000@qq.com’);
        $mail->setSubject(“Test title”);
        $mail->setTextBody(‘Test content’);
        var_dump($mail->send());
    }

Oh,终于可以发送了,看到论坛中有些朋友也在问同样的问题,估计现在你已经可以解决了。洋洋洒洒写了这么多,其实就一个目的,希望能给新手一点调试的经验吧,老手你当然乐呵乐呵就得了。
浪费一晚上青春,睡觉!

Yii2.0实现的批量更新及批量插入功能示例

本文实例讲述了Yii2.0实现的批量更新及批量插入功能。分享给大家供大家参考,具体如下:

批量更新

方法1

/**
* 批量更新循环周期
* @param array $condition
* $condition = ['advertise_id' => '','status' => '', 'weekdays'=>[1,2,3]] 查询条件
* $params = ['status' => '']
* @param $params
* @return bool
*/
public function batchUpdateAdSchedule($condition = [], $params)
{
  if (count($condition) == 0 || !is_array($condition) || count($params) == 0) {
    return false;
  }
  $conditions = ' 1 = 1 ';
  $bind = [];
  if (array_key_exists('advertise_id', $condition) && !empty($condition['advertise_id'])) {
    $conditions .= ' AND `advertise_id` = :advertiseId';
    $bind['advertiseId'] = $condition['advertise_id'];
  }
  if (array_key_exists('status', $condition) && !empty($condition['status'])) {
    $conditions .= ' AND `status` = :status';
    $bind['status'] = $condition['status'];
  }
  $result = AdvertiseSchedule::updateAll($params, $conditions, $bind);
  return $result > 0 ? true : false;
}

方法2

/**
* 批量更新商品销量
* @param $params
* @return bool|int
* @throws \yii\db\Exception
*/
public function batchUpdateSalesNum($params)
{
  if (count($params) == 0 || !is_array($params)) {
    return false;
  }
  $sql = '';
  foreach ($params as $key => $value) {
    $sql .= 'UPDATE `morefun`.`mbb_goods` SET `sale_num` = `sale_num` -' . $value['amount'] . ' WHERE `id` =' . $value['goods_id'] . ';';
  }
  $result = Yii::$app->db->createCommand($sql)->execute();
  return $result == 1 ? true : false;
}

批量插入

/**
* 批量插入
* @param $params
* @return int
* @throws \yii\db\Exception
*/
public function batchAddShopClassConn($params)
{
  $connection = Yii::$app->db;
  $queryBuilder = $connection->queryBuilder;
  /*$sql = $queryBuilder->batchInsert('user', ['name', 'age'], [
    ['Tom', 30],
    ['Jane', 20],
    ['Linda', 25],
  ]);*/
  $sql = $queryBuilder->batchInsert(shopClassConn::tableName(),
    ['shop_id', 'class_id'], $params);
  return $connection->createCommand($sql)->execute();
}

关于上一页与下一页实现细节

我想要把题库设计一下翻页功能,Mysql语句也很简单,在本地测试一点问题都没有,但是一放到服务器上便提示内存资源耗竭,最后在查看了一些资料后,在后面加了一个limit 1,如此便跑得飞快:

实现代码:

    public static function PrevQuestion($id,$uid=null,$testpaper=null)
    {
        $query = Question::find()->where(['<','id',$id]);

        if($uid)
        {
            $query->andWhere(['author'=>$uid]);
        }

        if($paper)
        {
            $query->LeftJoin('sq_testpaperinfo t','t.paper_id='.$paper_id);
        }

        $query->orderBy('id DESC');

        $query->limit(1);

        return $query->one();
    }

    public static function NextQuestion($id,$uid=null,$testpaper=null)
    {
        $query = Question::find()->where(['>','id',$id]);

        if($uid)
        {
            $query->andWhere(['author'=>$uid]);
        }

        if($paper)
        {
            $query->LeftJoin('sq_testpaperinfo t','t.paper_id='.$paper_id);
        }

        $query->orderBy('id DESC');
        $query->limit(1);

        return $query->one();
    }

下面是参考内容:

/**
* 获取当前记录的上一条记录
* @param seq
* @return
*/
@Select("select title, random_code from tb_blog where seq < ${seq} order by seq desc limit 1 ")
public Map<String,Object> getPreviousBlog(@Param("seq") long seq);

/**
* 获取当前记录的下一条记录
* @param seq
* @return
*/
@Select("select title, random_code from tb_blog where seq > ${seq} order by seq asc limit 1 ")
public Map<String,Object> getPostBlog(@Param("seq") long seq);

seq 是自增序列,random_code是id,title是博客标题。

seq不是主键,要使seq自增,先添加seq字段或建表时创建,再将seq添加unique索引,再使seq auto_increment,因为自增长列必须先是unique key或primary key。

使用phpword获取doc中的表格数据

1. 首先确定使用phpword是可以读取word文档中表格里面的数据, 使用的phpword版本0.17.0

1composer require "phpoffice/phpword"

2.关键词及包含原理 (这里只做简单概述)

本人做博文喜欢直接贴代码,直接用。可这个不太行啊,因为输入不统一,word格式样式太多,输出也不统一,有的要输出数据,有的要输出word或者html,所以这里就追一下原理(可能不严谨但是便于理解)

关键词

section(部分) : phpword中将word文档分为若干个section(部分)

element(元素) : 每个section包含若干个element(元素)、文本、图片,元素分为文本元素、表格元素、其他(未涉及不做讨论)

textRun(文本元素) : 每个文本集合包含多个文本

text(文本) : 为字符或者图片

table(表格元素) : 每个表格元素包含多个行 row

row(行) : 每个行包含多个列 cell

cell(列) : 每个列包含多个textRun(文本元素) 这里没错,就是包含多个文本元素(表格元素也可以但是没人在word表格的某一个格里再来一个表格吧)

各个节点之间的关系图

3.代码实现(本地测试已通)

<?php
/**
 * Created by PhpStorm.
 * User: parker
 * Date: 2020/10/18
 * Time: 16:09
 */

namespace common\services;


class WordService extends BaseService
{

    public static function importWord($info)
    {
        $word  = self::getWord($info['path']);
        dd($word);
    }

    /**
     * 获取word文档内容
     * @param string $path
     * @return array
     */
    public static function getWord($path = '')
    {
        //加载word文档,使用phpword处理
        $phpWord = \PhpOffice\PhpWord\IOFactory::load($path);
        return self::getNodeContent($phpWord);
    }

    /**
     * 根据word主节点获取分节点内容
     * @param $word
     * @return array
     */
    public static function getNodeContent($word)
    {
        $return = [];
        //分解部分
        foreach ($word->getSections() as $section)
        {
            if ($section instanceof \PhpOffice\PhpWord\Element\Section) {
                //分解元素
                foreach ($section->getElements() as $element)
                {
                    //文本元素
                    if ($element instanceof \PhpOffice\PhpWord\Element\TextRun) {
                        $text = '';
                        foreach ($element->getElements() as $ele) {
                            $text .= self::getTextNode($ele);
                        }
                        $return[] = $text;
                    }
                    //表格元素
                    else if ($element instanceof \PhpOffice\PhpWord\Element\Table) {
                        foreach ($element->getRows() as $ele)
                        {
                            $return[] = self::getTableNode($ele);
                        }
                    }
                }
            }
        }
        return $return;
    }

    /**
     * 获取文档节点内容
     * @param $node
     * @return string
     */
    public static function getTextNode($node)
    {
        $return = '';
        //处理文本
        if ($node instanceof \PhpOffice\PhpWord\Element\Text)
        {
            $return .= $node->getText();
        }
        //处理图片
        else if ($node instanceof \PhpOffice\PhpWord\Element\Image)
        {
            $return .= self::pic2text($node);
        }
        //处理文本元素
        else if ($node instanceof \PhpOffice\PhpWord\Element\TextRun) {
            foreach ($node->getElements() as $ele) {
                $return .= self::getTextNode($ele);
            }
        }
        return $return;
    }

    /**
     * 获取表格节点内容
     * @param $node
     * @return string
     */
    public static function getTableNode($node)
    {
        $return = '';
        //处理行
        if ($node instanceof \PhpOffice\PhpWord\Element\Row) {
            foreach ($node->getCells() as $ele)
            {
                $return .= self::getTableNode($ele);
            }
        }
        //处理列
        else if ($node instanceof \PhpOffice\PhpWord\Element\Cell) {
            foreach ($node->getElements() as $ele)
            {
                $return .= self::getTextNode($ele);
            }
        }
        return $return;
    }

    /**
     * 处理word文档中base64格式图片
     * @param $node
     * @return string
     */
    public static function pic2text($node)
    {
        //获取图片编码
        $imageData = $node->getImageStringData(true);
        //添加图片html显示标头
        $imageData = 'data:' . $node->getImageType() . ';base64,' . $imageData;
        $return = '<img src="'.$imageData.'">';
        return $return;
    }
    /**
     * 处理word文档中base64格式图片
     * @param $node
     * @return string
     */
    public static function pic2file($node)
    {
        //图片地址(一般为word文档地址+在word中的锚点位置)
        $imageSrc  = 'images/' . md5($node->getSource()) . '.' . $node->getImageExtension();
        $imageData = $node->getImageStringData(true);
        //将图片保存在本地
        file_put_contents($imageSrc, base64_decode($imageData));
        return $imageSrc;
    }

    /**
     * 将word转化为html(转换存储html文件后展示)
     * @param $path
     * @throws \PhpOffice\PhpWord\Exception\Exception
     */
    public static function word2html($path)
    {
        $phpWord = FileImportService::getOne($path);
        //转为html处理
        $xmlWriter  = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, "HTML");
        $path = pathinfo($path);
        $fileName = $path['dirname'] . '/' . $path['filename'] . '.html';
        $xmlWriter->save($fileName);
        $html = file_get_contents($fileName);
        echo $html;
        die;

    }


}

关于word模板导入中OLEObject的二进制文件转图片的方法

很久以前就想要做这个事情,但时间不允许,当然更多的是技术不行,总期待着有现成的解决方案,当然现成的PHPWord可以解决很多事情,但还是遇到的新的问题,如下:

【题文】1.集合<Object: word/embeddings/oleObject1.bin>,<Object: word/embeddings/oleObject2.bin>,则<Object: word/embeddings/oleObject3.bin>( )。A、<Object: word/embeddings/oleObject4.bin>B、<Object: word/embeddings/oleObject5.bin>C、<Object: word/embeddings/oleObject6.bin>D、<Object: word/embeddings/oleObject7.bin>【答案】B【解析】∵<Object: word/embeddings/oleObject8.bin>,∴<Object: word/embeddings/oleObject9.bin>,∵<Object: word/embeddings/oleObject10.bin>,故选B。【结束】

上面是读取word的一种情形,所以就考虑把word文档中的公式都变成图片。

下面是探寻到的方法:

第一步:把word保存为html格式

第二步:用word(或WPS)重新打开html文件,并保存为docx格式文件

经过上面两步就实现了利用Mathtype等公式编辑器编辑的公式转图片的效果,非常好,现在可以读取了,但新的问题又来了,有些公式是利用word直接插入的公式,现在已经变形了!!!,呜呜呜……


今天查寻资料得知应该可能使用Apache POI解决这个文件读取的问题,但可惜是基于java的

地址:https://blog.csdn.net/qianhuan_/article/details/110197907

yii跨域处理_Yii2下session跨域名共存的解决方案

本文转自:https://blog.csdn.net/weixin_29130369/article/details/111922231?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-2&spm=1001.2101.3001.4242

前面谈过session相关配置,在开发的时候,常需要跨域共用session的是登录模块,我相信很多开发的朋友的都遇到过,只需要一个地方登录,相关联的网站也是处于登录状态。两种情况:一种9streets.cn和a.9streets.cn之间,另一种是a.com b.com之间,这几天总结了一下处理方法。

无论是一二级域名,和不同域名下的跨域,无非要达到两点:

客户端访问同一个sessionId,

所有域名对应的服务器访问的session的数据的位置必须一致。

1.访问共同的sessionId主要是通过把当前的sessionId写进cookie里面

cookie在不同域名下是不能访问的,我们需要在访问在后台设置用户在登录的时候,把需要共用的登录信息的域名,如果是在1,2级域名下,直接把cookie设置为所属主域名,例如:

setcookie(“session_id”,session_id(),time()+3600*24*365*10,”/”,”.a.com”);

也许你会问:如果是在不同的域名呢?采用P3P技术简单解决,实现原理,在访问网站x.com的时候,y.com程序触发y.com文件的写入sessionid值,sessionid值便可以获取,然后把seesion值存入数据库,取相同的sessionid值便可。这就要求y.com里面的程序文件必需能跨域访问,默认情况下,浏览器是不能跨域设置cookie的,加上p3p头后才行。在对应php文件加上:header(‘P3P: CP=”CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR”‘);

2.session数据存储位置一致的实现方法

session该数据默认情况下是存放在服务器的tmp文件下的,是以文件形式存在,而非存储在服务器的内存中,在这里我们得修改为所有域下都能访问的方式。网上介绍了数据库存储,文件形式存储,内存存储, 如果用数据库存储session数据,网站的访问量很大的话,SESSION 的读写会频繁地对数据库进行操作,效率就会明显降低,可以考虑存在内存服务器来实现,下面的session.rar里面介绍的是数据库存session的实例。

在yii2下 处理这中问题,根据网上搜到的教程 终配置成功教程如下:

$host = explode('.', $_SERVER["HTTP_HOST"]);
if (count($host) > 2) {
	define('DOMAIN', $host[1] . '.' . $host[2]);
} else {
	define('DOMAIN', $host[0] . '.' . $host[1]);
}
define('DOMAIN_HOME', 'www.' . DOMAIN);
define('DOMAIN_USER_CENTER', 'man.' . DOMAIN);
define('DOMAIN_API', 'api.' . DOMAIN);
define('DOMAIN_EMAIL', 'mail.' . DOMAIN);
define('DOMAIN_LOGIN', 'login.' . DOMAIN);
define('DOMAIN_IMG', 'img.' . DOMAIN);

然后配置User 和 Session:

'user' => [
'enableAutoLogin' => true,
'identityCookie' => ['name' => '_identity', 'httpOnly' => true, 'domain' => '.' . DOMAIN],
],
'session' => [
     'cookieParams' => ['domain' => '.' . DOMAIN, 'lifetime' => 0],
     'timeout' => 3600,
],

这里在配置项的user和session里 我把domain写死了例如:’domain’=>’.baidu.com’,这样就不用判断了.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

PHP操作Excel

安装

composer require phpoffice/phpspreadsheet

简单使用

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

$spreadsheet = new Spreadsheet();

for($i=1;$i<=3;$i++)
{
        if($i > 1)
        {
                $sheet = $spreadsheet->createSheet();
        }
        $spreadsheet->setActiveSheetIndex($i-1);
        $sheet = $spreadsheet->getActiveSheet();
        $sheet->setTitle('sheet_sheet'.$i);
        $sheet->setCellValue('A1', 'Hello World !'.$i);
}


$writer = new Xlsx($spreadsheet);
$writer->save('./public/hello world.xlsx');

GridView直接更新数据,kartik\grid\EditableColumn用法 [ 2.0 版本 ]

本文转自:https://www.yiichina.com/tutorial/1110

<?php
use yii\helpers\Url;
use common\models\ProductCategory;

return [
    [
        'class' => 'kartik\grid\SerialColumn',
        'width' => '30px',
    ],

    [
        //'class' => '\kartik\grid\DataColumn',
        'attribute' => 'name',
        'class' => '\kartik\grid\EditableColumn',
    ],
    [
        'class' => '\kartik\grid\DataColumn',
        'attribute' => 'category.name',
    ],

    [
        'class' => '\kartik\grid\EditableColumn',
        'attribute' => 'price',
    ],

    'created_at:datetime',
    
    [
        'class' => 'kartik\grid\ActionColumn',
        'dropdown' => false,
        'vAlign' => 'middle',
        'urlCreator' => function ($action, $model, $key, $index) {
            return Url::to([$action, 'id' => $key]);
        },
        'header' => Yii::t('app', '操作'),
        'viewOptions' => ['role' => 'modal-remote', 'title' => 'View', 'data-toggle' => 'tooltip'],
        'updateOptions' => ['role' => 'modal-remote', 'title' => 'Update', 'data-toggle' => 'tooltip'],
        'deleteOptions' => ['role' => 'modal-remote', 'title' => 'Delete',
            'data-confirm' => false, 'data-method' => false,// for overide yii data api
            'data-request-method' => 'post',
            'data-toggle' => 'tooltip',
            'data-confirm-title' => Yii::t('app', '操作确认'),
            'data-confirm-message' => Yii::t('app', '你确定要删除这个选项吗?')],
    ],

];

在控制器index方法里加上一段

/**
 * Lists all Product models.
 * @return mixed
 */
public function actionIndex()
{    
    $searchModel = new ProductSearch();
    $dataProvider = $searchModel->search(Yii::$app->request->queryParams);


    if ($this->isAjax && Yii::$app->request->post('hasEditable')) {
        Yii::$app->response->format = Response::FORMAT_JSON;
        
        $model = Product::findOne($this->post['editableKey']);

        $out = ['output' => '', 'message' => ''];

        $this->post[$model->formName()] = $this->post[$model->formName()][$this->post['editableIndex']];

        if ($model->load($this->post)) {
            // can save model or do something before saving model
            if($model->save()) {

                $output = '';

                /*if (isset($this->post[$model->formName()]['price_cny'])) {
                    $output = Yii::$app->formatter->asDecimal($model->price, 2);
                }*/

                $out = ['output' => $output, 'message' => ''];
            }else{
                $out['message'] = $model->getErrors();
            }
        }else{
            $out['message'] = $model->getErrors();
        }
        return $out;
    }
    

    return $this->render('index', [
        'searchModel' => $searchModel,
        'dataProvider' => $dataProvider,
    ]);
}

如果需要做权限控制之类的,修改提交地址不想直接放在index方法,可以自定义提交地址,加上editableOptions参数即可

[
    //'class' => '\kartik\grid\DataColumn',
    'class' => '\kartik\grid\EditableColumn',
    'attribute' => 'price',
    'editableOptions'=> function ($model, $key, $index) {
        return [
            //'size'=>'sm',
            'formOptions' => [
                'method'=>'post',
                'action' => ['editable']
            ]
        ];
    }
],