如何在dql where语句中使用主义自定义类型?

时间:2019-05-16 09:17:48

标签: doctrine-orm dql

我在symfony项目中使用Spatie's enums,并为这些对象创建了自定义DBAL类型。将枚举对象保存到数据库时,将其保存为特殊的字符串格式。我的EnumType中的转换函数如下:

public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
    if ($value === null) {
        return null;
    }

    return get_class($value) . '::' . $value->getIndex() . '::' . $value->getValue();
}

例如,我有一个如下所示的交易状态枚举:

namespace App\Enum;

use Spatie\Enum\Enum;

/**
 * @method static self failed()
 * @method static self pending()
 * @method static self completed()
 */
final class TransactionStatus extends Enum {}

当我将其保存到数据库时,它可以分别转换为以下字符串之一:

App\Enum\TransactionStatus::0::failed
App\Enum\TransactionStatus::1::pending
App\Enum\TransactionStatus::2::completed

这有助于我的EnumType知道将其转换回哪个枚举。我之所以在字符串中使用索引号,是因为这有助于排序。

现在,所有这些对于将我的实体保存并保存到数据库都非常有效。但是,当我尝试在DQL语句的where子句中使用枚举时,它根本无法工作。

namespace App\Repository;

use App\Entity\Transaction;
use App\Enum\TransactionStatus;
use Symfony\Bridge\Doctrine\RegistryInterface;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;

class TransactionRepository extends ServiceEntityRepository
{
    public function __construct(RegistryInterface $registry)
    {
        parent::__construct($registry, Transaction::class);
    }

    public function findByStatus(TransactionStatus $status)
    {
        return $this->createQueryBuilder('t')
            ->andWhere('t.status = :status')
            ->setParameter('status', $status)
            ->getQuery()->getResult();
    }
}

由于某些原因,学说忽略了我的转换函数,而只使用了Spatie枚举中内置的__toString()函数。因此,学说正在寻找字符串"pending"而不是"App\Enum\TransactionStatus::1::pending"

如何确保我的枚举始终在DQL where子句中正确转换?

1 个答案:

答案 0 :(得分:0)

好的,即使它是超级hacky,我也找到了一种方法。我只是从__toString()方法的调用位置进行检查,如果它是从Doctrine的DBAL中调用的,那么我使用枚举的DB格式。

namespace App\Enum;

use Spatie\Enum\Enum as BaseEnum;

abstract class Enum extends BaseEnum
{
    public function __toString(): string
    {
        if (debug_backtrace()[1]['class'] === 'PDOStatement') {
            return get_class($this) . "::$this->index::$this->value";
        }

        return parent::__toString();
    }
}