Buy Access to Course
15.

Utilizar RAND() u otras funciones no compatibles

|

Share this awesome video!

|

Keep on Learning!

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Por si acaso, vamos a aleatorizar el orden de las fortunas de una página. Prueba con esta categoría, que tiene 4.

Empieza abriendo FortuneController y buscando showCategory(). En este momento, consultamos la categoría de la forma normal. Luego, en nuestra plantilla, hacemos un bucle sobre category.fortuneCookies.

Cambia la consulta a ->findWithFortunesJoin(), que está aquí enCategoryRepository. Recuerda: esto se une a FortuneCookie y selecciona esos datos, resolviendo nuestro problema N+1.

52 lines | src/Controller/FortuneController.php
// ... lines 1 - 13
class FortuneController extends AbstractController
{
// ... lines 16 - 35
public function showCategory(int $id, CategoryRepository $categoryRepository, FortuneCookieRepository $fortuneCookieRepository): Response
{
$category = $categoryRepository->findWithFortunesJoin($id);
// ... lines 39 - 49
}
}

Ahora que hacemos esto, también podemos controlar el orden. Digamos->orderBy('RAND()', Criteria::ASC). Sólo estamos consultando un Category... pero esto controlará también el orden de las galletas de la suerte relacionadas... que veremos cuando hagamos un bucle sobre ellas.

121 lines | src/Repository/CategoryRepository.php
// ... lines 1 - 6
use Doctrine\Common\Collections\Criteria;
// ... lines 8 - 18
class CategoryRepository extends ServiceEntityRepository
{
// ... lines 21 - 54
public function findWithFortunesJoin(int $id): ?Category
{
return $this->addFortuneCookieJoinAndSelect()
// ... lines 58 - 59
->orderBy('RAND()', Criteria::ASC)
// ... lines 61 - 62
}
// ... lines 64 - 119
}

¡Genial! Si probamos esto... ¿error?

Esperaba una función conocida, obtuvo RAND

Espera... RAND es una función conocida de MySQL. Entonces... ¿por qué no funciona? Vale, Doctrine soporta muchas funciones dentro de DQL, pero no todo. ¿Por qué? Porque Doctrine está diseñado para trabajar con muchos tipos diferentes de bases de datos... y si sólo una o algunas bases de datos soportan una función como RAND, entonces Doctrine no puede soportarla. Afortunadamente, podemos añadir esta función o cualquier función personalizada que queramos nosotros mismos o, en realidad, a través de una biblioteca.

Busca la biblioteca beberlei/doctrineextensions. Es genial. Nos permite añadir un montón de funciones diferentes a varios tipos de bases de datos. Baja aquí y coge la línea composer require... pero no necesitamos la parte dev-master. ¡Ejecuta eso!

composer require beberlei/doctrineextensions

Instalar esto no cambia nada en nuestra aplicación... sólo añade un montón de código que podemos activar para las funciones que queramos. Para ello, vuelve aconfig/packages/doctrine.yaml, en algún lugar debajo de orm, digamos dql. Aquí hay un montón de categorías diferentes, sobre las que puedes leer más en la documentación. En nuestro caso, tenemos que añadir numeric_functions junto con el nombre de la función, que es rand. Pon esto en la clase que permitirá a Doctrine saber qué hacer: DoctrineExtensions\Query\Mysql\Rand.

54 lines | config/packages/doctrine.yaml
doctrine:
// ... lines 2 - 7
orm:
// ... lines 9 - 24
dql:
numeric_functions:
rand: DoctrineExtensions\Query\Mysql\Rand
// ... lines 28 - 54

Definitivamente, no tienes que fiarte de mi palabra sobre cómo debe configurarse esto. En la documentación... hay un enlace "config" aquí abajo... y si haces clic en mysql.yml, puedes ver que describe todas las cosas diferentes que puedes hacer y cómo activarlas.

Voy a cerrar eso... actualizo, y... ¡ya está! Cada vez que actualizamos, los resultados aparecen en un orden diferente.

Vale, ¡otro equipo de temas! Terminemos con una situación compleja de groupBy() en la que seleccionamos algunos objetos y algunos datos adicionales a la vez.