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

时间:2015-09-30 15:20:26

标签: 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);
    }
}

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

2 个答案:

答案 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()方法,这正是我们所需要的。