Cómo crear y usar una función DQL en Symfony

symfony_1_1.jpg
Solucionex
08
Nov 19

Doctrine no proporciona todas las funciones disponibles de mysql por defecto. Sin embargo, nosotros podemos crearlas y añadirlas para poder usarlas en nuestro proyecto de desarrollo con Symfony.

Funciones de Doctrine

¿Qué funciones va a necesitar nuestra aplicación Symfony para funcionar correctamente? Pues es muy probable que necesites hacer una consulta a la base de datos que te devuelva todos los datos de un año, con lo que necesitaríamos la función YEAR o devolver directamente valores enteros de una cierta columna de la base de datos, por lo que podríamos usar la función ROUND.

Para calcular distancias entre puntos geográficos delimitados por Latitud y Longitud es necesario utilizar funciones más avanzadas como ACOS, COS, SIN, RADIANS, DEGREES...

En fin, en cuanto crezca un poquito tu aplicación y sea algo más que un simple entorno CRUD, vas a necesitar consultas más avanzadas. Y vas a poder usar cualquier que esté en la lista de funciones de MySql, que puedes ver aquí por ejemplo.

Cómo usar una función DQL en una consulta

Sencillo, como cualquier función dentro de una consulta, debe ser fácil reconocer este fragmento de código donde vamos a utilizar la función YEAR dentro de una consulta que se encuentra en el repositorio de una entidad Post, que tendrá un campo createdAt y por el cual filtraremos para obtener todos los posts creados en un año pasado por parámetro:

class PostRepository extends EntityRepository { public function findByYear($year) { return $this ->createQueryBuilder('p') ->where('YEAR(p.createdAt) = :year') ->setParameter('year', $year) ->getQuery() ->getResult(); } }

Añadir funciones DQL a Symfony

El código anterior probablemente nos dé un error parecido a este: year Class not found .... ¿Por qué no me deja utilizarla? Porque hay que "crearla" y "registrarla" en Symfony previamente. Todo esto es my sencillo, son dos pasos donde tocaremos el fichero de configuración de doctrine (config/packages/doctrine.yaml) y crear el fichero php de la función correspondiente.

Registrar función DQL en Symfony

Empiezo por el segundo paso, porque por defecto algunas funciones ya están "creadas", solo hay que incorporarlas a la configuración de Doctrine dentro de Symfony:

doctrine: orm: dql: string_functions: YEAR: DoctrineExtensions\Query\Mysql\Year

Si la función que necesitamos no la tuviese incorporada por defecto doctrine 2, tendríamos que crearla y registrar la ruta al nuevo fichero en la configuración que hemos puesto previamente.

Las funciones se dividen en string_functions, numeric_functions, datetime_functions.

Crear función DQL para Symfony

Bien, si nuestra función no está creada, como la función SIN (seno), por ejemplo, crearemos el fichero App\DQL\Sin.php uy ahí crearemos la clase Sin, que a su vez extenderá de FunctionNode, a partir de ahí, es obligatorio poner una función parser dentro de la clase que se corresponda con la sintaxis de la función:

namespace App\DQL; use Doctrine\ORM\Query\AST\Functions\FunctionNode; use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; class Sin extends FunctionNode { public $value; public function parse(Parser $parser) { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); $this->value = $parser->StringPrimary(); $parser->match(Lexer::T_CLOSE_PARENTHESIS); } public function getSql(SqlWalker $sqlWalker) { return 'SIN(' . $this->value->dispatch($sqlWalker) . ')'; } }

Funciones DQL implementadas

En este repositorio encontramos la mayoría de las funciones ya implementadas, con lo que no las tendremos que implementar nosotros, ahorrándonos ese trabajo y haciendo que nuestro desarrollo sea más sencillo.

Si solo nos hace falta una función, no haría falta, pero si vamos a usar varias, esta extensión de doctrine nos va ahorrar bastantes líneas de código.

Igualmente, por cada función que queramos usar la tendremos que registrar en la configuración de doctrine, paso que hemos visto un poco más arriba con la función YEAR.

Esperamos que después de leer este post te sea mucho más sencilla la tarea de escribir consultas en DQL.