Exécuter des requêtes SQL brutes avec Doctrine

Publié le 16/01/2020 • Mis à jour le 16/01/2020


English language detected! 🇬🇧

  We noticed that your browser is using English. Do you want to read this post in this language?

Read the english version 🇬🇧 Close

Dans ce bout de code, nous allons voir comment exécuter des requêtes brutes via l'instance DBAL de Doctrine. Dans le premier exemple, nous préparons une requête et nous lui affectons un paramètre de type entier. Dans le second, comme il n'y pas de paramètre à remplacer, nous pouvons directement utiliser la méthode raccourcie fetchAll pour récupérer des données. Dans le dernier exemple, on utilise la fonction createNativeQuery() du manageur Doctrine.


<?php

declare(strict_types=1);

// src/Controller/Snippet/Snippet70Trait.php

namespace App\Controller\Snippet;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\ParameterType;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query\ResultSetMapping;

/**
 * J'utilise un trait PHP afin d'isoler chaque snippet dans un fichier.
 * Ce code doit être apellé d'un contrôleur Symfony étendant AbstractController (depuis Symfony 4.2)
 * ou Symfony\Bundle\FrameworkBundle\Controller\Controller (Symfony <= 4.1).
 * Les services sont injectés dans le constructeur du contrôleur principal.
 *
 * @property Connection             $connection
 * @property EntityManagerInterface $entityManager
 */
trait Snippet70Trait
{
    public function snippet70(): void
    {
        $sql = 'SELECT type, count(*) AS count FROM article WHERE id > ? GROUP BY type';
        echo '-- $statement->fetchAllAssociative() --'.PHP_EOL;
        echo $sql.PHP_EOL.PHP_EOL;

        try {
            $statement = $this->connection->prepare($sql);
        } catch (Exception $e) {
            throw new \RuntimeException(sprintf('Error while preparing the SQL: %s', $e->getMessage()));
        }

        // Properly replace first placeholder "?" in the SQL by an integer value
        $statement->bindValue(1, 20, ParameterType::INTEGER);
        $statement->execute();
        var_dump($statement->fetchAllAssociative());

        echo '-- $this->connection->fetchAllAssociative() --'.PHP_EOL;
        $sql2 = 'SELECT type, count(*) AS count FROM article GROUP BY type';
        echo $sql2.PHP_EOL.PHP_EOL;
        var_dump($this->connection->fetchAllAssociative($sql2));

        // You can also use the createNativeQuery() function from the Doctrine entity manager
        echo '-- $this->entityManager->createNativeQuery() --'.PHP_EOL;
        $rsm = (new ResultSetMapping())
            ->addScalarResult('type', 'type')
            ->addScalarResult('count', 'count');
        var_dump($this->entityManager->createNativeQuery($sql2, $rsm)->getArrayResult());

        // That's it! 😁
    }
}

 Exécuter le snippet  ≪ this.showUnitTest ? this.trans.hide_unit_test : this.trans.show_unit_test ≫  Plus sur Stackoverflow   Lire la doc   Lire la doc

<?php

declare(strict_types=1);

namespace App\Tests\Controller\Snippets;

use App\Tests\WebTestCase;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\ParameterType;

/**
 * @covers Snippet70Trait
 */
final class Snippet70Test extends WebTestCase
{
    private Connection $connection;

    protected function setUp(): void
    {
        self::bootKernel();
        $this->connection = $this->getDoctrineDefaultConnection();
    }

    /**
     * @covers Snippet70Trait::snippet70
     */
    public function testSnippet70(): void
    {
        $statement = $this->connection->prepare('SELECT type, count(*) AS count FROM article WHERE id > ? GROUP BY type');
        $statement->bindValue(1, 20, ParameterType::INTEGER);
        $statement->execute();
        $res = $statement->fetchAllAssociative();
        self::assertIsArray($res);
        self::assertSame(['type', 'count'], array_keys($res[0] ?? []));

        $res2 = $this->connection->fetchAllAssociative('SELECT type, count(*) AS count FROM article GROUP BY type');
        self::assertIsArray($res2);
        self::assertSame(['type', 'count'], array_keys($res2[0] ?? []));
    }
}