Search code examples
phpsqlpostgresqldoctrine-orm

How to create multiple regex conditions with Doctrine QueryBuilder


When using Doctrine ORM with Postgres, how to create the same as this SQL does with QueryBuilder:

WHERE column2 IS NOT NULL AND (column1 ~= :pattern OR column1 ~= :pattern2)

I'd also like avoiding having all conditions in one line like following:

->andWhere('column2 IS NOT NULL AND (column1 ~= :pattern OR column1 ~= :pattern2'))

Solution

  • The solution is to

    1) create custom DQL function

    <?php
    
    declare(strict_types=1);
    
    use Doctrine\ORM\Query\AST\Functions\FunctionNode;
    use Doctrine\ORM\Query\AST\Node;
    use Doctrine\ORM\Query\Lexer;
    use Doctrine\ORM\Query\Parser;
    use Doctrine\ORM\Query\SqlWalker;
    use function sprintf;
    
    /**
     * "REGEX" "(" StringPrimary "," StringPrimary ")"
     */
    final class RegexFunction extends FunctionNode
    {
        /** @var Node */
        public $fieldExpression;
    
        /** @var Node */
        public $patternExpression;
    
        /**
         * @inheritdoc
         */
        public function getSql(SqlWalker $sqlWalker) : string
        {
            return sprintf(
                '%s :: TEXT ~* %s',
                $this->fieldExpression->dispatch($sqlWalker),
                $this->patternExpression->dispatch($sqlWalker)
            );
        }
    
        /**
         * @inheritdoc
         */
        public function parse(Parser $parser) : void
        {
            $parser->match(Lexer::T_IDENTIFIER);
            $parser->match(Lexer::T_OPEN_PARENTHESIS);
    
            $this->fieldExpression = $parser->StringPrimary();
            $parser->match(Lexer::T_COMMA);
            $this->patternExpression = $parser->StringPrimary();
    
            $parser->match(Lexer::T_CLOSE_PARENTHESIS);
        }
    }
    

    2) register it in config

    3) then in can be used in query builder or expression builder like this:

    $expr->orX()->add('REGEX(e.field, :pattern) = true');