Model的定义优先还是DB的schema优先?

背景

最近负责把项目的代码从PHP5.6升级到PHP7.3。
层出不穷的问题请见前几篇博客。
当然之前遇到的大多数是PHP版本升级后的兼容问题,
而这次遇到了Yii重构导致现行代码出错的问题。

找不到的 ActiveModel Property

PHP5.6 => PHP7.3, yii1.1.15 => Yii1.1.21。
升级之后在Error Log观察到了类似Property "MyselfDefinedModel.id" is not defined的例外。

显然翻查DB的schema,我们在对应的MyselfDefinedModel的Table中并没有设定id作为Primary Key。
甚至没有id这个column,那么这个Id是怎么来的呢?

经过一番寻找,
在更新后的Yii1.1.21中我们发现了一些微妙的变化。

1
2
3
4
5
6
7
8
9
10
11
12
// yii 1.1.21
// framework/yiilite.php
if(($modelPk=$model->primaryKey())!==null || $table->primaryKey===null){
$table->primaryKey=$modelPk;
...
}

// yii 1.1.15
if($table->primaryKey===null) {
$table->primaryKey=$model->primaryKey();
...
}

可以发现,在新版本的Yii中,无论$table->primaryKey是否为null,我们始终会用$model->primaryKey()的结果去赋值给$table->primaryKey

然而我们自定义的MyselfDefinedModel 继承自BaseModel, 而我们在BaseModel中定义了public function primaryKey() {return 'id'}的方法。

于是,没有做任何override的MyselfDefinedModel自动继承了primaryKey()的方法,当Acitverecord去寻找期PrimaryKey的时候,新版本的Yii便让这个值成为了PrimaryKey。

1
2
3
4
5
6
7
8
9
10
class BaseModel extend CActiveRecord
{
...
public function primaryKey() {return 'id'};
...
}

class MyselfDefinedModel extend BaseModel
{
}

解决方法

不更改Yii自身的情况下,我们可以在MyselfDefinedModel中overridepublic function primaryKey() 然后返回正确的primary Key。

1
2
3
4
5
6
class MyselfDefinedModel extend BaseModel
{
...
public function primaryKey() {return 'other_id'};
...
}

毕竟,忘记在子类中override PrimaryKey本身就存在问题。
但是,一旦修改起来,PrimaryKey不是id的表出奇的多,那不如去把Yii改了?

如此产生了以下的新问题,Yii的关于获取PrimaryKey的变化,会不会是一次失败的重构?

后话

于是屁颠屁颠跑到了github的yii1.1 repository,提出了issue。表示自己怀疑这段重构有问题。

并表示具体做法是把之前某个commit的重构给revert。从而让DB schema 优先于model中的设定。

很幸运的是这个问题不过10分钟就收到了回复。有人站起来指出model配置优先于DB schema的必要性。

简而言之是model中的public function primaryKey() 方法是唯一可以重新指定primaryKey的地方,所以必须要优先于DB schema。

嗯但是DB schema 放着好好的不用,到底有哪些情况下我们需要重新指定我们的PrimaryKey呢?

于是,当我们需要对PrimaryKey加一些校验的时候,我们希望动态生成这些校验值附加到我们自定义的PrimaryKey上,然后通过校验的PrimaryKey再去访问数据。(具体联想到GlobalId也可以用这种方法实现)

问题Close。以上。