关于cacheKey的设计 最好加上用户或者浏览器特定的因素在里面 如果不考虑这些因素 所有用户的操作可能就被串行化了(不同的人 浏览器 都在做这个action 动作时 如果key不是用户客户端特定的 他们将被同一个key给锁住)
针对对不同的人 要用不同的缓存键 所以可以用某种前后缀方法 保证键对客户端的唯一性:
php 早期有个 ip2long 方法可以把客户端的ip转换为整数 但后来ipv6出现后 这个方法好像有些失效 网上有人提出了ip2bin方法(可以搜索下)
还有一个方法是 cacheKey
里面添加sessionId 做前缀
$repeatCheckKey = {$sessionId}.$this->action->id
翻译过来 的 有些不太好理解 ,实际就讲了两个问题:
模块的用途
如何使用模块 两种用法:
把相似函数 聚集起来 形成一个名空间 抱成一个模块
跨项目重用 做为微系统重用 比如用户 评论模块 这些经常每个项目都用的
模块间依赖 通过接口解耦 基本思想就是模块间引入接口来解耦模块的互相访问 不要直接粗暴的使用另一个模块内部的功能 所有功能应该在模块边界完成( 通过模块配置注入 , 或者通过模块自身提供接口供别的模块使用) 你把模块看做是一个对象 对象具有隐藏 封装 (继承可以先不考虑)特征 所以对象内部的东西你需要使用公共方法来访问(最好定义接口 接口是契约 是应该长期稳定的东西 不应该经常变动 如果不提供接口 其他模块访问本模块 是零散的直接访问 而随着时间的变化 这种公共方法会因为需求而变化(比如 参数类型 名称 个数 返回类型 抛出的异常等等 都会变化) 所以有必要先定义接口 这样先使通信协定稳定下来 不要经常变动 。 这样要求你在设计模块对外的方法时需要仔细斟酌(模块也有一些是给内部用的属性和方法) 而不是拍脑袋乱写,这也就是 接口即契约的思想--共识达成不到万不得已就不要瞎变 给你提供了一个警戒线)
@fecommerce #2楼 REPL 这个你需要搜索下 先看看这个干啥用的 抛开yii不说 你可以使用psysh 直接做其他交互式shell可以做的事 你用进程思想来思考 如果你做了一个web页 然后在上面敲php代码 然后代码以字符串的形式传递给 psysh进程 这个进程可以执行你的代码 执行完后 在返回给web服务器 然后返回结果给浏览器 这样几乎可以实现一个在线php交互编程功能 我只是这样想 具体能否实现还不清楚
实际上你用了 yii-shell 可以在命令行中 访问你模块中的某个功能 不需要从控制器的action进入 yii中 进入系统功能的方法 常规就是需要你写某个控制器的某个action 然后在action中 访问功能 但你必须建立文件 这样有时候很麻烦 等你文件类什么的都建立好了 可能就忘了你要干啥 这时直接打开 yii-shell 立即就可以调用你的 方法 验证正误 当然你也可以写单元测试 来验证你的功能 这个体验是很像的
关于重复提交:
接 @forecho的回复。
思路就是 哈希POST (注意下 两次提交有没有不一样的参数混进来 比如xxxToken)中的值 提交成功后存一个md5 (位数比较少哈! ) 下次处理提交前对比哈希 如果一样 就是内容重复 。 session key 可以命名为 $lastActionParamsHash , 值:md5(\Yii::$app->request->post()) ; 这样一定程度内可以防止 “手抖”多次点击提交按钮
对于手抖 其实在js端也可以做限制 比如点击按钮后 就灰显(disable)之。
这个方案 跟防止快速提交性质稍微不一样了 但也好像有些关联 :d:
$repeatCheckKey = $this->action->id ;
if($cache->get($repeatCheckKey) !== false ){
// 提示用户提交过快
}
if($model->save()){
// 60 秒内防止重复提交
$cache->set($repeatCheckKey ,time(),60) ;
}
上面这个只是示意做法 如果真的可行 那么可以利用事件机制 无侵入实现
只需要监听ActiveRecord::EVENT_BEFORE_INSERT 以及 ActiveRecord::EVENT_AFTER_INSERT 就可以无侵入实现
还有一种方法 直接跟ar无关 直接监听控制器的beforeAction 跟afterAction 利用这种思路也可以实现
经过思考 觉得还是监听控制器吧
关于张冠李戴没有具体提及,补充下 就是:
SELECT user.* ,cmtSum.cmtAmount as xxx
上例的xxx 可以是user表中的字段 这个字段就是被强行赋值掉了