Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Utilizar RAND() u otras funciones no compatibles

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $6.00

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.

... 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.

... 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.

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.

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "beberlei/doctrineextensions": "^1.3", // v1.3.0
        "doctrine/doctrine-bundle": "^2.7", // 2.9.1
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
        "doctrine/orm": "^2.13", // 2.15.1
        "symfony/asset": "6.2.*", // v6.2.7
        "symfony/console": "6.2.*", // v6.2.10
        "symfony/dotenv": "6.2.*", // v6.2.8
        "symfony/flex": "^2", // v2.2.5
        "symfony/framework-bundle": "6.2.*", // v6.2.10
        "symfony/proxy-manager-bridge": "6.2.*", // v6.2.7
        "symfony/runtime": "6.2.*", // v6.2.8
        "symfony/twig-bundle": "6.2.*", // v6.2.7
        "symfony/webpack-encore-bundle": "^1.16", // v1.16.1
        "symfony/yaml": "6.2.*" // v6.2.10
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.4
        "symfony/maker-bundle": "^1.47", // v1.48.0
        "symfony/stopwatch": "6.2.*", // v6.2.7
        "symfony/web-profiler-bundle": "6.2.*", // v6.2.10
        "zenstruck/foundry": "^1.22" // v1.32.0
    }
}
userVoice