Aprende a registrar una función DQL personalizada (una extensión de doctrina) en Symfony 4 fácilmente.

El analizador DQL de Doctrine 2 tiene ganchos para registrar funciones que luego pueden usarse en sus consultas DQL y transformarse en SQL, lo que permite extender las capacidades de Doctrines Query, en lugar de escribir SQL sin formato. En este artículo, le explicaremos brevemente cómo configurar una extensión de doctrina personalizada en su proyecto Symfony 4.

1. Cree/elija su extensión DQL

Como primer paso, cree un directorio en el directorio src de su proyecto Symfony, a saber, DQL. Este directorio almacenará las clases que desea registrar como extensiones de doctrina personalizadas. Dentro de este directorio, el espacio de nombres de los archivos almacenados dentro debería ser App\DQL. En nuestro caso, queremos registrar 2 extensiones de texto personalizadas para doctrine (match against y soundex), por lo que tendremos 2 archivos, nuestra estructura se verá así:

Symfony 4 DQL Functions

El código de la función MatchAgainst y el archivo MatchAgainst.php que registraremos es el siguiente (para ti solo es importante el espacio de nombres):

namespace App\DQL;

use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;

/**
 * "MATCH_AGAINST" "(" {StateFieldPathExpression ","}* InParameter {Literal}? ")"
 */
class MatchAgainst extends FunctionNode {

    public $columns = array();
    public $needle;
    public $mode;

    public function parse(\Doctrine\ORM\Query\Parser $parser) {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        do {
            $this->columns[] = $parser->StateFieldPathExpression();
            $parser->match(Lexer::T_COMMA);
        } while ($parser->getLexer()->isNextToken(Lexer::T_IDENTIFIER));
        $this->needle = $parser->InParameter();
        while ($parser->getLexer()->isNextToken(Lexer::T_STRING)) {
            $this->mode = $parser->Literal();
        }
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) {
        $haystack = null;
        $first = true;
        foreach ($this->columns as $column) {
            $first ? $first = false : $haystack .= ', ';
            $haystack .= $column->dispatch($sqlWalker);
        }
        $query = "MATCH(" . $haystack .
                ") AGAINST (" . $this->needle->dispatch($sqlWalker);
        if ($this->mode) {
            $query .= " " . $this->mode->dispatch($sqlWalker) . " )";
        } else {
            $query .= " )";
        }
        
        return $query;
    }

}

Una vez que tenga una extensión válida, proceda a registrarla en el siguiente paso.

2. Registrar la extensión DQL

Para registrar funciones DQL en Symfony 4, simplemente puede registrarlas especificando las clases en el bloque respectivo bajo el bloque dql de orm en doctrine. Recuerda que en Doctrine, solo hay tres tipos de funciones en DQL, las que devuelven un valor numérico, las que devuelven una cadena y las que devuelven una Fecha, por lo que debe haber un bloque mayor que contenga cada tipo de función:

# config/packages/doctrine.yaml
doctrine:
    orm:
        # ...
        dql:
            string_functions:
                test_string: App\DQL\StringFunction
                second_string: App\DQL\SecondStringFunction
            numeric_functions:
                test_numeric: App\DQL\NumericFunction
            datetime_functions:
                test_datetime: App\DQL\DatetimeFunction

En nuestro caso, con nuestras funciones MatchAgainst y Soundex, que manejan texto, simplemente las registraríamos con el siguiente fragmento en el doctrine.yamlarchivo debajo del nodo string_functions:

# app/config/packages/doctrine.yaml
doctrine:
    # Bajo orm, crea el DQL
    orm:
        #
        # ...
        # 
        dql:
            # Registrar funciones de cadena con el espacio de nombres correcto
            string_functions:
                MATCH_AGAINST: App\DQL\MatchAgainst
                SOUNDEX: App\DQL\SoundexFunction

Para administradores de entidades declarados explícitamente

En caso de que uses varios administradores de entidades en Doctrine, puedes registrar las funciones personalizadas específicamente para algunas de ellas dentro del bloque del administrador:

# config/packages/doctrine.yaml
doctrine:
    orm:
        # ...
        entity_managers:
            example_manager:
                dql:
                    string_functions:
                        MATCH_AGAINST: App\DQL\MatchAgainst

Que te diviertas ❤️!


Interesado en la programación desde los 14 años, Carlos es un programador autodidacta, fundador y autor de la mayoría de los artículos de Our Code World.

Conviertete en un programador más sociable

Patrocinadores