我在桌子上使用UUID作为PK。它们存储在BINARY(16)
MySQL列中。我发现他们在YII中被映射到string
类型。我生成的CRUD代码虽然破坏了,因为这些二进制列类型在视图中是HTML编码的。例如:
<?php echo
CHtml::link(CHtml::encode($data->usr_uuid), /* This is my binary uuid field */
array('view', 'id'=>$data->usr_uuid)); ?>
要解决此问题,我在我的模型中覆盖afterFind()
和beforeSave()
,我分别使用bin2hex
和hex2bin
将值转换为/从十六进制转换。有关详细信息,请参阅this。
这可以解决视图问题。
但是,现在在访问表单的URL时搜索PK:
http://myhost.com/mysite/user/ec12ef8ebf90460487abd77b3f534404
导致User::loadModel($id)
被调用,而后者又调用:
User::model()->findByPk($id);
这不起作用,因为SQL正在生成(由于它被映射到php string
类型)是
select ... where usr_uuid='EC12EF8EBF90460487ABD77B3F534404'
如果可以,那会有效,因为这些uuid字段会将条件更改为:
select ... where usr_uuid=unhex('EC12EF8EBF90460487ABD77B3F534404')
我想知道我是如何干净地处理这个问题的。我看到了一个可能性 - 扩展CMysqlColumnSchema
并覆盖特殊情况下的必要方法,并将二进制(16)列作为uuid类型处理。
这似乎并不整洁,因为在php(它被视为字符串)或mysql(我将其作为二进制(16)列)中原生地支持uuid
。
有人有任何建议吗?
答案 0 :(得分:1)
如果您计划在自己的代码中使用它,那么我将创建自己的基础AR类:
class ActiveRecord extends CActiveRecord
{
// ...
public function findByUUID($uuid)
{
return $this->find('usr_uuid=unhex(:uuid)', array('uuid' => $uuid));
}
}
如果是关于使用生成的代码等,那么自定义模式可能是一个好主意。
答案 1 :(得分:0)
我使用以下方法使用Yii / MySQL的uuid(二进制(16))列可行且高效。我提到有效率,因为我可以用一个破折号使列成为CHAR(32)或(36),但这样可以真正地从窗口中释放出来。
我扩展了CActiveRecord
并为其添加了虚拟属性uuid
。还重载了两个基类方法getPrimaryKey
和setPrimaryKey
。有了这些变化,Yii的大多数人都很高兴。
class UUIDActiveRecord extends CActiveRecord
{
public function getUuid()
{
$pkColumn = $this->primaryKeyColumn;
return UUIDUtils::bin2hex($this->$pkColumn);
}
public function setUuid($value)
{
$pkColumn = $this->primaryKeyColumn;
$this->$pkColumn = UUIDUtils::hex2bin($value);
}
public function getPrimaryKey()
{
return $this->uuid;
}
public function setPrimaryKey($value)
{
$this->uuid = $value;
}
abstract public function getPrimaryKeyColumn();
}
现在我使用此虚拟属性获取/设置UUID:
$model->uuid = generateUUID(); // return UUID as 32 char string without the dashes (-)
最后一点是关于我如何搜索。这是通过以下方式完成的:
$criteria = new CDbCriteria();
$criteria->addCondition('bkt_user = unhex(:value)');
$criteria->params = array(':value'=>Yii::app()->user->getId()); //Yii::app()->user->getId() returns id as hex string
$buckets = Bucket::model()->findAll($criteria);
最后一点,参数记录,即main.php
中的以下行:
'db'=>array(
...
'enableParamLogging' => true,
);
仍然不起作用,再次,Yii将尝试html编码二进制数据(不是一个好主意)。我还没有找到解决方法,所以我在配置文件中禁用了它。