- 这确实是 Yii2 的 bug,是的,是的,是的
- 我:好像玩梗过度。别人:你是不是觉得自己很幽默?
考试挂了一门,不过问题不大
这段空闲时间稍微写了一点东西,其中涉及到 Yii2 权限控制修改角色(或者权限、规则等),虽然问题的解决过程不复杂,但是这种隐藏的彩蛋见到的话是真的有种被人秀的感觉,所以还是发出来
下面是一段用来更新“角色名”的代码:
$auth = Yii::$app->authManager;
$role = $auth->getRole($name);
$role->name = $newName;
$auth->update($name, $role);
我用到的 authManager
是数据库的,update
方法最终会调用 yii\rbac\DbManager
里的 updateItem
方法,以下为关键代码:
if ($item->name !== $name && !$this->supportsCascadeUpdate()) {
$this->db->createCommand()
->update($this->itemChildTable, ['parent' => $item->name], ['parent' => $name])
->execute();
$this->db->createCommand()
->update($this->itemChildTable, ['child' => $item->name], ['child' => $name])
->execute();
$this->db->createCommand()
->update($this->assignmentTable, ['item_name' => $item->name], ['item_name' => $name])
->execute();
}
意思就是说,如果新的名字不等于旧的名字,并且“supportsCascadeUpdate”,那么就更新子表
supportsCascadeUpdate
的官方 API 文档介绍是“返回一个值,指示数据库是否支持级联更新和删除。对于 SQLite 数据库,默认实现将返回 false,对于所有其他数据库,则返回 true”(其实自己看代码也看得懂)
其他数据库,那就是包括 Mysql 喽~
那么就是说,上面代码的意思是,“当改了名字,并且不是 Mysql 数据库”的时候,就更新
为了把重点突出,我特地改了“不”的颜色
看到这里我傻了,我相信看到这里的你们也傻了,这逻辑不通啊,于是我用 Xdebug 调试,结果就是上面解释的那样
大史(《我的三体》中角色)曾说过:“事出反常必有妖”(实际上是纪晓岚说的)
肯定还是我的理解有问题,反复看了好几次官方 API 后我发现了“是否支持级联更新和删除……级联更新和删除……级联”
龙珠超 BGM 起~哦,不对,不是那个吉连!
实际上,那句代码的含义应该是指,如果改了名,并且数据库不支持级联,那么才执行之后的代码,之后代码就是更新子表的操作
“级联”在这里简而言之就是“外键”,整段代码再翻译过来就是“如果数据库不支持自动改名,才手动改名”
MyISAM 不支持外键,级联自然就不存在,我习惯是用 InnoDB 的,至于为什么变成了 MyISAM,那是因为默认配置的问题
default-storage-engine=InnoDB
# skip-innodb
Mysql 配置改成这两个,再看看最终创建的表是不是 InnoDB,是的话,问题就解决了
问题的最终原因除了我自己没看清外,我觉得 supportsCascadeUpdate
方法本身就有问题,是简单通过字符串匹配去检测“是否支持级联”的,算是一个小小的 bug 吧,最后……
现在谁还在用 MyISAM 啊!好吧,我是被迫的……