我在Symfony项目中使用Spatie的枚举,并为这些对象制作了自定义的DBAL类型。当我将枚举对象保存到数据库时,我会以特殊的字符串格式保存。我的EnumType
中的转换功能看起来像这样:
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if ($value === null) {
return null;
}
return get_class($value) . '::' . $value->getIndex() . '::' . $value->getValue();
}
所以例如,我有一个看起来像这样的交易状态:
namespace AppEnum;
use SpatieEnumEnum;
/**
* @method static self failed()
* @method static self pending()
* @method static self completed()
*/
final class TransactionStatus extends Enum {}
,当我将其保存到数据库时,它可以分别变成这些字符串中的任何一个:
AppEnumTransactionStatus::0::failed
AppEnumTransactionStatus::1::pending
AppEnumTransactionStatus::2::completed
这有助于我的EnumType
知道什么枚举将其转换回。我在字符串中使用索引号的原因是因为这有助于分类。
现在,这一切都非常适合获取和将我的实体保存到数据库中。但是,当我尝试在DQL语句的Where子句中使用枚举时,它根本不起作用。
namespace AppRepository;
use AppEntityTransaction;
use AppEnumTransactionStatus;
use SymfonyBridgeDoctrineRegistryInterface;
use DoctrineBundleDoctrineBundleRepositoryServiceEntityRepository;
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"
而不是"AppEnumTransactionStatus::1::pending"
。
我如何确保我的枚举始终在DQL中正确转换?
好吧,我找到了一种方法,即使它超级骇客。我只是从调用 __toString()
方法的位置检查,如果是从学说的dbal调用的,则使用枚举的DB格式。
namespace AppEnum;
use SpatieEnumEnum 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();
}
}