1
votes

I use Spatie's enums in my symfony project and I made a custom DBAL type for those objects. When I save an enum object to the database, I save it in a special string format. The conversion function in my EnumType looks like this:

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

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

So for example I have a transaction status enum that looks like this:

namespace App\Enum;

use Spatie\Enum\Enum;

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

And when I save it to the database it can turn into any one of these strings respectively:

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

This helps my EnumType to know what enum to transform it back into. And the reason I use the index number in the string is because that helps with sorting.

Now this all works very well for fetching and saving my entities to the database. But when I try to use an enum in a where clause of a DQL statement, it doesn't work at all.

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();
    }
}

Because for some reason doctrine ignores my conversion function and just uses the __toString() function that's built into Spatie's enum. So doctrine is looking for the string "pending" instead of "App\Enum\TransactionStatus::1::pending".

How do I make sure that my enums always get converted correctly in a DQL where clause?

1

1 Answers

0
votes

Okay I found a way to do it, even though it is super hacky. I just check from where the __toString() method is called and if it's called from Doctrine's DBAL then I use the DB format of the enum.

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();
    }
}