我使用Doctrine2类型来加密数据库值。该类型通过加密和解密来将PHP值内部转换为数据库值和从数据库值转换。由于Doctrine2类型,这完美地工作。
加密存储为base64编码的字符串。每个加密的字符串都以固定的定义前缀为前缀。这意味着数据库字段包含加密和解密的值(这是外部要求所必需的),由前缀识别。
我的愿望如下:
假设我有一个实体。我想强制使用Doctrine加密或解密实体的所有属性。我这样做是通过强制类型中的数据库值以加密或解密的形式存储。
但是,当我调用方法EntityManager::computeChangeSets
时,实体的所有属性都没有标记为已更改。当然,实际数据(PHP值)不会改变。但是,数据库值会(应该)更改。
如何做到这一点?
Doctrine类型的一些代码:
<?php
use Doctrine\DBAL\Types\Type;
class EncryptedType extends Type {
private static $forceDecrypt = false;
// Encryption stuff, like encrypt () and decrypt ()
public function convertToPHPValue($value, AbstractPlatform $platform) {
if ($value === null) {
return null;
}
return $this -> decrypt($value, false);
}
public function convertToDatabaseValue($value, AbstractPlatform $platform) {
if ($value === null) {
return null;
}
if (self::$forceDecrypt) {
return (string) $value;
}
return $this -> encrypt((string) $value, false);
}
}
我删除了所有不需要的代码。
答案 0 :(得分:2)
这不是一个错误吗?
解决方法:如果实体由管理员管理,则其状态为STATE_MANAGED
,当您将其更改为STATE_NEW
并强制更新时,这可以解决您的问题。
答案 1 :(得分:0)
在深入学习Doctrine代码数小时后,我找到了自己问题的答案。
我的解决方案大纲下方可以帮助其他人。
首先,我创建了一个简单的值类,它可以保存任何类型的PHP值。它有__toString()
方法将其转换回原始值。
代码:
class Value {
private $value;
public function __construct($value) {
$this -> value = $value;
}
public function __toString() {
return $this -> value;
}
}
EncryptedType
类保持完全相同。关键是实体的价值。当必须在数据库中强制更新类的属性(并因此使用EncryptedType
类)时,它将按以下方式设置:
foreach (self::$properties as $property) {
$value = $accessor -> getValue($entity, $property);
if ($value !== null) {
$accessor -> setValue($entity, $property, new Value($value));
}
}
($accessor
是属性访问者。)
注意new Value(...)
包装器,它将确保Doctrine注意到属性值的更改并在数据库中进行更改。当然,该值将取自__toString()
方法,这正是我们所需要的。