使用Doctrine类型更新具有相同PHP值的数据库值

Hid*_*dde 9 php types doctrine-orm

我使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我删除了所有不需要的代码.

Hid*_*dde 1

经过几个小时的深入研究 Doctrine 代码后,我找到了自己问题的答案。

下面显示了我的解决方案的概要以帮助其他人。


首先,我创建了一个简单的值类,它可以保存任何类型的 PHP 值。它有一个__toString()方法可以将其转换回原始值。

代码:

class Value {
    private $value;

    public function __construct($value) {
        $this -> value = $value;
    }

    public function __toString() {
        return $this -> value;
    }
}
Run Code Online (Sandbox Code Playgroud)

班级EncryptedType保持完全相同。重点是实体的价值。当必须在数据库中强制更新类的属性(从而使用该类EncryptedType)时,它将按以下方式设置:

foreach (self::$properties as $property) {
    $value = $accessor -> getValue($entity, $property);
    if ($value !== null) {
        $accessor -> setValue($entity, $property, new Value($value));
    }
}
Run Code Online (Sandbox Code Playgroud)

($accessor是一个属性访问器。)

注意new Value(...)包装器,它将确保 Doctrine 注意到属性值的变化并在数据库中进行更改。当然,该值将从__toString()方法中获取,这正是我们所需要的。